-
Notifications
You must be signed in to change notification settings - Fork 0
Automations
Many steps like testing before releasing a new package version or building and hosting the documentation are automated using GitHub Actions or other tools. Below, we describe some of this automation, their setup and management.
GitHub provides a simple way to automate tasks using GitHub Actions. Any YAML files in the .github/workflows directory of a repository are automatically picked up by GitHub and - if they are configured correctly - executed when certain events occur.
The first step in a GitHub Actions workflow is to define the events that trigger the workflow. For example, we may want to run a workflow when code is pushed to the repository, when a pull request is opened, or on a schedule (e.g., nightly builds).
Here is an example of a workflow that runs on every push to the main branch:
name: Fancy Workflow
on:
push:
branches: [ main ]In our repos, we typically have some workflows run on every pull request, like automated tests and a build-and-publish action that builds the package and publishes it to TestPyPI. So, as soon as we think a new version is ready, we create the pull request and when the triggered workflows fail, we can fix the issues before merging the pull request.

A workflow consists of one or more jobs, which are executed in parallel by default, except if they depend on each other. Each job can have multiple steps, which are executed sequentially. Most of our actions only have one job with a couple of steps.
Let's look at a very basic testing workflow:
name: tests
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
# This allows us to manually trigger the workflow from the GitHub UI.
workflow_dispatch:
jobs:
test:
name: Run tests & report coverage
runs-on: ubuntu-latest # Run the job on the latest Ubuntu OS.
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.10"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install .[tests]
- name: Test package
run: pytest testsNote that we have four steps here and that a step may simply be defined by a reference to a pre-built action from someone else. E.g., the actions/checkout@v4 step checks out the code from the repository, so that we can run tests on it. This action was written by GitHub and is basically used in almost every workflow.
Similarly, the actions/setup-python@v5 step sets up a specific Python version for the job and was written by GitHub as well. But there are also many custom actions for specific tasks, like building and publishing a package to TestPyPI or PyPI, that were contributed by the community.
The last two steps simply execute bash commands to install the package and its test dependencies, and then run the tests using pytest.
If the tests pass, the workflow is successful. If they fail, the workflow fails and we can see the output of the failing tests in the GitHub UI.
To be able to publish a built package on TestPyPI or PyPI, we need to configure both the workflow and the project on PyPI to trust whatever is coming from the GitHub Actions workflow.
To achieve this, we can define an environment for every job in a workflow. For example, to publish mypackage to PyPI, we define the following environment in the workflow:
# ... other parts of the workflow ...
jobs:
publish:
name: Publish to PyPI
runs-on: ubuntu-latest
needs: [ build ] # This job depends on the build job.
environment:
name: pypi
url: https://pypi.org/
steps:
# Here, we download the package built and uploaded in the previous `build` job
# of the same workflow.
- name: Download built package
uses: actions/download-artifact@v4
with:
name: mypackage
path: dist/
- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@v1For this to succeed, we must have a PyPI account, go to "Publishing" and "Add a new pending publisher" if we haven't already done so. There we need to specify the name of the project, which GitHub user or organization the built package will be coming from, the repository name, as well as the environment and workflow name. Only if everything matches, the package will be published to PyPI.
If you already have a project set up, you can to to the project page on PyPI and manage the "Publishing" settings there.

While GitHub Actions can be used to build publish the documentation, it is simpler to use the service from Read the Docs for this. They build and manage all the documentations for different versions of our packages, and we can easily link to the documentation from the README file or the package page on PyPI.
However, for that too, we need to set up some stuff:
- Go to Read the Docs and sign up with your GitHub account.
- Add a new project and enter the repository name from which the documentation should be built.
- Go to the project's settings and navigate to "Integrations" under "Building". There you should find a "GitHub incoming webhook" (if not, create it). On the other side, in your repository's settings on GitHub, you should find the exact same webhook under "Webhooks". If this is not the case, try deleting the webhook on Read the Docs and creating it again.
Also, it is nice to have the docs built already when we create a pull request, to ensure that works before we publish. For that, check the box "Build pull requests for this project" in the main settings page of the project on Read the Docs.
Lastly, make sure you have a minimal .readthedocs.yml file (see more all the options for this file here) in the root of your repository, so that Read the Docs knows how to build the documentation. Here is an example:
# Required
version: 2
build:
os: ubuntu-22.04
tools:
python: "3.10"
# Build documentation in the docs/source directory with Sphinx
sphinx:
builder: html
configuration: docs/source/conf.py
fail_on_warning: false
# tell RTD to install the package with the `docs` optional requirements
python:
install:
- method: pip
path: .
extra_requirements:
- docsTo show off the success (or failure) of our fancy automations, we can add badges to the README file of our repository. Both every GitHub Actions workflow and the Read the Docs documentation build provide badges in the form of dynamic images that we can use.
E.g., the testing workflow of the [lycosystem/lymph] repository has the following badge:
[](https://github.com/lycosystem/lymph/actions)Which will then look like this
As soon as our tests fail, the badge will show the words "failing" on red, instead of "passing" on green. That way, users can immediately see if the latest code seems to be working as intended or not.