Release pipeline
Maintainer workflow for publishing the eai-sup* family
(eai-supcore, eai-supinit, eai-supmig) in lockstep. Mirrors the
pyswig / a2c release pipeline: curated changelog, bump_release.py, tag
verification, wheel smoke tests, GitLab registry, TestPyPI gate, then manual
production PyPI.
See also package-publishing.md for package layout and CI variables.
Prerequisites
- Protected refs (Settings → Repository → Protected branches and tags):
- Branches:
master,develop - Tags:
v*(required so masked/protected CI variables are available on tag pipelines)
- Branches:
- CI variables (masked):
TWINE_PASSWORD_TESTPYPI— TestPyPI API token; not protected (needed ondevelopfor manualpublish:testpypi:branch)TWINE_PASSWORD_PYPI— PyPI API token; protected (tag pipelines only)
- PyPI and TestPyPI projects registered for
eai-supcore,eai-supinit,eai-supmig - GitLab Package Registry enabled (
publish:gitlabusesCI_JOB_TOKEN)
Changelog policy
CHANGELOG.md follows Keep a Changelog.
- Keep a single
## [Unreleased]section with### Added/### Changed/### Fixedbullets as work lands ondevelop. - Use
- (nothing yet)when a subsection has no entries yet. - Do not dump raw commit lists into the changelog; write user-facing notes.
- At release,
python scripts/bump_release.py:- moves
[Unreleased]notes into## [X.Y.Z] - YYYY-MM-DD - resets
[Unreleased]with placeholder bullets - updates footer compare/tag links (
[Unreleased]: …,[X.Y.Z]: …)
- moves
- The bump script also syncs lockstep version across
VERSION, all three__version__attrs,packages/eai-supcoreproject version, and CLIeai-supcore==pins, then creates achore(release): Bump version to X.Y.Zcommit (add--tagto create the annotated tag locally).
Example unreleased section:
## [Unreleased]
### Added
- `eai-supmig doctor` reports missing Conan profiles
### Fixed
- Bootstrap skips ai-rules submodule when `tools/ai-rules/` is already a git repo
Release steps
- Land features on
develop; keepCHANGELOG.md[Unreleased]curated. - Wait for green CI on
develop. - Run
python scripts/bump_release.py(lockstep version sync + changelog + commit) and pushdevelop. - Wait for green CI on the bump commit on
develop. - Tag from
develop:git tag -a vX.Y.Z -m "Release X.Y.Z"thengit push origin vX.Y.Z(tag pipelines use protectedv*variables). - Wait for the tag pipeline to succeed through at least
package:build,package:smoke,publish:gitlab,publish:testpypi, andpackage:smoke-testpypi. Fix ondevelopand re-tag only if that fails — do not updatemasteryet. - Optionally run manual
publish:pypi(thenpackage:smoke-pypi) when ready for production. - Last step: FF-merge (or rebase)
develop→masterand pushmasteronly after the release is known good.
Optional pre-tag validation on develop: after a branch pipeline builds wheels
(build:package), trigger manual publish:testpypi:branch.
Branch pipeline jobs
| Job | When | Purpose |
|---|---|---|
build:package | develop, master, MR | Build wheel/sdist; twine check |
publish:testpypi:branch | manual on develop / master | Upload to TestPyPI (allow_failure: true) |
Tag pipeline jobs
| Job | When | Purpose |
|---|---|---|
package:build | tag | verify_release_version.py; build; twine check |
package:smoke | tag | Fresh venv: install all three wheels; CLI --help |
publish:gitlab | tag, automatic | Upload to GitLab PyPI registry |
publish:testpypi | tag, automatic | Upload to TestPyPI |
package:smoke-testpypi | after TestPyPI | Lockstep eai-supcore/init/mig==X.Y.Z from TestPyPI |
publish:pypi | tag, manual | Upload to production PyPI |
package:smoke-pypi | after PyPI | Lockstep eai-supcore/init/mig==X.Y.Z from PyPI |
Local dry-run
pip install -e packages/eai-supcore -e packages/eai-supinit -e packages/eai-supmig -e ".[dev]"
python scripts/build_packages.py
python -m twine check dist/*
python scripts/smoke_install_package.py --dist dist --expected-version 0.4.4 --venv .smoke-venv
python scripts/bump_release.py --dry-run
On Windows, use the same commands from an activated .venv.
Version source of truth
VERSION(repo root) — lockstep version for all three distributions- Mirrored in
src/eai_sup{core,init,mig}/__init__.pyand CLIeai-supcore==pins - Git tag
vX.Y.Zmust match that version (scripts/verify_release_version.py)