Install uv
Install fh-fablib. The recommended way is to use
uv tool install -e ~/projects/fh-fablibif you have a local git checkout you want to install from. Otherwise you can useuv tool install fh-fablibto install the packaged version.Add a
fabfile.pyto your project. A minimal example follows:import fh_fablib as fl fl.require("1.0.20250710") fl.config.update(host="[email protected]") environments = [ fl.environment( "production", { "domain": "example.com", "branch": "main", "remote": "production", }, aliases=["p"], ), ] ns = fl.Collection(*fl.GENERAL, *fl.NINE, *environments)
Run
fl hookto provide a default prek configuration (orfl hook --forceto override the dotfiles).Run
fl --listto get a list of commands.
app = "app": Name of primary Django app containing settings, assets etc.base:pathlib.Pathobject pointing to the base dir of the project.branch: Branch containing code to be deployed.domain: Primary domain of website. The database name and cache key prefix are derived from this value.environments: A dictionary of environments, see below.environment: The name of the active environment or"default".force: Always force-push when deploying.host: SSH connection string (username@server)remote: git remote name for the server. Only used for thefetchtask.
For the sake of an example, suppose that additional processes should be
restarted after deployment. A custom deploy task follows:
# ... continuing the fabfile above
@fl.task
def deploy(ctx):
"""Deploy once 🔥"""
fl.deploy(ctx) # Reuse
with fl.Connection(fl.config.host) as conn:
fl.run(conn, "systemctl --user restart other.service")
ns.add_task(deploy)Note
Instead of making existing tasks more flexible or configurable it's preferable to contribute better building blocks resp. to improve existing buildings blocks to make it easier to build customized tasks inside projects.
If you need multiple environments, add environment tasks as follows:
import fh_fablib as fl
fl.require("1.0.20250710")
fl.config.update(host="[email protected]")
environments = [
fl.environment(
"production",
{
"domain": "example.com",
"branch": "main",
"remote": "production",
},
aliases=["p"],
),
fl.environment(
"next",
{
"domain": "next.example.com",
"branch": "next",
"remote": "next",
},
aliases=["n"],
),
]
ns = fl.Collection(*fl.GENERAL, *fl.NINE, *environments)Now, fl production pull-db, fl next deploy and friends should
work as expected.
check: Check the coding stylecm: Compile the translation catalogsdebug: Run development server with debugpy enableddeploy: Deploy once 🔥dev: Run the development server for the frontend and backendfetch: Ensure a remote exists for the server and fetchfreeze: Freeze the virtualenv's stategithub: Create a repository on GitHub and push the codehook: Install the prek hooklocal: Local environment setupmm: Update the translation catalogspull-db: Pull a local copy of the remote DB and reset all passwordspull-media: Rsync a folder from the remote to the local environmentreset-pw: Set all user passwords to"password"reset-sq: Reset all PostgreSQL sequencesupdate: Update virtualenv and node_modules to match the lockfilesupgrade: Re-create the virtualenv with newest versions of all libraries
nine: Run all nine🌟 setup tasks in ordernine-alias-add: Add aliasses to a nine-manage-vhost virtual hostnine-alias-remove: Remove aliasses from a nine-manage-vhost virtual hostnine-checkout: Checkout the repository on the servernine-db-dotenv: Create a database and initialize the .env. Currently assumes that the shell user has superuser rights (either throughPGUSERandPGPASSWORDenvironment variables or through peer authentication)nine-disable: Disable a virtual host, dump and remove the DB and stop the gunicorn@ unitnine-reinit-from: Reinitialize an environment from a different environmentnine-restart: Restart the application servernine-ssl: Activate SSLnine-unit: Start and enable a gunicorn@ unitnine-venv: Create a venv and install packages from requirements.txtnine-vhost: Create a virtual host using nine-manage-vhosts
The following functions may be used to build your own tasks. They cannot be executed directly from the command line.
run(c, ...): Wrapper aroundContext.runorConnection.runwhich always sets a few useful arguments (echo=True,pty= Trueandreplace_env=Falseat the time of writing)
_check_branch(ctx): Terminates if checked out branch does not match configuration._check_no_uncommitted_changes(ctx): Terminates if there are uncommitted changes on the server.
_local_env(path=".env"):speckenv.envfor a local env file_srv_env(conn, path):speckenv.envfor a remote env file_python3(): Return the path of a Python 3 executable. Prefers newer Python versions._local_dotenv_if_not_exists(): Ensure a local.envwith a few default values exists. Does nothing if.envexists already._local_dbname(): Ensure a local.envexists and return the database name._dbname_from_dsn(dsn): Extract the database name from a DSN._dbname_from_domain(domain): Mangle the domain to produce a string suitable as a database name, database user and cache key prefix._concurrently(ctx, jobs): Run a list of shell commands concurrently and wait for all of them to terminate (or Ctrl-C)._random_string(length, chars=None): Return a random string of length, suitable for generating secret keys etc.require(version): Terminate if fh_fablib is older.terminate(msg): Terminate processing with an error message.
_deploy_django: Update the Git checkout, update the virtualenv._deploy_staticfiles: Collect staticfiles._rsync_static: rsync the localstatic/folder to the remote, optionally deleting everything which doesn't exist locally._nine_restart: Restart the systemd control unit.