Build and Release
The document outlines the steps to build and release the deeptab package. It is assumed that all feature branches and PRs for the release have been reviewed, approved, and merged into main before starting this process.
Release workflow
%%{init: {'theme': 'base', 'themeVariables': {
'primaryColor': '#dbeafe',
'primaryTextColor': '#1e3a5f',
'primaryBorderColor': '#3b82f6',
'lineColor': '#6b7280',
'secondaryColor': '#ede9fe',
'tertiaryColor': '#f0fdf4',
'edgeLabelBackground': '#f9fafb'
}}}%%
flowchart TD
A["git checkout main && git pull<br/>git checkout -b release/vX.Y.Z"]:::git --> B[Hotfixes & doc updates]:::setup
B --> QA["Quality checks<br/>lint → format → check → test"]:::ci
QA --> QAP{All pass?}:::decision
QAP -->|No| B
QAP -->|Yes| D["Build docs: just docs"]:::setup
D --> E[Commit changes & push branch]:::git
E --> F{Release type?}:::decision
F -->|RC| RC1["cz bump --dry-run<br/>then cz bump rcN"]:::setup
F -->|Stable| ST1["cz bump --dry-run<br/>then cz bump"]:::setup
RC1 --> RC2["git tag vX.Y.ZrcN<br/>git push origin vX.Y.ZrcN"]:::git
RC2 --> RC3[CI: publish-testpypi.yml]:::ci
RC3 --> RC4[TestPyPI + GitHub pre-release]:::rc
RC4 -->|Issues found| B
RC4 -->|RC approved| ST1
ST1 --> ST2["Open PR: release/vX.Y.Z → main"]:::pr
ST2 --> ST3{Review & approve}:::decision
ST3 --> ST4[Merge PR into main]:::pr
ST4 --> ST5["git checkout main && git pull<br/>git tag vX.Y.Z<br/>git push origin vX.Y.Z"]:::git
ST5 --> ST6[CI: publish-pypi.yml]:::ci
ST6 --> ST7[PyPI + GitHub Release]:::stable
classDef setup fill:#dbeafe,stroke:#3b82f6,color:#1e3a5f
classDef pr fill:#ede9fe,stroke:#8b5cf6,color:#3b0764
classDef decision fill:#fef9c3,stroke:#ca8a04,color:#713f12
classDef git fill:#f0fdf4,stroke:#22c55e,color:#14532d
classDef ci fill:#fff7ed,stroke:#f97316,color:#7c2d12
classDef rc fill:#fdf4ff,stroke:#d946ef,color:#701a75
classDef stable fill:#ecfdf5,stroke:#10b981,color:#064e3b
1. Create the release branch
After all PRs for the release are merged into main, create a dedicated release branch.
Important
Always branch off from an up-to-date main. Never start a release from a stale local copy.
git checkout main && git pull
git checkout -b release/vX.Y.Z
git push -u origin release/vX.Y.Z
2. Apply hotfixes and documentation updates
Use the release branch to apply any last-minute bug fixes, dependency security patches, or documentation updates required before the release.
Note
Only bug fixes and documentation changes belong on the release branch. New features must target the next release cycle via main.
Warning
If you update any dependencies (e.g. to resolve security findings), regenerate the lock file immediately:
poetry update <package>
Then verify the change does not break any tests.
Security audit — run pip-audit and resolve any vulnerability with an available fix before bumping the version:
poetry run pip-audit
Vulnerabilities with no upstream fix available should be noted and tracked as known accepted risks.
3. Quality checks
Run all checks in the order shown below. Each step must pass cleanly before proceeding to the next.
3.1 Linting
just lint
Runs ruff check --fix and auto-corrects fixable issues. Review and manually resolve any remaining errors.
3.2 Formatting
just format
Runs ruff format to ensure consistent code style across the codebase.
3.3 Pre-commit hooks
just check
Runs all pre-commit hooks across all files: ruff lint/format, prettier (YAML/Markdown/JSON), and Pyright type checking.
Important
If just check modifies any files, stage and commit them before continuing:
git add -u && git commit -m "style: apply pre-commit formatting"
3.4 Unit tests
just test
Runs the full test suite with coverage reporting.
Warning
A test failure at this stage must be fixed on the release branch before proceeding. Do not skip, suppress, or comment out failing tests.
4. Documentation
Build the HTML docs locally. Sphinx treats all warnings as errors (-W), so every warning must be resolved before proceeding.
just docs
Review the rendered output in docs/_build/html/. Check for broken links, missing API entries, and any rendering issues on new or changed pages.
Note
See the Documentation Guide for docstring conventions and tips on building docs locally.
5. Commit all changes
Once all checks and the documentation build pass cleanly, stage and commit any outstanding changes:
git add -A
git commit -m "chore(release): pre-release fixes and QA for vX.Y.Z"
git push origin release/vX.Y.Z
Note
Prefer just commit over a manual git commit to stay consistent with the conventional commit style enforced by commitizen.
6. Version bump
Important
Always run --dry-run first and review the proposed CHANGELOG entries carefully before applying the bump.
Step 1 — preview:
poetry run cz bump --dry-run
Inspect the output:
The proposed increment (MAJOR / MINOR / PATCH) matches expectations
The CHANGELOG entries are complete and correctly classified
There are no duplicate entries (can happen when multiple commits share identical messages)
Step 2 — apply:
poetry run cz bump
This will:
Update
versioninpyproject.tomlAppend the new section to
CHANGELOG.mdCreate a local commit:
bump: version X.Y.Z-1 → X.Y.Z
Step 3 — review the bump commit:
git show HEAD
Check that pyproject.toml shows the correct version and that CHANGELOG.md reads cleanly. Manually amend duplicate entries if present, then push:
git push origin release/vX.Y.Z
For a release candidate — set the version explicitly instead of using cz bump:
poetry version X.Y.ZrcN
poetry lock
git add pyproject.toml poetry.lock CHANGELOG.md
git commit -m "bump: version X.Y.Z-1 → X.Y.ZrcN"
See Versioning for the full SemVer rules and commit-type reference.
7. Tag and publish a release candidate
RC tags are pushed directly from the release branch — no PR to main is required.
git tag -a vX.Y.ZrcN -m "Release candidate vX.Y.ZrcN"
git push origin vX.Y.ZrcN
This triggers publish-testpypi.yml, which publishes to TestPyPI and creates a GitHub pre-release.
If issues are found, fix them on the release branch (return to step 2), bump to the next RC (rcN+1), and repeat.
8. Release PR (stable only)
Once all RCs are approved (or skipping RC for a straightforward release), open a PR from release/vX.Y.Z to main on GitHub.
After review and approval, merge the PR
Merging to
maindoes NOT trigger a PyPI release
Important
Promoting a model from experimental to stable? Verify the Model Promotion Policy checklist is complete before merging a release PR that includes a promotion.
9. Create and push the stable tag
After the release PR is merged into main:
git checkout main && git pull
git tag -a vX.Y.Z -m "Release vX.Y.Z"
git push origin vX.Y.Z
Warning
Pushing the tag triggers PyPI publication immediately and cannot be undone. Confirm that main is in the expected state and the version in pyproject.toml is correct before pushing.
10. Publish package
The tag push automatically triggers the appropriate GitHub Actions workflow — see CI/CD for full details. In summary:
Stable tag (
vX.Y.Z) →publish-pypi.yml→ PyPI + GitHub ReleaseRC tag (
vX.Y.ZrcN) →publish-testpypi.yml→ TestPyPI + GitHub pre-release
Both workflows use OIDC Trusted Publishing — no API tokens required.
11. GitHub Release
The GitHub Release is created automatically by the publish workflow. Once it appears, verify that:
The release notes reflect the correct CHANGELOG section
Assets (wheel and sdist) are attached
The release is marked stable (not pre-release) for a stable tag
Add any manual context or migration notes to the release description if needed.