Release process
This page describes how to manage versioning, build and publish Python packages to PyPI, build and publish Docker images, and deploy documentation — all through GitHub Actions.
Overview
The release pipeline consists of the following coordinated steps:
1 2 3 4 5 6 7 8 9 | |
All workflows are defined in .github/workflows/.
0. Updating the changelog
Before cutting a release tag, update docs/changelog.md with all issues from the associated GitHub project.
Prerequisites
- GitHub CLI (
gh) installed. - Authenticated via
gh auth login. - Python dependencies installed (
pandas).
Steps
-
Identify the GitHub project number for the release. For example, project 83 tracks the
3.1.0milestone.
Find it in the project URL:https://github.com/orgs/InstituteforDiseaseModeling/projects/<number>. -
Run the script from the
dev_scripts/directory:1 2
cd dev_scripts python project_changelog.py --project_id 83 --version 3.1.0 -
Review the updated
docs/changelog.mdto verify entries look correct, then commit:1 2
git add docs/changelog.md git commit -m "Update changelog for X.Y.Z release"
1. Versioning
How versions work
All packages use setuptools-scm for fully dynamic versioning. There is no static version stored in any pyproject.toml — every package declares dynamic = ["version"] and the version is computed at build time directly from the git tag:
1 2 3 4 5 6 7 8 | |
- Tag format:
v{MAJOR}.{MINOR}.{PATCH}(e.g.,v3.0.6) - Fallback (no tag reachable):
0.0.0.dev0 no-local-version: strips the+gHASHlocal suffix so published wheels have clean version strings
Version between tags
We only update tags with releases. Between releases, setuptools-scm automatically appends a post-release and dev segment to reflect the number of commits since the last tag:
1 | |
For example, 4 commits after tagging v3.0.6:
1 2 3 4 5 6 7 8 | |
The dev number varies per package because each package's version is computed independently based on how many commits have touched files under its subdirectory since the last tag.
You can check the current version of all installed packages at any time:
1 | |
The built wheel filename and package metadata reflect whatever setuptools-scm resolves at python -m build time. No file editing is needed to change the version; creating a new git tag is the only required action.
Creating a new version
To release a new version, create and push an annotated git tag. That is the only step required — setuptools-scm picks it up automatically at build time.
1 2 | |
Pushing a v* tag triggers the Deploy Packages workflow, which builds all packages and publishes them to PyPI (after manual approval).
How the version flows into built packages
When python -m build runs, setuptools-scm walks the git history, finds the nearest v* tag, and injects that value as the package version. No file editing is needed.
2. Building and publishing Python packages
Packages in this repository
The monorepo contains 8 packages, all built in parallel:
| Package directory | PyPI name |
|---|---|
idmtools_core |
idmtools |
idmtools_cli |
idmtools-cli |
idmtools_models |
idmtools-models |
idmtools_platform_comps |
idmtools-platform-comps |
idmtools_platform_general |
idmtools-platform-general |
idmtools_platform_slurm |
idmtools-platform-slurm |
idmtools_platform_container |
idmtools-platform-container |
idmtools_test |
idmtools-test |
Workflow: Deploy Packages (deploy.yml)
Triggers:
| Event | What happens |
|---|---|
Push to main branch |
Builds packages only (no upload) |
Tag matching v* |
Builds packages → publishes to PyPI (after approval) → builds Docker images |
Manual dispatch with target=test |
Builds + publishes to TestPyPI + builds Docker staging image |
Each step is explained below. No manual intervention is required beyond the trigger events mentioned above.
Step 1 — Build all packages
Each package is built using the PEP 517 build frontend:
1 2 | |
This produces both a source distribution (.tar.gz) and a wheel (.whl) in idmtools_{package}/dist/. Built artifacts are uploaded as GitHub Actions artifacts with a 1-day retention.
Step 2 — Publish to TestPyPI (manual, optional)
Run the Deploy Packages workflow manually from with target=test:
- Go to Actions → Deploy Packages.
- Click Run workflow, select a branch you want to build from, set Where to upload to
test. - Packages are uploaded to TestPyPI using the
TEST_PYPI_API_TOKENsecret. skip-existing: trueprevents errors if the version already exists.
Install from TestPyPI to verify:
1 | |
Step 3 — Publish to production PyPI (automatic on tag)
When a v* tag is pushed (created by the git tag):
- All 8 packages are built.
- The
publish-to-pypijob waits for a manual approval from reviewers in thedeploy_pypiGitHub environment. - After approval, packages are published using OIDC Trusted Publishers — no API token needed.
Manual approval required
Production PyPI publishing requires a reviewer to approve the deploy_pypi environment gate in the GitHub Actions UI before the upload proceeds.
Local build and staging upload
1 2 3 4 5 | |
3. Building and publishing Docker images
Two Docker images are maintained in this repository, both published to the GitHub Container Registry (GHCR).
Image 1 — SSMT worker image (COMPS platform)
Registry path: ghcr.io/institutefordiseasemodeling/idmtools_comps_ssmt_worker
Build script: idmtools_platform_comps/ssmt_image/build_ssmt_image.py
Staging image
Trigger: Manual dispatch via Deploy Packages with target=test, or via the separate Build SSMT Image Staging workflow (build_ssmt_image_staging.yml).
1 | |
The workflow:
- Installs
idmtools_platform_compsfrom the build artifacts. - Logs into GHCR using
GITHUB_TOKEN. - Runs the build script to build and push a staging image:
1 2 | |
Production image
Trigger: Automatically after a v* tag is pushed and all packages are published to PyPI.
1 | |
The build script:
- Queries GHCR to determine the next build number automatically.
- Tags the image with three tags:
- Full version:
3.1.0.5 - Base version:
3.1.0 latest
- Full version:
Local build (without push)
1 2 | |
To build and push manually:
1 2 | |
Image 2 — Container platform runtime image
Registry path: ghcr.io/institutefordiseasemodeling/container-rocky-runtime
Build script: idmtools_platform_container/docker_image/build_container_image.py
Trigger: Manual dispatch only via the Build Container Image workflow (build_container_image.yml).
1 | |
The workflow runs:
1 2 | |
The script:
- Reads
BASE_VERSIONfile for the base version string. - Queries GHCR to calculate the next build number automatically.
- Builds using the
Dockerfilein the same directory. - Tags and pushes to GHCR.
To build without pushing:
1 | |
GHCR authentication (local builds)
1 | |
The token requires write:packages and read:packages scopes.
4. Building and deploying documentation
Documentation is built with MkDocs and the Material theme, then deployed to GitHub Pages.
Live site: https://institutefordiseasemodeling.github.io/idmtools/
Workflow: Deploy MkDocs (deploy_docs_api.yml)
Triggers:
| Event | What happens |
|---|---|
Push to main branch |
Builds and deploys docs automatically |
| Manual dispatch | Builds and deploys on demand |
Building docs locally
1 2 3 4 5 6 7 8 | |
Concurrency protection
The workflow uses a pages concurrency group with cancel-in-progress: false to prevent partial deployments from being cancelled.
Documentation dependencies
From docs/requirements.txt:
1 2 3 4 | |
5. Full release checklist
Use this checklist when cutting a new release:
- [ ] All changes merged to
devbranch and tests passing. - [ ] Create new release tag with
git tag vx.y.zand push to repo withgit push origin vx.y.z - [ ] Verify the new tag (e.g.,
v3.1.0) appears in the repository. - [ ] Merge
dev→mainvia pull request. - [ ] The push to
maintriggers:- [ ] Deploy Packages — builds all 8 packages.
- [ ] Deploy MkDocs — builds and deploys documentation to GitHub Pages.
- [ ] To publish to TestPyPI (optional validation step before release):
- Run Actions → Deploy Packages manually on
any branchwithtarget=test. - Install from TestPyPI and smoke-test.
- Run Actions → Deploy Packages manually on
- [ ] Once confident, the
v*tag triggers production PyPI publish — approve thedeploy_pypienvironment gate when prompted. - [ ] After PyPI publish succeeds, the SSMT Docker image is automatically built and pushed to GHCR.
- [ ] To rebuild the Container Runtime image separately: run Actions → Build Container Image manually.
6. Required secrets and environments
| Secret / environment | Used by | Purpose |
|---|---|---|
TEST_PYPI_API_TOKEN |
deploy.yml |
Upload to TestPyPI |
GITHUB_TOKEN |
deploy.yml, deploy_docs_api.yml, build_ssmt_image_staging.yml |
GHCR login, Pages deploy (auto-provided by GitHub) |
deploy_pypi environment |
deploy.yml |
Manual approval gate for production PyPI publish |