- Request State Machine (auto-generated)
We use just
as our command runner. It's
a single file binary available for many platforms so should be easy to
install.
# macOS
brew install just
# Linux
# Install from https://github.com/casey/just/releases
# Add completion for your shell. E.g. for bash:
source <(just --completions bash)
# Show all available commands
just # shortcut for just --list
You'll need an appropriate version of Python on your PATH. Check the
.python-version
file for the required version.
Possibly something API compatible with Docker would also work, but we don't officially support that.
Set up a local development environment with:
just devenv
Check that Django is configured correctly with:
just manage check
You can run all the tests with:
just test
To load some initial data for playing with the app locally use:
just load-example-data
To start the app use:
just run
just
automatically takes care of a few things:
- ensuring commands are run using the correct Python virtual environment;
- ensuring that the installed packages match what's specified in the
requirements.*.txt
files; - ensuring that the variables specified in
.env
are loaded into the environment.
Running commands outside of just
is a reasonable and supported
workflow, but you will need to handle the above tasks yourself e.g. by
activating a virtual environment and running something like:
set -a; source .env; set +a
The asset build tooling and component library is currently extracted from job-server for use in airlock.
We also add the components browser view at the /ui-components. This acts as a test to see everything works, and a helpful builtin reference for using the slippers components.
To update the upstream assets, first remove any existing built assets:
just assets/clean
And then update with the latest upstream assets:
just assets/update
By default, just assets/update
with fetch the job-server repo from
GitHub. You can optionally use a local job-server checkout. This is
useful if you are making changes to the job-server assets and want to
test how they will be applied in Airlock.
just assets/update /absolute/path/to/local/job-server
Note: do not commit assets updated using a local job-server checkout. Merge
your job-server changes first, then run just assets/update
to update from
the upstream repo.
To log opentelemetry traces to the console in local environments,
set the OTEL_EXPORTER_CONSOLE
environment variable in your .env
file.
To reduce some of the noise for local development, some instrumentations can be turned off; to run a local server and disable everything except tracing we explicitly add in Airlock code, run:
OTEL_PYTHON_DISABLED_INSTRUMENTATIONS=django,sqlite3,requests
Tests are divided into the following categories.
- unit
- fast tests of small code units
- integration
- tests of components working together (e.g. views)
- functional
- end-to-end Playwright tests
Each category lives in its own directory (for example tests/unit
) and can be run with
just test -k <category>
(for example just test -k unit
).
Additional arguments passed to just test
are passed on to pytest. For example, to
run all the tests except the functional tests, run just test -k 'not functional'
,
or to run a single test, run e.g. just test tests/unit/test_urls.py::test_urls
.
Functional tests run headless by default. To see what's going on, they can be run in headed mode. The following command will run just the functional tests, in headed mode, slowed down by 500ms. See the playwright docs for additional cli arguments that may be useful.
just test -k functional --headed --slowmo 500
To leave the browser instance open after a test failure you can make
pytest drop into the debugger using the --pdb
argument:
just test --headed --pdb ... <path/to/test.py>
We include DDT as a dev dependency, as it is useful for inspecting django
specific things. However, it is not enabled by default. It is only enabled if
both DJANGO_DEBUG
and DJANGO_DEBUG_TOOLBAR
env vars are set to "True"
.
By default, the functional tests run with the latest chromium browser only (the Playwright default). In order to test older/different browser version, you can pass an environment variable specifying a path to browser executable. E.g. to run with the system chrome at /usr/bin/google-chrome:
PLAYWRIGHT_BROWSER_EXECUTABLE_PATH=/usr/bin/google-chrome-stable just test -k functional
(To verify the custom browser executable, run with -s
to print an info message to
the console, or with --headed
for headed mode.)
This needs some first time setup, but after that is fairly simple to use. You
will need the Bitwarden cli bw
installed to pull the dev Github auth
credentials. You need to run the following command with your github username.
just job-server/configure GHUSERNAME
This will configure and run the latest job-server image at http://localhost:9000 to use in integration testing airlock. It will automatically point your current .env config to this local instance.
This command is idempotent, and can be safely re-run.
In future you can just do the following to start it up:
just job-server/run
You will need at least one workspace set up in job-server and locally in airlock to test integration:
just job-server/create-workspace NAME # defaults to "airlock-test-workspace"
IMPORTANT GOTCHA: The current release API is awkward, and will refuse to upload a file that's already been uploaded. This will change, but for now, you can clear the state of all releases for a workspace with:
just job-server/remove-releases workspace
This is useful to test against an development version of job-server.
- Build the prod image in your job-server checkout:
just docker/build prod
export JOB_SERVER_IMAGE=job-server
Now the configure and run command will use the local job-server image, rather than the published one.
To go back to normal, you can use just job-server/stop
. This will comment out
the AIRLOCK_API_*
lines in .env. just job-server/run
will uncomment them.
By default, the local job-server maintains db and file on a couple of volumes. To reset back to a clean slate, you can kill and re-configure, and then add workspaces again.
just job-server/clean
just job-server/configure GHUSERNAME
just job-server/create-workspace
New versions should be deployed automatically on merge to main
after a
short delay. Github Actions should build a new Docker image, and then
the backends poll regularly for updated images. See:
https://github.com/opensafely-core/backend-server/tree/main/services/airlock
The documentation in this repository forms part of the main OpenSAFELY documentation. It is also available within Airlock itself in order to be accessible from within the OpenSAFELY backends.
To build the docs as a standalone documentation site with MkDocs to preview content changes, run:
just docs-serve
docs/stylesheets/extra.css
).
When the main OpenSAFELY documentation is built, it imports the airlock docs/
directory
and builds it within the main documentation site.
These are handled in the main OpenSAFELY documentation repository.
If you need to redirect URLs —
and this should be fairly infrequent —
make any changes to the _redirects
file in the main documentation repository,
and test them in a preview there.
Airlock documentation is located in the docs directory. Local configuration is
specified in the mkdocs.yml
located at the repo root.
Note that most of the config in the mkdocs.yml
is specific to the within-airlock docs and
will be ignored when the docs are imported into the main OpenSAFELY documentation.
In order to serve the docs within Airlock, the directory built by mkdocs (with
just docs-build
) is specified as a static files directory in the STATICFILES_DIRS
setting. A simple view makes them available within Airlock, using the django.static.serve
view (see airlock/views/docs.py
)
- Developer makes changes to documentation files
- PR opened; CI builds a cloudflare pages preview
- PR merged; CI triggers a deploy of the main OpenSAFELY documentation site
To check how local changes appear within the main OpenSAFELY docs, first push a branch with your Airlock changes. Then, in a local checkout of the documentation repo:
- In
mkdocs.yml
, update the import line in thenav
section with your branch:- Releasing with Airlock: '!import https://github.com/opensafely-core/airlock?branch=<YOUR BRANCH>'
- Run the main docs with:
(
MKDOCS_MULTIREPO_CLEANUP=true just run
MKDOCS_MULTIREPO_CLEANUP=true
ensures that the external repos are re-fetched)
Merges to the main branch in this repo trigger a deployment of the main OpenSAFELY documentation via a Github Action.