Skip to content

rubygems-release: guarantee GitHub Release for every published tag (closes ci#354) - #355

Open
opoudjis wants to merge 3 commits into
mainfrom
feature/rubygems-release-github-release-notes
Open

rubygems-release: guarantee GitHub Release for every published tag (closes ci#354)#355
opoudjis wants to merge 3 commits into
mainfrom
feature/rubygems-release-github-release-notes

Conversation

@opoudjis

@opoudjis opoudjis commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Closes #354

Summary

Two coordinated changes: (1) the release-notes floor on rubygems-release.yml, and (2) the opt-out variants for the 27 opoudjis-maintained gems that write their notes by hand.

Part 1 — release-notes floor in rubygems-release.yml

Adds a mechanical floor: every tag pushed by the shared workflow carries a GitHub Release with at least auto-generated notes (PR titles since the previous tag). Closes the class where a gem accumulates tags with no releases (metanorma-plugin-lutaml v0.7.35-v0.7.50 hit this before backfill; the same pattern recurs elsewhere in the stack).

New input

release_notes: 'auto' (default) | 'manual'
  • auto — if no Release exists for the pushed tag, create one with auto-generated notes (PR titles since the previous tag).
  • manual — skip the ensure-release step entirely.

Never overwrite

If a Release already exists for the tag (whether from a hand-written maintainer note or a prior workflow run), the step detects it via gh release view and leaves it alone. gh release create only fires on the not-exists path.

Placement

The new step lives at the end of the release job, right after the "Verify gem published on rubygems.org" post-publish check and before the "Post-release event" repository_dispatch. Runs on the same SHOULD_PUBLISH / skip_push gates as the publish step itself, plus release_notes != 'manual'.

Auth

Uses the release job's existing contents: write permission (inherited from the caller — every current caller template carries contents: write per ci#339). No new secret required.

Part 2 — opt-out variants for 27 opoudjis-maintained gems

Per opoudjis's decision on the ticket, the floor is opt-out for gems whose maintainers write release notes by hand at release time. Introduces two variant caller templates + updates 27 cimas.yml mappings.

Variant templates (2 new files)

  • cimas-config/gh-actions/master/release_manual_notes.yml — variant of release.yml that passes release_notes: manual to the reusable.
  • cimas-config/gh-actions/master/release_wo_bundle_install_manual_notes.yml — variant of release_wo_bundle_install.yml with the same opt-out.

Each variant file carries a header block naming its parent template, its consumer set, and how to switch back to the auto-notes floor. Same per-variant documentation discipline established with Gemfile.grammar-build in ci#353.

cimas.yml mapping updates (27)

  • 24 gems switching from release.ymlrelease_manual_notes.yml:
    metanorma-cli, metanorma-core, metanorma-ogc, metanorma-cc, metanorma-ribose, metanorma-iho, metanorma-ieee, metanorma-iec, metanorma-ietf, metanorma-standoc, metanorma-iso, metanorma-taste, metanorma-itu, metanorma-generic, metanorma-bipm, metanorma-jis, metanorma-plateau, metanorma-document, isodoc, isodoc-i18n, html2doc, gb-agencies, cnccs, isoics.
  • 3 gems switching from release_wo_bundle_install.ymlrelease_wo_bundle_install_manual_notes.yml:
    metanorma-utils, metanorma (top-level), mn-requirements.

Exempt-by-construction (no variant needed)

  • metanorma-nist and metanorma-bsi map release_github_packages.yml, which calls ghpkg-release.yml, not rubygems-release.yml. Part 1's floor lives in rubygems-release.yml and doesn't reach the ghpkg-release path. Those two gems are already exempt without any variant mapping.

Non-opoudjis gems

Every gem not in the opt-out list keeps its current mapping and gets the auto-notes floor on their next release run. This is the intended default per ticket #354.

Effect after next cimas wave (~2026-07-22)

  • Non-opt-out gems: their next release carries auto-generated Release notes if none exist, hand-written notes preserved if they do.
  • Opt-out gems (the 27 above): their release.yml gets synced to the variant, workflow skips the ensure-release step, maintainer authors Release + notes by hand.

🤖

opoudjis added 3 commits July 21, 2026 13:14
…loses ci#354)

Adds a floor: every tag this workflow publishes carries a GitHub
Release with at least auto-generated notes (PR titles since the
previous tag). Closes the class where gems accumulate tags with no
releases (metanorma-plugin-lutaml v0.7.35-v0.7.50 hit this before
backfill; the same pattern recurs elsewhere in the wider stack).

## New input

  release_notes: 'auto' (default) | 'manual'

- 'auto' — if no Release exists for the pushed tag, create one with
  auto-generated notes.
- 'manual' — skip the ensure-release step entirely. For gems whose
  maintainers write release notes by hand at release time; the
  maintainer creates the Release themselves.

## Never overwrite

If a Release already exists for the tag (whether created by hand with
maintainer notes, or by a prior run of this workflow), the step
detects it and leaves it alone. `gh release view` is used as the
existence check; `gh release create` only fires on the not-exists path.

## Placement

New step lives at the end of the release job, right after the
"Verify gem published on rubygems.org" post-publish check and before
the "Post-release event" repository_dispatch. Runs on the same
SHOULD_PUBLISH / skip_push gates as the publish step itself, plus the
release_notes != 'manual' opt-out.

## Auth

Uses the release job's existing `contents: write` permission
(inherited from the caller — every current caller template has
`permissions: contents: write` per ci#339). No new secret required;
`GITHUB_TOKEN` is sufficient for release creation on the workflow's
own repo.

Closes #354.
Introduces the opt-out mechanism opoudjis called for on ci#354 for
maintainers who write GitHub Release notes by hand at release time.

- `gh-actions/master/release_manual_notes.yml` — variant of
  `release.yml` that passes `release_notes: manual` to the reusable.
- `gh-actions/master/release_wo_bundle_install_manual_notes.yml` —
  variant of `release_wo_bundle_install.yml` with the same opt-out.

Each variant file carries a header block naming its parent, its
consumer set, and how to switch back to the auto-notes floor. Same
per-variant documentation discipline as the `Gemfile.grammar-build`
variant added to `gh-actions/model/` in ci#353.

- 20 gems mapping `release.yml` → `release_manual_notes.yml`:
  metanorma-cli, metanorma-core, metanorma-ogc, metanorma-cc,
  metanorma-ribose, metanorma-iho, metanorma-ieee, metanorma-iec,
  metanorma-ietf, metanorma-standoc, metanorma-iso, metanorma-taste,
  metanorma-itu, metanorma-generic, metanorma-bipm, metanorma-jis,
  metanorma-plateau, metanorma-document, isodoc, isodoc-i18n.
- 1 gem mapping `release_wo_bundle_install.yml` →
  `release_wo_bundle_install_manual_notes.yml`: metanorma-utils.

- `metanorma-nist`, `metanorma-bsi` map `release_github_packages.yml`,
  which calls `ghpkg-release.yml`, not `rubygems-release.yml`.
  ci#354's auto-notes floor lives in `rubygems-release.yml` and
  doesn't reach the ghpkg-release path, so those two gems are already
  exempt without any variant mapping.

The variants land on origin main for the 21 opoudjis-maintained gems.
Their next release runs pass `release_notes: manual` to the reusable
(introduced in the sibling commit on this branch), the reusable skips
its Ensure-GitHub-Release step, and Release + notes remain the
maintainer's manual responsibility.
…et (ci#354)

Follow-up to the initial 21-gem opt-out set. Adds the non-metanorma-*
gems the maintainer confirmed as owned but that my initial predicate
missed (predicate was too narrow — matched only 'metanorma-*' + explicit
'isodoc*'/'basicdoc-models').

Added to release_manual_notes.yml (release.yml → variant):
- html2doc
- gb-agencies
- cnccs
- isoics

Added to release_wo_bundle_install_manual_notes.yml
(release_wo_bundle_install.yml → variant):
- metanorma (top-level gem — family root, not matched by 'metanorma-*'
             predicate because no trailing '-<flavour>')
- mn-requirements

Total opt-out set is now 27 gems (still 2 exempt-by-construction:
metanorma-nist + metanorma-bsi via release_github_packages.yml).

Also updated the maintainer memory file (~/.claude/memory/user_maintained_gems.md
locally) to record these six explicitly, matching the discipline used
for basicdoc-models 2026-06-24. Memory update is out-of-tree from this
repo but referenced here for the paper trail.
@opoudjis
opoudjis force-pushed the feature/rubygems-release-github-release-notes branch from e7309be to 631fd77 Compare July 21, 2026 03:30
ronaldtse added a commit that referenced this pull request Jul 25, 2026
Reverts the two-phase "gated-direct" release architecture added in #293.
A release is now atomic: workflow_dispatch bumps + tags + publishes in
one job. A green run means the gem is on rubygems.org. The idempotent
push guard handles duplicate pushes (re-runs, stale do-release
listeners from consumer rake.yml files).

Why (see ci#370 for full postmortem):

- "Publication DEFERRED" was a green check. A run that did NOT publish
  reported success, inverting the meaning of green. Maintainers could
  not tell from the run list whether a release actually shipped.
- The 11-hop relay (workflow_dispatch → tag → rake → do-release →
  publish) required per-consumer wiring that wasn't enforced. fractor
  v0.1.11 failed silently because its rake.yml didn't dispatch
  do-release; the tag-listener preflight passed because it matched
  dependent-tests.yml, which also doesn't dispatch do-release.
- Wrapper workflows (omnizip, other non-cimas consumers) couldn't
  reach override inputs on the inner shared workflow. Hard-stop with
  no maintainer recourse.
- The original motivation (double-publish race) was already handled
  by gem-idempotent-push-guard-action. The relay was solving a
  problem already solved.
- Test gating belongs at PR time (required status checks on the main
  branch), not as a workflow-level relay splitting publish across
  multiple events.

What's removed:

- SHOULD_PUBLISH env var and conditional — publish always runs on
  workflow_dispatch.
- "Publication DEFERRED" summary step.
- Tag-listener preflight (was looking for the wrong thing).
- No-PAT fallback notice (no relay to fall back from).
- "Tag current version (skip mode)" step (no relay to trigger).
- release-chain.md (11-layer taxonomy of a now-defunct architecture,
  stubbed with a redirect to docs/rubygems-release.md).

What's kept:

- preflight job (bundle resolve, gem build, credentials check, OIDC
  Trusted Publisher exchange — useful fail-fast checks).
- gem-idempotent-push-guard-action (handles duplicate publish).
- Post-publish verification (polls rubygems.org).
- release-passed dispatch (downstream listeners like notify.yml).
- repository_dispatch: do-release listener (backward compat with
  consumer rake.yml files that still dispatch it; idempotent guard
  handles the duplicate).

What's deprecated (kept as no-op for backward compat):

- `gated` input — accepted but ignored. Consumer repos that pass it
  see no error; publish happens immediately.

Same treatment for monorepo-rubygems-release.yml.

README.md and docs/rubygems-release.md updated to describe the
single-phase model. Docs now explicitly state the consumer model:
metanorma/ci is shared infrastructure for any gem, not just
cimas-managed repos. Defaults must work for both populations.

Supersedes: #333 (reverted in #368), #293.
Blocks: #355 (depends on SHOULD_PUBLISH; needs rework to a one-line
gh release create call, no variant templates, no cimas.yml churn).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

rubygems-release: guarantee GitHub release notes for every released tag (auto-generate, with manual opt-out)

2 participants