This repository has a small yet instructive project that shows you how to create a devcontainer for developing on Codespaces and how to base the GitHub actions workflows on it.
Specifically, the project is a simple Python app whose dependencies are managed by Poetry.
-
It contains some simple tests (for example purposes) that are run with pytest.
-
It uses ruff for linting and formatting, and mypy for type checking.
-
Finally, it has two Github actions workflows for:
- linting, formatting, and type checking.
- running the tests with pytest.
-
The Docker login action
docker/login-action@v3
should be able to pull and push container images to and from the registry. To do this, we need to create a personal access token with the minimum required scope (respecting the principle of least privilege). -
In this project, I used a personal access token (classic) (see official docs on how to create one here).
-
Once you have created the token, copy its value and paste it into a repository secret (e.g. a secret named
GH_DEVCONTAINER_TOKEN
). See the official documentation on how to create secrets for a repository. -
Next, select the minimum scopes required for this personal access token:
write:packages
read:packages
-
To create and reuse a cached container image for faster workflow runs, we are using the convenient action devcontainers/[email protected]
. We specify where to fetch the image from using the imageName
input, which accepts an URL of the following form ghcr.io/NAMESPACE/IMAGE_NAME:latest
. The namespace is typically the github account name under which the repo exists and the image name is the repository name (read more about it in the official docs).
- Check out a feature/branch from the main branch.
- Spin off a devcontainer to work on that new feature.
- Devcontainer gets the latest container image cached from the container registry.
- Devcontainer gets latest Poetry virtual environment from cache.
- When PR is merged into main branch, a new latest devcontainer image is pushed to the registry, which will be used for future version developments.
Note that in step 3, the devcontainer is not rebuilt, but reused from the latest cached version.
Similar to scenario 1, but pushing new devcontainer image is skipped because the workflow has not been triggered by a push to main, rather a PR event (for more see specification of push
, refFilterForPush
, and eventFilterForPush
(default) inputs for devcontainer/ci
action).
If we were to add a new Python library as part of our development, in step 4 of scenario 1 we would not get the virtual environment from the cache, but we would use the newly created one with the additional library and push it to the cache.