Commit graph

2 commits

Author SHA1 Message Date
f9a99056fe
fix(release): release notes come from the CHANGELOG, not the tag message
Same-day correction to ee2259f. That commit followed the order literally --
"use the tag's own message" -- and the result was an llm-security v8.0.0
release page reading "llm-security v8.0.0" and nothing else.

The defect is structural, not a typo: --create-tag mints -m "<name>
v<version>", so the tag message is mechanical EXACTLY where this helper made
the tag. The tag message is a good source only for tags written by hand.

The right source was already proven on the instance: llm-security v7.8.3's
release body is byte-for-byte its CHANGELOG `## [7.8.3]` section. So the
CHANGELOG is the org's established source, not a new invention -- and all 10
backfilled repos ship one (measured, 10/10).

- extractChangelogSection / releaseBodyFrom: pure, tested. Priority is
  CHANGELOG section -> tag message -> empty, and the source is REPORTED so a
  run says where the text came from rather than implying it wrote it.
- Three heading dialects are live and all three are covered: `## [6.0.0] -
  date`, `## [0.2.0] -- date` (em-dash), `## v1.0 (date)`, and voyage's
  `## v5.10.1 -- date -- trailing prose`. The version token matches exactly,
  so 0.1.0-pre is not 0.1.0 and 1.1.0 is not 1.10.0. An empty section (the
  standing `## [Unreleased]`) returns null so the caller falls through
  instead of publishing a blank body.
- backfill gains --repair for the backlog the first cut created. It PATCHes
  a PUBLISHED page, so the bar is strictly more informative, never merely
  different: no CHANGELOG section means no update, and a hand-written body at
  least as long as the section is left alone. Measured: that rule is what
  protects portfolio-optimiser v1.1.0 (4750 hand-written chars vs 3704).

Dry-run over the org: 14 release objects would gain real notes, e.g.
llm-security v8.0.0 19 chars -> 10530, config-audit v6.0.0 19 -> 27309.

18 new tests, written red first. Suite 211/211; check-versions 12/12 OK.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-18 02:41:18 +02:00
ee2259f63f
feat(release): file the Forgejo release object as part of a release
A pushed git tag is filed by Forgejo under /tags; only an explicit release
object appears under /releases. release-plugin.mjs only ever made a tag, so
every plugin's public releases page sat a version behind the ref the catalog
pinned -- llm-security showed v7.8.3 against a v8.0.0 tag.

Measured 2026-09-18 against the instance API: 24 repos in org `open`, 21 with
at least one tag, 11 of those 21 with no release object for their newest tag.
That reproduces the order's own independently-measured list exactly.

- parseForgejoRepo / planForgejoRelease / ensureForgejoRelease: pure, tested.
  The release body is the tag's own message VERBATIM or empty -- never
  generated prose. Read via %(contents:subject)+%(contents:body), never
  %(contents), which drags the SSH signature block into the notes.
- The step fires only on a run that PUBLISHES (--create-tag --write, or
  --push): filing a release object is itself a publish and must not ride
  along on a local --write past the operator's one-shot push token.
- Synchronous (curl via execFileSync), like check-versions.mjs's
  checkHomepage: runRelease is called without an await and its return value
  becomes the exit code, so an async step would let a rejected POST surface
  after the run had already exited 0 and called the release complete.
- 429 and the 502/503/504 family are retried with backoff, never swallowed.
  An unthrottled sweep drew 17 HTTP 429s and the first version of that sweep
  read every one as an empty list -- "verified nothing" was indistinguishable
  from "verified everything, all clean".
- The token reaches curl through a 0600 header file, never argv.

scripts/backfill-forgejo-releases.mjs covers the backlog and retries the one
step, reusing the same planner and API shell so the two cannot drift. Only
the newest tag is considered. Documented exception: ktg-plugin-marketplace
pre-polyrepo-archive, an archive marker, not a release; the register is keyed
by repo AND tag so that repo's next real release is still backfilled.

Tests written red first: 20 new (12 release path, 8 backfill), and the two
real-git integration tests were probed known-negative -- breaking the wiring
turns 68/0 into 66/2. Suite 193/193; check-versions 12/12 OK.

The backfill of the 10 outstanding release objects is NOT done: it was denied
in-session as a public-surface write and is the operator's call.

Order: 20260917T235642Z-730962924-from-from-ai-to-chitta

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-18 02:23:52 +02:00