Skip to content

ci(deploy): rake release[X.Y.Z] + OIDC trusted-publishing release workflow - #42

Merged
mhenrixon merged 1 commit into
mainfrom
feature/v1-release-tooling
Jul 3, 2026
Merged

ci(deploy): rake release[X.Y.Z] + OIDC trusted-publishing release workflow#42
mhenrixon merged 1 commit into
mainfrom
feature/v1-release-tooling

Conversation

@mhenrixon

Copy link
Copy Markdown
Collaborator

What & why

docs-kit is ready for a v1.0.0 cut. This wires up releases the exact same way as the sibling gems — daisyui, phlex-reactive, and pgbus — so the whole family releases identically: a version-bumping rake release[X.Y.Z] task plus an OIDC trusted-publishing GitHub Actions workflow.

Refs #8.

Changes

rake release[X.Y.Z] (Rakefile) — ported from the sibling gems, adapted for docs-kit:

  • Runs only on main with a clean working tree.
  • Bumps lib/docs_kit/version.rb, updates Gemfile.lock and docs/Gemfile.lock (the dogfood site), verifies gem build --strict, commits, pushes, and creates the GitHub Release with generated notes.
  • rake release[X.Y.Z,force] deletes + re-cuts an existing tag/release; rake release[pre] flags a pre-release.
  • Also a rake build gem content-verify task.
  • Drops require "bundler/gem_tasks" (its argless release task collides with the parameterized one); spec / rubocop / default remain explicit.

.github/workflows/release.yml — fires on release: published, mirroring daisyui's hardened variant:

Job Does
test Full bundle exec rake on Ruby 3.2 / 3.3 / 3.4
build Verifies tag == gem version, builds --strict, content-checks the gem (no .gemspec/.git*/spec dirs), generates SHA256/512
publish-rubygems OIDC trusted publishing via rubygems/configure-rubygems-credentials (SHA-pinned), Sigstore-signs, gem push --attestation; idempotent (skips if the version is already on RubyGems)
upload-release-assets Attaches the gem + checksums + Sigstore bundle to the GitHub Release

No API token is stored anywhere — id-token: write + the rubygems environment do it over OIDC.

Docs: a README "Releasing (maintainers)" section with the task usage and the one-time setup (RubyGems pending trusted publisher + the GitHub rubygems environment) — without which the first release fails. CHANGELOG Unreleased entry. .rubocop.yml excludes the Rakefile from Metrics/BlockLength (the release task is a long sequential script by design, same as the sibling gems).

⚠️ One-time manual setup before the first release

Trusted publishing requires two things wired once (documented in the README):

  1. RubyGems pending trusted publisher — profile → Trusted Publishers → Create a pending publisher (gem docs-kit, repo mhenrixon/docs-kit, workflow release.yml, environment rubygems). "Pending" works for a gem not yet pushed, so 0.1.0 never needs a manual gem push — the very first rake release[1.0.0] publishes over OIDC.
  2. GitHub rubygems environment — Settings → Environments → new environment named rubygems.

Verification

  • rake -T lists release[version,force] + build.
  • rake build packs cleanly (--strict); the gem passes the workflow's unwanted-files guard (no .gemspec/.git*/spec dirs; 79 files).
  • release.yml is valid YAML — 4 jobs, environment: rubygems, id-token: write, trigger release: published.
  • bundle exec rubocop — clean (103 files).
  • bundle exec rspec505 examples, 0 failures (dropping bundler/gem_tasks broke nothing).

Test plan

The workflow can't be dry-run without an actual release. After merge + the one-time setup above, rake release[1.0.0] cuts v1 and the workflow publishes it. rake release[1.0.0,force] is the recovery path if anything needs re-cutting.

https://claude.ai/code/session_01FPQb6z3YwcKRMbvoJhdxnX

…kflow

Sets up releases the same way as the sibling gems (daisyui, phlex-reactive,
pgbus), ahead of the v1 cut.

## Summary
- Rakefile: a `rake release[X.Y.Z]` task (main-only, clean-tree guarded) that
  bumps lib/docs_kit/version.rb, updates Gemfile.lock + docs/Gemfile.lock,
  verifies `gem build --strict`, commits, pushes, and creates the GitHub
  Release. Supports `pre` (pre-release) and `force` (re-cut a tag). Plus a
  `rake build` gem content-verify task. Drops `bundler/gem_tasks` (its own
  arg-less `release` task would collide); spec/rubocop/default stay explicit.
- .github/workflows/release.yml: on `release: published`, test (3.2/3.3/3.4) →
  build + content-check → publish-rubygems → upload-release-assets. Publishes
  over OIDC trusted publishing (rubygems/configure-rubygems-credentials, SHA
  pinned), Sigstore-signs the gem, and is idempotent (skips a re-push of an
  already-published version). `rubygems` environment + id-token: write.
- README "Releasing (maintainers)": the task usage + the ONE-TIME setup
  (RubyGems pending trusted publisher + the `rubygems` GitHub environment)
  without which the first release fails.
- .rubocop.yml: exclude Rakefile from Metrics/BlockLength (the release task is
  a long sequential script by design, matching the sibling gems).
- CHANGELOG: Unreleased entry.

## Verification
- [x] rake -T lists release[version,force] + build
- [x] rake build packs cleanly (--strict); gem contents pass the workflow's
      unwanted-files guard (no .gemspec/.git*/spec dirs; 79 files)
- [x] release.yml is valid YAML; 4 jobs; environment: rubygems; id-token: write
- [x] bundle exec rubocop — clean (103 files)
- [x] bundle exec rspec — 505 examples, 0 failures

Refs #8

Claude-Session: https://claude.ai/code/session_01FPQb6z3YwcKRMbvoJhdxnX
@mhenrixon mhenrixon self-assigned this Jul 3, 2026
@mhenrixon mhenrixon added the enhancement New feature or request label Jul 3, 2026
@mhenrixon
mhenrixon merged commit df9705b into main Jul 3, 2026
4 checks passed
@mhenrixon
mhenrixon deleted the feature/v1-release-tooling branch July 4, 2026 14:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant