Conversation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
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 updateNEWS.mdusing merged PRs since the last tag (and merge/remove## Unreleased). - Updated
Rakefileto load.rakefiles fromtasks/. - Added
prepare-release.ymlworkflow to bump the gem version, updateNEWS.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.
| if news =~ /^## Unreleased\n(.*?)(?=^## )/m | ||
| unreleased = $1.strip | ||
| news = news.sub(/^## Unreleased\n.*?(?=^## )/m, "") |
There was a problem hiding this comment.
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.
| 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, "") |
| body = [unreleased, pr_entries].reject(&:empty?).join("\n") | ||
| new_section = "## #{version} (#{today})\n\n#{body}\n" | ||
|
|
||
| news.sub!(/^(# News\n+)/, "\\1#{new_section}\n") |
There was a problem hiding this comment.
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.
| 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 |
| - name: Update NEWS.md | ||
| env: | ||
| GH_TOKEN: ${{ github.token }} | ||
| run: bundle exec rake "release:update_changelog[${{ steps.version.outputs.new }}]" |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
@copilot apply changes based on this feedback
There was a problem hiding this comment.
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" |
There was a problem hiding this comment.
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).
| BRANCH="release/v$NEW_VERSION" | |
| BRANCH="release-$NEW_VERSION" |
| 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 | ||
|
|
There was a problem hiding this comment.
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.
| 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 |
…rkflow Agent-Logs-Url: https://github.com/thoughtbot/factory_bot/sessions/51e4ccb7-1eef-4798-b80e-f87f1f5f7850 Co-authored-by: neilvcarvalho <761956+neilvcarvalho@users.noreply.github.com>
Summary
Adds a manually-triggered workflow that automates the mechanical parts of preparing a release:
patch,minor, ormajorfrom a dropdown in the GitHub Actions UIgem-release'sgem bumpto updatelib/factory_bot/version.rbgh pr listand formats them as changelog entries## Unreleasedsection exists inNEWS.md, its content is merged into the new version section (duplicates with PR titles are acceptable)release/vX.Y.Zbranch and opens a draft PR named "Release vX.Y.Z" for review before anything is published