From 5b450408968eac7d3b752ceb221f1c194f90d374 Mon Sep 17 00:00:00 2001 From: Karl Falconer Date: Wed, 26 Aug 2026 13:58:46 -0400 Subject: [PATCH] Cut releases from the GitHub Releases UI The Release workflow triggered on `push: tags` and created the GitHub release itself, so publishing v0.1.0 from the Releases UI failed: the gem pushed to RubyGems, then the run went red on `gh release create` with `HTTP 422 Release.tag_name already exists`. Trigger on `release: published` instead and drop the release-creation step, since the release already exists by the time the workflow fires. Read the tag from `github.event.release.tag_name` rather than `GITHUB_REF_NAME`, and check out that tag explicitly. The version-vs-tag guard stays, so a release tagged without the `v` prefix now fails the guard instead of silently not triggering anything. Drop `contents: write` from the publishing job. GitHub creates the tag before the workflow runs, so bundler's `release:source_control_push` (`tag_version { git_push } unless already_tagged?`) always takes the already-tagged branch and never pushes. Release notes now come from Generate release notes in the UI, so point each CHANGELOG.md heading at its GitHub release instead of feeding the notes from that file. The headings were already reference links with no definitions, so they rendered as literal brackets. Also correct the 0.1.0 date to the day it actually published. Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/release.yml | 46 ++++++++++++----------------------- CHANGELOG.md | 22 +++++++++++++++-- README.md | 36 ++++++++++++++------------- 3 files changed, 55 insertions(+), 49 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 53eb34a..8c71662 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,10 +1,11 @@ name: Release -# Cut a release by bumping lib/omniauth-shipbob/version.rb, committing, then: -# git tag -a v0.1.0 -m "v0.1.0" && git push origin master --tags +# Cut a release from the GitHub Releases UI: draft a release, set the tag to `vX.Y.Z` +# (matching lib/omniauth-shipbob/version.rb), and publish it. GitHub creates the tag, +# which fires this workflow. on: - push: - tags: ["v*"] + release: + types: [published] jobs: # Never publish a version that has not passed the matrix. @@ -26,11 +27,14 @@ jobs: permissions: id-token: write # mandatory for trusted publishing - contents: write # `rake release` pushes the tag; `gh` creates the release + # GitHub already created the release and its tag, so nothing here writes to + # the repo: `rake release` sees the tag and skips its own tag-and-push step. + contents: read steps: - uses: actions/checkout@v5 with: + ref: ${{ github.event.release.tag_name }} # rubygems/release-gem installs its own short-lived git credentials. persist-credentials: false @@ -40,38 +44,20 @@ jobs: bundler-cache: true # `rake release` builds whatever version.rb says, regardless of the tag. If the - # two disagree it would publish one version and tag another, so stop here first. - - name: Verify the tag matches the gem version + # two disagree it would publish one version under another version's release, so + # stop here first. + - name: Verify the release tag matches the gem version + env: + TAG_NAME: ${{ github.event.release.tag_name }} run: | gem_version="$(ruby -r./lib/omniauth-shipbob/version -e 'print Omniauth::Shipbob::VERSION')" - tag_version="${GITHUB_REF_NAME#v}" + tag_version="${TAG_NAME#v}" if [ "$gem_version" != "$tag_version" ]; then - echo "::error::Tag ${GITHUB_REF_NAME} does not match lib/omniauth-shipbob/version.rb (${gem_version})." + echo "::error::Release tag ${TAG_NAME} does not match lib/omniauth-shipbob/version.rb (${gem_version})." exit 1 fi echo "Releasing omniauth-shipbob ${gem_version}" # Builds the gem and runs `gem push` against the gemspec's allowed_push_host. - # The tag already exists, so bundler skips its own tag-and-push step. - name: Push to RubyGems.org uses: rubygems/release-gem@v1 - - - name: Create the GitHub release - env: - GH_TOKEN: ${{ github.token }} - run: | - notes="$(awk -v v="${GITHUB_REF_NAME#v}" ' - $0 ~ "^## \\[" v "\\]" { flag = 1; next } - flag && /^## \[/ { exit } - flag { print } - ' CHANGELOG.md)" - - if [ -n "$(printf '%s' "$notes" | tr -d '[:space:]')" ]; then - printf '%s\n' "$notes" > release-notes.md - gh release create "$GITHUB_REF_NAME" --verify-tag \ - --title "$GITHUB_REF_NAME" --notes-file release-notes.md - else - echo "No CHANGELOG.md section for ${GITHUB_REF_NAME}; generating notes from commits." - gh release create "$GITHUB_REF_NAME" --verify-tag \ - --title "$GITHUB_REF_NAME" --generate-notes - fi diff --git a/CHANGELOG.md b/CHANGELOG.md index 659215e..a94c360 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,21 @@ # Changelog -All notable changes to this project are documented in this file. +All notable changes to this project are documented in this file. Each version heading +links to its [GitHub release](https://github.com/dropstream/omniauth-shipbob/releases), +where the notes are generated from the merged pull requests. -## [0.1.0] - 2026-08-19 +## [Unreleased] + +### Changed + +- Releases are now cut by publishing a release from the GitHub Releases UI instead of by + pushing a tag from the command line. The `Release` workflow triggers on + `release: published` and no longer creates the GitHub release itself, which previously + failed with `Release.tag_name already exists` when the release came from the UI. + Release notes are now produced by **Generate release notes** in the UI rather than + extracted from this file; this file links to each release instead. + +## [0.1.0] - 2026-08-26 ### Changed @@ -46,3 +59,8 @@ All notable changes to this project are documented in this file. ## [0.0.2] - Initial published strategy. + +[Unreleased]: https://github.com/dropstream/omniauth-shipbob/compare/v0.1.0...master +[0.1.0]: https://github.com/dropstream/omniauth-shipbob/releases/tag/v0.1.0 +[0.0.3]: https://github.com/dropstream/omniauth-shipbob/releases/tag/v0.0.3 +[0.0.2]: https://github.com/dropstream/omniauth-shipbob/releases/tag/v0.0.2 diff --git a/README.md b/README.md index 46fdf9c..17c734e 100644 --- a/README.md +++ b/README.md @@ -82,30 +82,32 @@ To install this gem onto your local machine, run `bundle exec rake install`. ## Releasing -Releases are cut by pushing a tag; GitHub Actions builds and publishes the gem to -[rubygems.org](https://rubygems.org) via +Releases are cut from the [GitHub Releases UI](https://github.com/dropstream/omniauth-shipbob/releases/new); +GitHub Actions builds and publishes the gem to [rubygems.org](https://rubygems.org) via [RubyGems trusted publishing](https://guides.rubygems.org/trusted-publishing/), so no API key is stored in the repo and the gemspec can keep `rubygems_mfa_required`. 1. Bump `VERSION` in `lib/omniauth-shipbob/version.rb` and add a `CHANGELOG.md` section - for it (the release notes are taken from that section). -2. Commit both on `master`. -3. Tag and push: - - ```sh - git tag -a v0.1.0 -m "v0.1.0" - git push origin master --tags - ``` - -The `Release` workflow then runs the full test matrix, refuses to continue if the tag and -`version.rb` disagree, pushes the gem, and opens a GitHub release. + for it, along with a link definition for the new heading at the bottom of that file. + Commit both on `master`. +2. Draft a new release with the target set to `master` and the tag set to the version + prefixed with `v` — `v0.1.0`, not `0.1.0`. The prefix is stripped before comparing + against `version.rb`; the gem version itself carries no `v`. +3. Click **Generate release notes** — the preferred method — then publish. The generated + notes list the merged pull requests; `CHANGELOG.md` carries the curated prose and + links back to each release. + +Publishing creates the tag, which fires the `Release` workflow: it reruns the full test +matrix, refuses to continue if the tag and `version.rb` disagree, and pushes the gem. +Note that RubyGems versions are immutable — a bad release can be yanked, never replaced, +so the version bump has to be committed before the release is published. ### One-time RubyGems setup -Before the first automated release, register this repo as a trusted publisher: on -rubygems.org open the gem → **Trusted publishers** → **Create**, with owner -`dropstream`, repository `omniauth-shipbob`, workflow `release.yml`, and environment -`release`. +Already configured, and only needed again if the gem is renamed or moved: on rubygems.org +open the gem -> **Trusted publishers** -> **Create**, with owner `dropstream`, repository +`omniauth-shipbob`, workflow `release.yml`, and environment `release`. The repo also needs +an environment named `release`. ## Contributing