alunduil / alunduil/collection-json.hs
Automate Hackage releases: derived PVP bump + generated changelog
- Langage dominant
- Haskell
- Étoiles
- 3
- Forks
- 1
- Merge moyen
- 5 h 32 min
- PR mergées (30 j)
- 67
Description
## Summary
Proper release automation for Hackage: a mechanically-derived PVP bump
and a generated changelog, opened as a release PR when changes land.
Delivered in independently-mergeable pieces. Both the bump level and the
changelog are **derived, never declared** — a mis-classified bump is a
PVP violation, and the `[Unreleased]` section is not reliably kept
current, so neither a human-picked default nor a hand-maintained section
is acceptable.
## Motivation
#140 documents a manual cadence as a stopgap (PR #158). The durable fix
removes the maintainer from assembling releases by hand so dep bumps and
changes reach Hackage on their own — the 7-year-stale-upload problem.
Builds on the tag-driven `release.yml` already in place.
## Non-negotiables
- **Bump level derived from an API diff** (last released version → HEAD),
not declared or defaulted. A `fix:` that changes a signature is a PVP
major (A.B); a patch default would ship it wrong.
- **Changelog generated from history**, not read from `[Unreleased]` —
that section is not reliably maintained.
## Pieces
### 1. Spike: API-diff → PVP verdict (keystone)
Prove a tool (`cabal-diff`, `hackage-diff`, or GHC `.hi`-interface
comparison) reliably classifies `1.3.1.3` → HEAD as A.B / C / D for this
package. Every downstream piece's correctness rides on this. Deliverable:
a working command + a go/no-go. If nothing is reliable enough, that
reshapes the whole approach — surface it before building further.
### 2. Changelog generation
git-cliff (or equivalent) + a commit convention going forward. Wrinkle:
~7 years of non-conventional history won't reconstruct cleanly, so the
first generated entry is curated once and generation takes over from the
next release. Deliverable includes an honest assessment of how much of
the backlog git-cliff can actually recover.
### 3. Version-bump script
Reads the current `version:` from the cabal file, applies the piece-1
verdict to the correct PVP position, rolls the piece-2 changelog, and
opens a release PR. No default level.
### 4. Weekly workflow + release wiring
Scheduled job runs the script and opens/updates the release PR; no-op
when nothing has landed. On merge, create the `v` tag →
`release.yml` uploads the candidate → the candidate is smoke-tested
(#259) → publish runs automatically with the promoted candidate
artifact (#258).
**The release PR is the only human gate.** Approving it is where the
derived version bump and the generated changelog get confirmed;
everything after the merge is unattended. Publish therefore stops being
a `workflow_dispatch` and fires off the tag. The long-term intent is to
automate the approval away too once it's reliably rubber-stamped, so
don't add gates downstream of the merge — harden the checks feeding it
instead.
## Gotchas
- Tag on merge needs a **PAT or GitHub App token** — `GITHUB_TOKEN`-pushed
tags don't trigger `release.yml`. Alternative: refactor `release.yml`
to fire on a version-change merge to `main` (read it first per repo
CLAUDE.md).
- That token / branch-protection bypass lives in **alunduil-infrastructure
Terraform** — spans a second repo.
- Auto-publish makes the candidate smoke test (#259) load-bearing: it is
the last check before an irreversible Hackage upload. Land it, and the
candidate promotion in #258, before flipping publish off
`workflow_dispatch`.
- The `hackage` environment currently has no protection rules (#260).
Restrict it by deployment tag, not by required reviewer — a reviewer
would reintroduce the manual gate this design removes.
## Acceptance criteria
- [ ] Piece 1 recorded: does an API-diff tool give a reliable PVP verdict
for this package? (go/no-go)
- [ ] Changelog generated from history; backlog-recovery limits documented
- [ ] Commit convention adopted, with a lint
- [ ] Bump script derives the version from the API diff — no default level
- [ ] Weekly workflow opens the release PR; no-op when nothing landed
- [ ] Merging the release PR tags and triggers `release.yml`
- [ ] Merging the release PR results in a published Hackage version with
no further human action
- [ ] CONTRIBUTING cadence section revised to the automated flow
## Additional context
Relates to #140 (interim manual cadence, currently in PR #158).
Supersedes #143, which covered pieces 1, 3, and 4 of this issue at less
depth; the release-please rejection rationale it recorded is preserved in
#107's closing comment.
Discrete pieces filed separately: #258 (publish the promoted candidate
artifact), #259 (smoke-test the candidate as a downstream consumer), #260
(restrict the `hackage` environment), #261 (GitHub Releases), #144 (the
candidate job's environment-scoped token, PR #256). Merge gating is #165.
Guide de contribution
Ouvrir le guide de contribution
Évaluation
Cette issue n'a pas encore été évaluée.