GitHub Actions#
The project uses several workflows using GitHub Actions to maintain code quality and
confirm that the package and website are building correctly. The actions are defined in
the .github/workflows directory and currently include:
Continuous integration workflow#
The ci.yml workflow runs when a pull request is opened and when new commits are made
to an existing pull request. It is the main quality assurance check on new code and runs
three jobs:
code quality assurance (
qa): does the code pass all thepre-commitchecks.code testing (
test): do all unit and integration tests in thepytestsuite pass.documentation building (
docs_build): does the documentation build correctly.
If any of those checks fail, you will need to push new commits to the pull request to fix the outstanding issues. The status of code checking for pull requests can be seen at:
ImperialCollegeLondon/virtual_ecosystem
Although GitHub Actions automates these steps for any pushes, pull requests and releases
on the repository, you should also perform the same steps locally before submitting code
to ensure that your code passes testing. The pre-commit test is automatic but follow
the instructions for running pytest and building the
documentation.
CI workflow details
name: Test and build
# When does this run - new, reopened or updated PRs, pushes to main or develop and when
# the workflow is called by another workflow, such as the publishing actions.
on:
pull_request:
types: [opened, synchronize, reopened]
push:
branches: [main, develop]
workflow_call:
jobs:
qa:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
with:
python-version: "3.12"
- uses: pre-commit/action@v3.0.1
test:
needs: qa
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ ubuntu-latest, macos-latest, windows-latest ]
python-version: ["3.12", "3.13", "3.14"]
steps:
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}
- name: Install Poetry
run: |
pipx install poetry --python python${{ matrix.python-version }}
poetry --version
- name: Install dependencies
run: poetry install
- name: Run unit tests
run: poetry run pytest --cov-report xml -m "not integration"
- name: Archive log for error checking on failure
if: failure()
uses: actions/upload-artifact@v7
with:
name: failed_tests_ve_run_cli_log
path: ${{ runner.temp }}/log_file.log
archive: false
retention-days: 1
- name: Upload coverage to Codecov
if: >-
${{ ! (
github.event.pull_request.user.login == 'dependabot[bot]' ||
github.event.pull_request.user.login == 'pre-commit-ci[bot]'
) && (
matrix.os == 'ubuntu-latest' &&
matrix.python-version == '3.12'
)
}}
uses: codecov/codecov-action@v6
with:
fail_ci_if_error: true
token: ${{ secrets.CODECOV_TOKEN }}
verbose: true
docs_build:
needs: qa
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
with:
python-version: "3.12"
- name: Install Poetry
run: |
pipx install poetry --python python3.12
poetry --version
- name: Install dependencies
run: poetry install
- name: Build docs using sphinx
run: |
cd docs
poetry run sphinx-build -W --keep-going source build
- name: Archive built docs for error checking on failure
if: failure()
uses: actions/upload-artifact@v7
with:
name: built-docs
path: docs/build
retention-days: 2
Publication workflow#
The publish.yaml workflow runs when a release is made on the GitHub site and uses
trusted publishing to build the package and publish it on
PyPI.
The full workflow setup can be seen below, along with comments, but the basic flow is:
When a GitHub release is published, the PyPI publication workflow is triggered.
The standard continuous integration tests are run again, just to be sure!
If the tests pass, the package is built and the wheel and source code are stored as job artefacts.
The built files are automatically added to the release assets.
The built files are then also published to the Test PyPI server, which is configured to automatically trust publications from this GitHub repository.
As long as all the steps above succeed, the built files are now published to the main PyPI site, which is also configured to trust publications from the repository.
The last step of publication to the main PyPI site can be skipped by including the
text test-pypi-only in the title text for the release. This allows pre-release
tests and experimentation to be tested without automatically adding them to the
official released versions.
Publication workflow details
name: Publishing
on:
release:
types: [published]
jobs:
# First, run the standard CI checks - for this to work correctly, the workflow needs
# to inherit the organisation secrets used to authenticate to CodeCov.
# https://github.com/actions/runner/issues/1413
ci_checks:
uses: ./.github/workflows/ci.yml
secrets: inherit
# Then if the standard CI checks pass run the integration tests
integration_tests:
needs: ci_checks
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
# All supported OSs, minimum and maximum python version
os: [ ubuntu-latest, macos-latest, windows-latest ]
python-version: ["3.12", "3.14"]
steps:
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}
- name: Install Poetry
run: |
pipx install poetry --python python${{ matrix.python-version }}
poetry --version
- name: Install dependencies
run: poetry install
- name: Run integration tests
run: poetry run pytest -m "integration"
- name: Archive log for error checking on failure
if: failure()
uses: actions/upload-artifact@v7
with:
name: failed_tests_ve_run_cli_log
path: ${{ runner.temp }}/log_file.log
archive: false
retention-days: 1
# Next, build the package wheel and source releases and add them to the release assets
build-wheel:
needs: integration_tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
# Build the package - this could use `poetry build` directly but pyproject.toml
# already has the build-system configured to use poetry so `pip` should pick that
# up automatically.
- name: Build sdist
run: |
python -m pip install --upgrade build
python -m build
# Upload the build outputs as job artifacts - these will be two files with x.y.z
# version numbers:
# - virtual_ecosystem-x.y.z-py3-none-any.whl
# - virtual_ecosystem-x.y.z.tar.gz
- uses: actions/upload-artifact@v7
with:
path: dist/virtual_ecosystem*
# Add the built files to the release assets, alongside the repo archives
# automatically added by GitHub. These files should then match exactly to the
# published files on PyPI.
- uses: softprops/action-gh-release@v3
with:
files: dist/virtual_ecosystem*
# Now attempt to publish the package to the TestPyPI site, where the virtual_ecosystem
# project has been configured to allow trusted publishing from this repo and workflow.
#
# The skip-existing option allows the publication step to pass even when the release
# files already exists on PyPI. That suggests something has gone wrong with the
# release or the build file staging and the release should not be allowed to continue
# to publish on PyPI.
publish-TestPyPI:
needs: build-wheel
name: Publish virtual_ecosystem to TestPyPI
runs-on: ubuntu-latest
permissions:
id-token: write
steps:
# Download the built package files from the job artifacts
- name: Download sdist artifact
uses: actions/download-artifact@v8
with:
name: artifact
path: dist
# Information step to show the contents of the job artifacts
- name: Display structure of downloaded files
run: ls -R dist
# Use trusted publishing to release the files downloaded into dist to TestPyPI
- name: Publish package distributions to TestPyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
repository-url: https://test.pypi.org/legacy/
verbose: true
# skip-existing: true
# The final job in the workflow is to publish to the real PyPI as long as the release
# name does not contain the tag 'test-pypi-only'
publish-PyPI:
if: ${{ ! contains(github.event.release.name, 'test-pypi-only')}}
needs: publish-TestPyPI
name: Publish virtual_ecosystem to PyPI
runs-on: ubuntu-latest
permissions:
id-token: write
steps:
# Download the built package files from the job artifacts
- name: Download sdist artifact
uses: actions/download-artifact@v8
with:
name: artifact
path: dist
# Information step to show the contents of the job artifacts
- name: Display structure of downloaded files
run: ls -R dist
# Use trusted publishing to release the files downloaded into dist to PyPI
- name: Publish package distributions to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
Updates to pre-commit#
The Virtual Ecosystem repository is registered with the
pre-commit.ci service. This runs and
reports the status of the
pre-commit suite - which duplicates the ci.yml workflow above - but also adds weekly
update checks on the pre-commit hooks used for the project.