Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 123 additions & 0 deletions docs/RELEASE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
# Release Process

This document describes how to release a new version of the `cypress-on-rails` gem.

## Prerequisites

1. Install the `gem-release` gem globally:
```bash
gem install gem-release
```
Comment on lines +7 to +10
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Verify gem-release installation method.

The documentation suggests installing gem-release globally, but the task description at line 7 of lib/tasks/release.rake states it "is installed via bundle install". This inconsistency could confuse users.

Consider updating the documentation to clarify whether the gem should be installed globally or via Bundler, or document both approaches.

-1. Install the `gem-release` gem globally:
+1. Install the `gem-release` gem (either globally or via your Gemfile):
    ```bash
+   # Option 1: Global installation
    gem install gem-release
+   
+   # Option 2: Add to your Gemfile and run bundle install
+   # gem 'gem-release'
    ```
🤖 Prompt for AI Agents
In docs/RELEASE.md around lines 7 to 10, the instructions conflict with
lib/tasks/release.rake which says gem-release is installed via bundle; update
the docs to be explicit about both supported installation methods (global vs
Bundler) and show the recommended approach: either a single-line note to run
`gem install gem-release` for global use or, preferably, add gem 'gem-release'
to the project's Gemfile and run `bundle install`; ensure the wording clarifies
which method the release task expects (Bundler by default) and give both options
so readers are not confused.


2. Ensure you have write access to the rubygems.org package

3. Set up two-factor authentication (2FA) for RubyGems and have your OTP generator ready

## Release Steps

### 1. Prepare for Release

Ensure your working directory is clean:
```bash
git status
```

If you have uncommitted changes, commit or stash them first.

### 2. Pull Latest Changes

```bash
git pull --rebase
```

### 3. Run the Release Task

To release a specific version:
```bash
rake release[1.19.0]
```

To automatically bump the patch version:
```bash
rake release
```

To perform a dry run (without actually publishing):
```bash
rake release[1.19.0,true]
```

### 4. Enter Your OTP

When prompted, enter your one-time password (OTP) from your authenticator app for RubyGems.

If you get an error during gem publishing, you can run `gem release` manually to retry.

### 5. Update the CHANGELOG

After successfully publishing the gem, update the CHANGELOG:

```bash
bundle exec rake update_changelog
# This will:
# - Add a new version header with the release date
# - Add version comparison links
# - Prompt you to move content from [Unreleased] to the new version

# Edit CHANGELOG.md to move unreleased changes to the new version section
git commit -a -m 'Update CHANGELOG.md'
git push
```

## Version Numbering

Follow [Semantic Versioning](https://semver.org/):

- **Major version** (X.0.0): Breaking changes
- **Minor version** (0.X.0): New features, backwards compatible
- **Patch version** (0.0.X): Bug fixes, backwards compatible
- **Pre-release versions**: Use dot notation, not dashes (e.g., `2.0.0.beta.1`, not `2.0.0-beta.1`)

## What the Release Task Does

The release task automates the following steps:

1. Checks for uncommitted changes (will abort if found)
2. Pulls the latest changes from the repository
3. Bumps the version number in `lib/cypress_on_rails/version.rb`
4. Creates a git commit with the version bump
5. Creates a git tag for the new version
6. Pushes the commit and tag to GitHub
7. Builds the gem
8. Publishes the gem to RubyGems

## Troubleshooting

### Authentication Error

If you get an authentication error with RubyGems:
1. Verify your OTP is correct and current
2. Ensure your RubyGems API key is valid
3. Run `gem release` manually to retry

### Version Already Exists

If the version already exists on RubyGems:
1. Bump to a higher version number
2. Or fix the version in `lib/cypress_on_rails/version.rb` and try again

### Uncommitted Changes Error

If you have uncommitted changes:
1. Review your changes with `git status`
2. Commit them with `git commit -am "Your message"`
3. Or stash them with `git stash`
4. Then retry the release

## Post-Release

After releasing:

1. Announce the release on relevant channels (Slack, forum, etc.)
2. Update any documentation that references version numbers
3. Consider creating a GitHub release with release notes
50 changes: 50 additions & 0 deletions lib/tasks/release.rake
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# frozen_string_literal: true

desc("Releases the gem using the given version.

IMPORTANT: the gem version must be in valid rubygem format (no dashes).

This task depends on the gem-release ruby gem which is installed via `bundle install`

1st argument: The new version in rubygem format (no dashes). Pass no argument to
automatically perform a patch version bump.
2nd argument: Perform a dry run by passing 'true' as a second argument.

Example: `rake release[1.19.0,false]`")
task :release, %i[gem_version dry_run] do |_t, args|
def sh_in_dir(dir, command)
puts "Running in #{dir}: #{command}"
system("cd #{dir} && #{command}") || raise("Command failed: #{command}")
end

def gem_root
File.expand_path('..', __dir__)
end

# Check if there are uncommitted changes
unless `git status --porcelain`.strip.empty?
raise "You have uncommitted changes. Please commit or stash them before releasing."
end

args_hash = args.to_hash
is_dry_run = args_hash[:dry_run] == 'true'
gem_version = args_hash.fetch(:gem_version, "")

# See https://github.com/svenfuchs/gem-release
sh_in_dir(gem_root, "git pull --rebase")
sh_in_dir(gem_root, "gem bump --no-commit #{%(--version #{gem_version}) unless gem_version.strip.empty?}")

# Release the new gem version
puts "Carefully add your OTP for Rubygems. If you get an error, run 'gem release' again."
sh_in_dir(gem_root, "gem release") unless is_dry_run

msg = <<~MSG
Once you have successfully published, update CHANGELOG.md:

bundle exec rake update_changelog
# Edit CHANGELOG.md to move unreleased changes to the new version section
git commit -a -m 'Update CHANGELOG.md'
git push
MSG
puts msg
end
63 changes: 63 additions & 0 deletions lib/tasks/update_changelog.rake
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# frozen_string_literal: true

require "English"

desc "Updates CHANGELOG.md inserting headers for the new version.

Argument: Git tag. Defaults to the latest tag."

task :update_changelog, %i[tag] do |_, args|
tag = args[:tag] || `git describe --tags --abbrev=0`.strip

# Remove 'v' prefix if present (e.g., v1.18.0 -> 1.18.0)
version = tag.start_with?('v') ? tag[1..-1] : tag
anchor = "[#{version}]"

changelog = File.read("CHANGELOG.md")

if changelog.include?(anchor)
puts "Tag #{version} is already documented in CHANGELOG.md, update manually if needed"
next
end

tag_date_output = `git show -s --format=%cs #{tag} 2>&1`
if $CHILD_STATUS.success?
tag_date = tag_date_output.split("\n").last.strip
else
abort("Failed to find tag #{tag}")
end

# After "## [Unreleased]", insert new version header
unreleased_section = "## [Unreleased]"
new_version_header = "\n\n## #{anchor} - #{tag_date}"

if changelog.include?(unreleased_section)
changelog.sub!(unreleased_section, "#{unreleased_section}#{new_version_header}")
else
abort("Could not find '## [Unreleased]' section in CHANGELOG.md")
end

# Find and update version comparison links at the bottom
# Pattern: [1.18.0]: https://github.com/shakacode/cypress-playwright-on-rails/compare/v1.17.0...v1.18.0
compare_link_prefix = "https://github.com/shakacode/cypress-playwright-on-rails/compare"

# Find the last version link to determine the previous version
last_version_match = changelog.match(/\[(\d+\.\d+\.\d+(?:\.\w+)?)\]:.*?compare\/v(\d+\.\d+\.\d+(?:\.\w+)?)\.\.\.v(\d+\.\d+\.\d+(?:\.\w+)?)/)

if last_version_match
last_version = last_version_match[1]
# Add new version link at the top of the version list
new_link = "#{anchor}: #{compare_link_prefix}/v#{last_version}...v#{version}"
# Insert after the "<!-- Version diff reference list -->" comment
changelog.sub!("<!-- Version diff reference list -->", "<!-- Version diff reference list -->\n#{new_link}")
else
puts "Warning: Could not find version comparison links. You may need to add the link manually."
end

File.write("CHANGELOG.md", changelog)
puts "Updated CHANGELOG.md with an entry for #{version}"
puts "\nNext steps:"
puts "1. Edit CHANGELOG.md to add release notes under the [#{version}] section"
puts "2. Move content from [Unreleased] to [#{version}] if applicable"
puts "3. Review and commit the changes"
end