Release transformers-mlinter
Cuts a versioned release. The canonical prose reference is docs/release.md; this
skill is the operational checklist. Publishing itself is done by CI — pushing the
vX.Y.Z tag triggers .github/workflows/release.yml, which builds, tests, and
publishes to PyPI via OIDC trusted publishing (no local upload).
Input
<version>: the target release versionX.Y.Z(e.g.0.1.2). A pre-release usesX.Y.ZrcN.
Constraints
- Semantic versioning. Patch releases (
Zbumps) reuse the existingvX.Y-releasebranch; a new minor/major starts a freshvX.Y-releasebranch. - Work from a clean checkout on
main. Never publish uncommitted changes. - Do NOT run
twine uploadlocally — publishing is CI-only via the pushed tag. - Always confirm with the user before pushing the tag (the tag push is the irreversible, publish-triggering step).
The version lives in one place
pyproject.toml [project].version is the single source of truth. At runtime
mlinter/_version.py reads the version from the installed distribution metadata,
falling back to pyproject.toml; nothing else hardcodes the release version. So a
release bumps exactly one version field plus the CHANGELOG:
pyproject.toml—[project].version(the only version edit)CHANGELOG.md— a new## [X.Y.Z] - YYYY-MM-DDsection (see step 2)
Do NOT reintroduce hardcoded version strings elsewhere. DEFAULT_BASE_VERSION in
mlinter/_version.py is a static 0.0.0 sentinel and must stay unbumped; the
docs/usage.md example suffix and the tests/test_mlinter.py version pins use fixed
illustrative values (1.2.3+g1a2b3c4, 9.9.9) decoupled from the real release.
Workflow
Preflight. Confirm the branch is
main, the tree is clean, and it is up to date (git status,git fetch && git status). Confirm the target<version>is greater than the latest tag (git tag).Update
CHANGELOG.md. Add a## [X.Y.Z] - YYYY-MM-DDsection (today's date) above the previous release, using### Added(new TRF rules only, in rule-number order) /### Improved(everything else that is not a bug fix) /### Fixed. KeepingAddedto rules alone is what makes it scannable — a release adds dozens. Summarize what landed since the last tag —git log vPREV..HEAD --onelineis the source. Each newTRFNNNrule and any change to file-discovery globs gets an entry.Bump the version — set
[project].versioninpyproject.tomlto<version>. That is the only version edit. For a release that added newTRFNNNrules, also add the corresponding public-API assertions intests/test_mlinter.py(public_api.TRFNNN == "TRFNNN"and"TRFNNN"inpublic_api.__all__) — mirror the existing pattern.Run local checks. All three must pass:
make lint make test make typecheckBuild and validate the package.
make build-release python -m twine check --strict dist/*Then smoke-test the wheel in a throwaway venv (adjust the version string):
python -m venv /tmp/mlinter-release && source /tmp/mlinter-release/bin/activate pip install dist/*.whl cd /tmp && mlinter --version && python -m mlinter --version python -c "import mlinter; print(mlinter.__version__)" deactivatemlinter --versionmust printX.Y.Z(no+g...suffix from an installed wheel).Commit the bump on
main. Match the existing message style:git add pyproject.toml CHANGELOG.md git commit -m "preparing for X.Y.Z" git push origin mainAdd any other files the release genuinely touched (new rule modules, tests, etc.).
Update the release branch. For a new minor line:
git switch -c vX.Y-release git push -u origin vX.Y-releaseFor a patch on an existing line, fast-forward the branch from
main:git switch vX.Y-release && git merge --ff-only main && git push origin vX.Y-releasePushing the branch runs the
Releaseworkflow's build+test job (no publish yet).Tag and publish. Confirm with the user first, then from
vX.Y-release:git tag vX.Y.Z -m "Release vX.Y.Z" git push origin vX.Y.ZThe tag push triggers the build job again followed by the
upload_packagejob, which runs in thepypi-releaseenvironment (may require reviewer approval) and publishes viapypa/gh-action-pypi-publishwith OIDC. Watch the run withgh run watchorgh run list --workflow=release.yml.Verify from PyPI once the publish job succeeds:
python -m pip install -U "transformers-mlinter==X.Y.Z" mlinter --versionOpen the next development version. With
X.Y.Zpublished, movemainoff the released version so subsequent commits are not attributed to a version already on PyPI. Default to the next patch,X.Y.(Z+1), unless the user names a different target. Two edits:pyproject.toml— set[project].versionto the next versionCHANGELOG.md— add a bare## [Unreleased]heading above the section just released, with no subsections; the next change adds its own### Added/### Improved/### Fixed
This lands on
mainthrough a branch, not a direct push:git switch main && git pull git switch -c start-NEXT # edit pyproject.toml and CHANGELOG.md git add pyproject.toml CHANGELOG.md git commit -m "Starting version NEXT" git push -u origin start-NEXT gh pr create --title "Starting version NEXT" --body "Post-release bump after X.Y.Z." gh pr merge --squash --delete-branchThe squash keeps
Starting version NEXTas the commit subject onmain. Do not tag this commit and do not merge it intovX.Y-release— the release branch stays at the released version.
Notes
- No
.dev0suffix is used. Releasing is a single bump + tag; the step 10 post-release bump setsmainto the next plainX.Y.Z. - First-ever PyPI publish requires a pending trusted publisher configured on PyPI
pointing at
release.ymlwith environmentpypi-release— seedocs/release.md. - Optional TestPyPI dry run is documented in
docs/release.mdand is manual.