Skip to content

Add workflow to prepare a release PR#1816

Open
neilvcarvalho wants to merge 3 commits intomainfrom
nc/automate-release-preparation
Open

Add workflow to prepare a release PR#1816
neilvcarvalho wants to merge 3 commits intomainfrom
nc/automate-release-preparation

Conversation

@neilvcarvalho
Copy link
Copy Markdown
Member

Summary

Adds a manually-triggered workflow that automates the mechanical parts of preparing a release:

  • A maintainer picks patch, minor, or major from a dropdown in the GitHub Actions UI
  • Uses gem-release's gem bump to update lib/factory_bot/version.rb
  • Collects all merged PRs since the last release tag via gh pr list and formats them as changelog entries
  • If an ## Unreleased section exists in NEWS.md, its content is merged into the new version section (duplicates with PR titles are acceptable)
  • Commits both changes to a release/vX.Y.Z branch and opens a draft PR named "Release vX.Y.Z" for review before anything is published

neilvcarvalho and others added 2 commits April 17, 2026 17:16
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@neilvcarvalho neilvcarvalho requested a review from Copilot April 17, 2026 20:32
@neilvcarvalho neilvcarvalho marked this pull request as ready for review April 17, 2026 20:32
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a manually-triggered GitHub Actions workflow and supporting Rake task to automate preparing a draft release PR (version bump + changelog update).

Changes:

  • Added release:update_changelog[VERSION] Rake task to update NEWS.md using merged PRs since the last tag (and merge/remove ## Unreleased).
  • Updated Rakefile to load .rake files from tasks/.
  • Added prepare-release.yml workflow to bump the gem version, update NEWS.md, push a release branch, and open a draft PR.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.

File Description
tasks/release.rake Implements changelog generation and NEWS.md section management.
Rakefile Loads tasks from tasks/*.rake so the new release task is available.
.github/workflows/prepare-release.yml Adds a workflow to run the version bump + changelog update and open a draft release PR.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread tasks/release.rake
Comment on lines +25 to +27
if news =~ /^## Unreleased\n(.*?)(?=^## )/m
unreleased = $1.strip
news = news.sub(/^## Unreleased\n.*?(?=^## )/m, "")
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ## Unreleased extraction/removal regex only matches when another ## ... header follows. If ## Unreleased is the last section in NEWS.md, it won’t be merged/removed. Consider extending the regex to also match end-of-file so this works regardless of section ordering.

Suggested change
if news =~ /^## Unreleased\n(.*?)(?=^## )/m
unreleased = $1.strip
news = news.sub(/^## Unreleased\n.*?(?=^## )/m, "")
if news =~ /^## Unreleased\n(.*?)(?=^## |\z)/m
unreleased = $1.strip
news = news.sub(/^## Unreleased\n.*?(?=^## |\z)/m, "")

Copilot uses AI. Check for mistakes.
Comment thread tasks/release.rake
body = [unreleased, pr_entries].reject(&:empty?).join("\n")
new_section = "## #{version} (#{today})\n\n#{body}\n"

news.sub!(/^(# News\n+)/, "\\1#{new_section}\n")
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sub! will return nil if the # News header pattern isn’t found, but the task will still write the file and print success. Consider checking the return value and aborting with a helpful error when the expected header isn’t present, to avoid silently producing no changelog update.

Suggested change
news.sub!(/^(# News\n+)/, "\\1#{new_section}\n")
unless news.sub!(/^(# News\n+)/, "\\1#{new_section}\n")
abort 'Expected NEWS.md to contain a "# News" header so the changelog entry could be inserted.'
end

Copilot uses AI. Check for mistakes.
Comment on lines +39 to +42
- name: Update NEWS.md
env:
GH_TOKEN: ${{ github.token }}
run: bundle exec rake "release:update_changelog[${{ steps.version.outputs.new }}]"
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This workflow runs bundle exec rake ... but never installs the bundle. Unlike .github/workflows/build.yml, there’s no bundle install (or bundler-cache: true), so this step will fail on a fresh runner. Add a dependency install step before invoking bundle exec.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot apply changes based on this feedback

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a bundle install step between ruby/setup-ruby and the bundle exec rake call, matching the pattern used in build.yml. Fixed in 5d61d82.

GH_TOKEN: ${{ github.token }}
NEW_VERSION: ${{ steps.version.outputs.new }}
run: |
BRANCH="release/v$NEW_VERSION"
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Branch naming here uses release/vX.Y.Z, but the project’s documented convention in RELEASING.md is release-x.x.x. To avoid confusion/automation mismatches, consider aligning the workflow’s branch name with the documented convention (or update the docs as part of this PR).

Suggested change
BRANCH="release/v$NEW_VERSION"
BRANCH="release-$NEW_VERSION"

Copilot uses AI. Check for mistakes.
Comment thread tasks/release.rake
Comment on lines +5 to +12
desc "Update NEWS.md with merged PRs since the last release tag. Usage: rake release:update_changelog[VERSION]"
task :update_changelog, [:version] do |_, args|
version = args.fetch(:version) { abort "Usage: rake release:update_changelog[VERSION]" }

# Find the last release tag and when it was made
last_tag = `git tag --sort=-version:refname`.split.grep(/^v?[0-9]/).first
since_date = `git log -1 --format=%as #{last_tag}`.strip

Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

last_tag can be nil if the repo has no tags matching ^v?[0-9], which will cause since_date to be derived from HEAD (and can lead to an empty/incorrect changelog range). Consider explicitly aborting with a clear message when no release tag is found, or allow an explicit since/tag argument for the task.

Suggested change
desc "Update NEWS.md with merged PRs since the last release tag. Usage: rake release:update_changelog[VERSION]"
task :update_changelog, [:version] do |_, args|
version = args.fetch(:version) { abort "Usage: rake release:update_changelog[VERSION]" }
# Find the last release tag and when it was made
last_tag = `git tag --sort=-version:refname`.split.grep(/^v?[0-9]/).first
since_date = `git log -1 --format=%as #{last_tag}`.strip
desc "Update NEWS.md with merged PRs since the last release tag. Usage: rake release:update_changelog[VERSION[,TAG[,SINCE]]]"
task :update_changelog, [:version, :tag, :since] do |_, args|
version = args.fetch(:version) { abort "Usage: rake release:update_changelog[VERSION[,TAG[,SINCE]]]" }
# Determine the changelog start date from an explicit date, an explicit tag, or the last release tag
since_date =
if args[:since] && !args[:since].strip.empty?
args[:since].strip
else
last_tag = if args[:tag] && !args[:tag].strip.empty?
args[:tag].strip
else
`git tag --sort=-version:refname`.split.grep(/^v?[0-9]/).first
end
abort "No release tag found matching ^v?[0-9]. Provide TAG or SINCE explicitly: rake release:update_changelog[VERSION[,TAG[,SINCE]]]" unless last_tag
`git log -1 --format=%as #{last_tag}`.strip
end

Copilot uses AI. Check for mistakes.
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.

3 participants