SuperAPI AI Directory

releasing

General & other

View repository

Updated 10-16 00:29

About this skill

Releasing mergify-cli

Everything is driven by .github/workflows/release.yml. There is no version to bump in any file — pyproject.toml and Cargo.toml keep their placeholder versions and the workflow stamps the tag in at build time. Never open a "release prep" PR.

Versions are calver: YYYY.M.N (no zero padding, N counts releases within the UTC month from 1, e.g. 2026.10.1). Three components so the version is valid SemVer for npm, since the CLI shares its version with the test-framework clients. Releases before October 2026 used YYYY.M.D.N.

RELEASING.md at the repo root is the human-facing runbook and explains why the flow is shaped this way (GitHub's immutable-releases policy). Read it when something goes wrong or the workflow itself needs changing.

Guardrails

  • Never run gh release create or push a tag by hand. A release created outside the workflow has no binaries, and once published it is immutable — the asset assertion then permanently blocks the PyPI publish for that version.
  • Never click / script "Draft a new release" in the Releases UI. Same trap.
  • Stage 2 (Publish) is irreversible and outward-facing — it locks the release and pushes to PyPI. Always get the user's explicit go-ahead before publishing, even if they already asked for "a release"; report the draft URL and stop.
  • Stage 1 is safe and repeatable: a draft can be deleted and rebuilt.

Stage 1 — build the draft

Pre-flight (report anything red, don't silently proceed):

gh run list --workflow=ci.yaml --branch main --limit 1              # main is green
gh release list --limit 3                                           # no leftover draft
git log --oneline $(git describe --tags --abbrev=0)..origin/main    # what ships

Trigger it:

gh workflow run release.yml                  # auto-picks YYYY.M.<next>
# or, only when a specific version is needed:
gh workflow run release.yml -f tag=2026.10.1 -f target_commitish=<sha>

Leave tag empty unless the user asked for a specific version; leave target_commitish empty unless cherry-picking a release off an older line.

Watch it (~5–10 min):

gh run list --workflow=release.yml --limit 1
gh run watch <run-id> --exit-status

It builds the seven-target wheel matrix, extracts the mergify binary from each wheel except the two musllinux ones (those only go to PyPI), packages the archives + SHA256SUMS, dumps cli-schema.json, signs the binaries with build provenance, and creates the draft release with notes generated from the PRs merged since the previous tag.

Then verify — the draft must carry exactly these seven assets:

tag=$(gh release list --limit 1 --json tagName --jq '.[0].tagName')
gh release view "$tag" --json isDraft,url,assets --jq '{draft:.isDraft,url:.url,assets:[.assets[].name]}'
  • mergify-<tag>-x86_64-unknown-linux-gnu.tar.gz
  • mergify-<tag>-aarch64-unknown-linux-gnu.tar.gz
  • mergify-<tag>-x86_64-apple-darwin.tar.gz
  • mergify-<tag>-aarch64-apple-darwin.tar.gz
  • mergify-<tag>-x86_64-pc-windows-msvc.zip
  • SHA256SUMS
  • cli-schema.json

Give the user the draft URL and the generated notes to review. Stop here.

Stage 2 — publish

Only after the user explicitly says to publish:

gh release edit "$tag" --draft=false --latest

That fires release: published, which re-asserts the seven assets, rebuilds the wheels with the same version stamp, and pushes to PyPI via Trusted Publishing (~5–10 min). Watch the release run the same way as in stage 1.

Note edits must happen before this (gh release edit "$tag" --notes-file notes.md) — drafts are mutable, published releases are not.

Verify after publishing

gh run list --workflow=release.yml --limit 2          # publish job green
curl -s https://pypi.org/pypi/mergify-cli/json | jq -r .info.version
gh pr list --repo Mergifyio/homebrew-tap --author mergify-ci-bot

The Homebrew formula bump is automatic: the homebrew-tap-sync workflow in Mergifyio/mergify-ci-bot opens a PR against Mergifyio/homebrew-tap within ~20 minutes of publish, updating RELEASE and the four per-arch checksums from SHA256SUMS. It still needs a human to merge it. The docs site picks up cli-schema.json off the latest release on its own — nothing to do there.

Recovery

Symptom Fix
Stage 1 failed mid-run No release exists yet, or a draft does. Delete the draft (gh release delete <tag> --cleanup-tag) and re-run stage 1.
Draft missing assets Delete the draft and re-run stage 1 — never backfill by hand.
assert-binaries-present failed after publish The release was created outside the workflow and is now immutable. Delete the release and its tag, then re-run stage 1 with the same tag.
PyPI publish failed (transient / outage) Wheels are built; re-run just the failed job: gh run rerun <run-id> --failed.
Wrong version already on PyPI PyPI versions can't be reused or overwritten. Ship the next N — do not try to reuse the tag.