This repository hosts a set of custom reusable github actions workflows.
- package-test-uv.yml
- promote-staging-to-production.yml
- package-test-legacy.yml
- package-test-coverage.yml
- package-full-test.yml
- deb-build-push-notify.yml
Test a Plone package. Test environment is bootstrapped using uv and buildout.
Note: Supported Python versions are listed on uv documentation. If you need to use a deprecated Python 3 version, you can pin an older uv version using the
uv_versioninput. For Python 2 support, use thepackage-test-legacy.ymlworkflow instead.
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
| buildout_command | string | No | .venv/bin/buildout | Command to run buildout |
| buildout_config_file | string | No | buildout.cfg | Buildout configuration file to use |
| buildout_options | string | No | (empty) | Additional options to pass to buildout |
| continue_on_error | boolean | No | true | Continue on error |
| python_version | string | No | 3.13 | Python version to use |
| requirements_file | string | No | requirements.txt | Requirements file to use for dependency installation |
| runner_label | string | No | ubuntu-latest | GitHub Actions runner label to use |
| soffice | boolean | No | false | Launch soffice (LibreOffice in service mode) |
| system_dependencies | string | No | (empty) | System dependencies to install before running tests |
| test_command | string | No | bin/test | Command to run tests |
| uv_version | string | No | 0.7.20 | Version of uv to use |
Secrets:
| Name | Required | Description |
|---|---|---|
| gh_token | No | Token used to authenticate git access to github.com (mr.developer sources) |
| mattermost_webhook_url | No | Mattermost webhook URL for notifications (optional) |
Tip: pass
gh_tokenwhen your buildout pullsmr.developersources. Without a token those checkouts clone anonymously and GitHub intermittently answers with a401, which surfaces asfatal: could not read Username for 'https://github.com': No such device or address. When the secret is omitted the workflow falls back to the job's ownGITHUB_TOKEN, which is enough for public sources; supply a PAT or GitHub App token for private ones. The same applies topackage-test-coverage.ymlandpackage-full-test.yml.
Tip: If your repository follows the default values for all workflow inputs, this is all you need to run the tests.
test:
permissions:
contents: read
uses: IMIO/gha-workflows/.github/workflows/package-test-uv.yml@v1Thanks to github actions matrixes, you can launch tests on multiple plone and python versions.
In the below example, we run tests on 2 python versions and 2 plone versions (4 tests in total). You need a specific requirements and buildout config file for each plone version.
test:
permissions:
contents: read
uses: IMIO/gha-workflows/.github/workflows/package-test-uv.yml@v1
strategy:
matrix:
python_version: ['3.10', '3.13']
plone_version: ['6.0', '6.1']
with:
buildout_config_file: gha_${{ matrix.plone_version }}.cfg
python_version: ${{ matrix.python_version }}
requirements_file: requirements_${{ matrix.plone_version }}.txtThis workflow promotes a Docker image from staging to production and deploys it using Rundeck.
It tags the specified Docker image in the registry and notifies via Mattermost.
It also runs a Rundeck job to deploy the image to the specified node.
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
| github_environment | string | No | production | GitHub environment to use for the job |
| image_name | string | Yes | — | Name of the Docker image |
| image_tag_staging | string | Yes | — | Tag of the Docker image in staging |
| image_tag_production | string | Yes | — | Tag of the Docker image in production |
| rundeck_job_id | string | Yes | — | ID of the Rundeck job to run for deployment |
| quick_release | boolean | No | false | Whether this is a quick release |
| runner_label | string | No | gha-runners | Label for the GitHub runner to use |
| schedule_time | string | No | 03:00 | Time to schedule the deployment tomorrow (e.g., "03:00") |
| service_name | string | No | — | Name of the service being deployed |
Note
If your RunDeck job needs to specify nodes (it's the case for a job where nodes are not checked by default), you can specify nodes by setting a GitHub environment variable called NODE_NAME. Multiple nodes can be specified, separated by commas (e.g., node1.lan,node2.lan).
Secrets:
| Name | Required | Description |
|---|---|---|
| mattermost_webhook_url | No | Webhook URL for Mattermost notifications |
| registry_url | Yes | URL of the registry |
| registry_username | Yes | Username for the registry |
| registry_password | Yes | Password for the registry |
| rundeck_url | Yes | URL of the Rundeck server |
| rundeck_token | Yes | Token for the Rundeck server |
jobs:
promote-staging-to-production:
uses: IMIO/gha-workflows/.github/workflows/promote-staging-to-production.yml@v1
with:
github_environment: production
image_name: myapp
image_tag_staging: staging
image_tag_production: latest
rundeck_job_id: 5b7c2640-1234-4b52-abcd-32745b326cd1
runner_label: ubuntu-latest
schedule_time: '02:00'
service_name: myappservice
quick_release: true
secrets:
registry_url: ${{ secrets.HARBOR_URL }}
registry_username: ${{ secrets.HARBOR_USERNAME }}
registry_password: ${{ secrets.HARBOR_PASSWORD }}
rundeck_url: ${{ secrets.RUNDECK_URL }}
rundeck_token: ${{ secrets.RUNDECK_TOKEN }}Test a Plone package using legacy buildout and Python versions.
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
| buildout_command | string | No | bin/buildout | Command to run buildout |
| buildout_config_file | string | No | buildout.cfg | Buildout configuration file to use |
| continue_on_error | boolean | No | false | Continue on error |
| matrix_experimental | boolean | No | false | Enable experimental matrix |
| plone_version | string | No | 4.3 | Plone version to use |
| python_version | string | No | 2.7 | Python version to use |
| requirements_file | string | No | requirements.txt | Requirements file to use for dependency installation |
| runner_label | string | No | ubuntu-latest | GitHub Actions runner label to use |
| soffice | boolean | No | false | Launch soffice (LibreOffice in service mode) |
| test_command | string | No | bin/test | Command to run tests |
Secrets:
| Name | Required | Description |
|---|---|---|
| mattermost_webhook_url | No | Mattermost webhook URL for notifications (optional) |
test:
uses: IMIO/gha-workflows/.github/workflows/package-test-legacy.yml@v1
with:
buildout_config_file: buildout.cfg
python_version: 2.7
requirements_file: requirements.txtTest a Plone package and generate a coverage report. Test environment is bootstrapped using uv and buildout. Optionally uploads the coverage report to Coveralls.
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
| buildout_command | string | No | .venv/bin/buildout | Command to run buildout |
| buildout_config_file | string | No | buildout.cfg | Buildout configuration file to use |
| buildout_options | string | No | (empty) | Additional options to pass to buildout |
| continue_on_error | boolean | No | false | Continue on error |
| plone_version | string | No | 6.1 | Plone version to use |
| requirements_file | string | No | requirements.txt | Requirements file to use for dependency installation |
| runner_label | string | No | ubuntu-latest | GitHub Actions runner label to use |
| soffice | boolean | No | false | Launch soffice (LibreOffice in service mode) |
| test_command | string | No | uvx coverage run bin/test -t !robot >> $GITHUB_STEP_SUMMARY | Command to run tests with coverage |
| upload_to_coveralls | boolean | No | false | Upload coverage report to Coveralls |
Secrets:
| Name | Required | Description |
|---|---|---|
| gh_token | No | Token used to authenticate git access to github.com (mr.developer sources) |
| mattermost_webhook_url | No | Mattermost webhook URL for notifications (optional) |
test:
permissions:
contents: read
uses: IMIO/gha-workflows/.github/workflows/package-test-coverage.yml@v1
with:
upload_to_coveralls: trueFull test pipeline for a Plone package, combining three parallel jobs in a single reusable workflow:
- code-analysis — runs a code analysis check (black by default) via
IMIO/gha/code-analysis-notify@v6 - test — runs package-test-uv.yml on each Python version of the
python_versionsmatrix - coverage — runs package-test-coverage.yml
Note: Since the Python matrix lives inside this workflow, pass the versions as a JSON array string via the
python_versionsinput (e.g.'["3.12", "3.13"]') instead of astrategy.matrixon the calling job.
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
| base_dir | string | No | src | Base directory for the code analysis check |
| buildout_command | string | No | .venv/bin/buildout | Command to run buildout |
| buildout_config_file | string | No | buildout.cfg | Buildout configuration file to use |
| buildout_options | string | No | (empty) | Additional options to pass to buildout |
| check | string | No | black | Code analysis check to run |
| check_path | string | Yes | — | Package path(s) to run the code analysis check on |
| continue_on_error | boolean | No | true | Continue on error (test job) |
| coverage_python_version | string | No | 3.13 | Python version for the coverage job |
| coverage_test_command | string | No | .venv/bin/coverage run bin/test -t !robot >> $GITHUB_STEP_SUMMARY | Test command for the coverage job |
| python_versions | string | No | ["3.13"] | Python versions for the test matrix, as a JSON array |
| requirements_file | string | No | requirements.txt | Requirements file to use for dependency installation |
| runner_label | string | No | ubuntu-latest | GitHub Actions runner label to use |
| soffice | boolean | No | false | Launch soffice (LibreOffice in service mode) |
| system_dependencies | string | No | (empty) | System dependencies to install before running tests |
| test_command | string | No | bin/test | Command to run tests |
| upload_to_coveralls | boolean | No | false | Upload coverage report to Coveralls |
| uv_version | string | No | 0.7.20 | Version of uv to use |
Secrets:
| Name | Required | Description |
|---|---|---|
| gh_token | No | Token used to authenticate git access to github.com (mr.developer sources) |
| mattermost_webhook_url | No | Mattermost webhook URL for notifications (optional) |
name: Tests
on:
push:
pull_request:
branches: [ main ]
workflow_dispatch:
jobs:
full-test:
permissions:
contents: read
uses: IMIO/gha-workflows/.github/workflows/package-full-test.yml@v1
secrets:
mattermost_webhook_url: ${{ secrets.SMARTWEB_MATTERMOST_WEBHOOK_URL }}
with:
check_path: |
imio/events/core
buildout_config_file: test_plone6.cfg
python_versions: '["3.12", "3.13"]'
runner_label: gha-runners-smartweb
test_command: TZ=UTC bin/test
upload_to_coveralls: trueBuild a deb package from a setup.py project, sign it, push it to the selected apt repositories and notify via Mattermost.
The package version is derived from setup.py as <version>-<timestamp>~<short sha> unless package_version is provided.
Target distributions are selected with the distributions input and built in parallel.
The target repository depends on the branch the workflow is called from: test_branch (dev-test by default) publishes to NEXUS_<DISTRIBUTION>_TEST_URL, every other ref to NEXUS_<DISTRIBUTION>_URL.
Every secret is optional: when it is not passed explicitly, the workflow falls back to the iMio naming convention. So a repository that follows that convention only needs secrets: inherit and nothing else.
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
| distributions | string | No | ["bookworm"] |
JSON array of target distributions. Supported values: bookworm, trixie. |
| package_dependency | string | No | passerelle | Deb dependency of the built package |
| package_install_path | string | No | /usr/lib/python3/dist-packages | Path where the package content is installed |
| package_name | string | No | (caller repository name) | Name of the deb package |
| package_version | string | No | (derived from setup.py) | Package version. If empty, derived as <version>-<timestamp>~<short sha> |
| runner_label | string | No | gha-runners-teleservices | Label for the GitHub runner to use |
| test_branch | string | No | dev-test | Branch publishing to the test apt repositories instead of the production ones. Empty string to always target production. |
Note
package_install_path defaults to the value used by the underlying action. Most teleservices packages need /usr/lib instead, so set it explicitly unless you really want the Python dist-packages directory.
Note
The version is read from a version = "x.y.z" line in setup.py (double quotes). The job fails if no such line is found.
Secrets:
None is required as such, but the workflow needs a repository URL, credentials and a signing key to do anything. Each one is taken from the explicit secret if passed, otherwise from the inherited fallback.
| Name | Inherited fallback | Description |
|---|---|---|
| repository_url_bookworm | NEXUS_BOOKWORM_URL, or NEXUS_BOOKWORM_TEST_URL on test_branch |
URL of the bookworm apt repository |
| repository_url_trixie | NEXUS_TRIXIE_URL, or NEXUS_TRIXIE_TEST_URL on test_branch |
URL of the trixie apt repository |
| repository_login | NEXUS_LOGIN |
Login for the apt repository |
| repository_password | NEXUS_PASSWORD |
Password for the apt repository |
| signer_key | DEB_SIGNER_KEY |
Key to sign the deb package (base64 encoded) |
| signer_key_passphrase | DEB_SIGNER_PASSPHRASE |
Passphrase of the signing key |
| mattermost_webhook_url | MATTERMOST_WEBHOOK_URL, then TELESERVICES_MATTERMOST_WEBHOOK_URL |
Webhook URL for Mattermost notifications |
Important
The inherited fallbacks only work when the caller passes secrets: inherit. Without it, pass the secrets explicitly.
Note
A distribution listed in distributions with no matching URL — neither explicit nor inherited — fails the job with an explicit error rather than pushing to the wrong repository. In particular, running on test_branch without NEXUS_<DISTRIBUTION>_TEST_URL set fails; it never falls back to the production repository.
Note
Only branches match test_branch: a tag push or any other ref targets the production repository. Set test_branch: '' to disable test targeting entirely. An explicitly passed repository_url_<distribution> secret wins on every branch — gate it in the caller if you need it to vary.
Standard case, nothing to configure:
name: Deb build push notify
on:
push:
branches:
- main
workflow_dispatch:
jobs:
deb:
uses: IMIO/gha-workflows/.github/workflows/deb-build-push-notify.yml@v1
secrets: inheritBoth distributions, with the install path most teleservices packages use:
jobs:
deb:
uses: IMIO/gha-workflows/.github/workflows/deb-build-push-notify.yml@v1
secrets: inherit
with:
distributions: '["bookworm", "trixie"]'
package_install_path: '/usr/lib'Publishing test builds from a different branch than dev-test:
on:
push:
branches:
- main
- staging
jobs:
deb:
uses: IMIO/gha-workflows/.github/workflows/deb-build-push-notify.yml@v1
secrets: inherit
with:
test_branch: staging
package_install_path: '/usr/lib'Repository that does not follow the iMio secret naming:
jobs:
deb:
uses: IMIO/gha-workflows/.github/workflows/deb-build-push-notify.yml@v1
with:
distributions: '["trixie"]'
package_install_path: '/opt/publik/wcs-scripts'
secrets:
repository_url_trixie: ${{ secrets.MY_APT_URL }}
repository_login: ${{ secrets.MY_APT_LOGIN }}
repository_password: ${{ secrets.MY_APT_PASSWORD }}
signer_key: ${{ secrets.MY_SIGNER_KEY }}
signer_key_passphrase: ${{ secrets.MY_SIGNER_PASSPHRASE }}
mattermost_webhook_url: ${{ secrets.MY_MATTERMOST_WEBHOOK_URL }}