internal/contributor-info/releasing.md
We're releasing this as a unified release with 6 packages total. We keep the version numbers in sync across all packages using unified versioning.
See Contributing
Always update CHANGELOG.md before running the release task. The release task reads the version from CHANGELOG.md and automatically creates a GitHub release from the changelog section.
main branch/update-changelog release (or rc, beta, or an explicit version like 16.5.0.rc.10) to:
### [16.5.0] - 2026-03-08)rc/beta: collapse prior prerelease sections and deduplicate entriesIf you forget this step, the release task will print a warning and the GitHub release will need to be created manually afterward using sync_github_release.
rake release automatically creates a GitHub release if a changelog section exists -- no separate sync_github_release step neededThe simplest way to release is with no arguments -- the task reads the version from CHANGELOG.md:
# Recommended: reads version from CHANGELOG.md (requires step 1)
bundle exec rake release
# For a specific version (overrides CHANGELOG.md detection)
bundle exec rake "release[16.2.0]"
# For a pre-release version (note: use period, not dash)
bundle exec rake "release[16.2.0.beta.1]" # Creates npm package 16.2.0-beta.1
# For a release candidate
bundle exec rake "release[16.5.0.rc.0]"
# Dry run to test without publishing
bundle exec rake "release[16.2.0,true]"
# Override version policy checks (monotonic + changelog/bump consistency)
RELEASE_VERSION_POLICY_OVERRIDE=true bundle exec rake "release[16.2.0]"
bundle exec rake "release[16.2.0,false,true]"
When called with no arguments, rake release:
### [16.5.0])Dry runs use a temporary git worktree so version bumps and installs do not modify your current checkout.
rake release validates release-version policy before publishing:
### [X.Y.Z...]; not Unreleased), it maps to expected bump type:
Use override only when needed:
RELEASE_VERSION_POLICY_OVERRIDE=truebundle exec rake "release[..., ..., true]")Full argument list:
bundle exec rake "release[version,dry_run,override_version_policy]"
version (optional): Version bump type or explicit version
patch, minor, major16.2.016.2.0.beta.1 (rubygem format with dots, converted to 16.2.0-beta.1 for NPM)dry_run (optional): true to preview changes without releasing (default: false)
override_version_policy (optional): true to override version policy checks (default: false)
Environment variables:
VERBOSE=1 # Enable verbose logging (shows all output)
NPM_OTP=<code> # Provide NPM one-time password (reused for all NPM publishes)
RUBYGEMS_OTP=<code> # Provide RubyGems one-time password (reused for both gems)
RELEASE_VERSION_POLICY_OVERRIDE=true # Override release version policy checks
GEM_RELEASE_MAX_RETRIES=<n> # Override max retry attempts (default: 3)
Examples:
bundle exec rake release # Use CHANGELOG.md version or patch bump
bundle exec rake "release[patch]" # Bump patch version (16.1.1 → 16.1.2)
bundle exec rake "release[minor]" # Bump minor version (16.1.1 → 16.2.0)
bundle exec rake "release[major]" # Bump major version (16.1.1 → 17.0.0)
bundle exec rake "release[16.2.0]" # Set explicit version
bundle exec rake "release[16.2.0.beta.1]" # Set pre-release version (→ 16.2.0-beta.1 for NPM)
bundle exec rake "release[patch,true]" # Dry run
VERBOSE=1 bundle exec rake "release[patch]" # Release with verbose logging
NPM_OTP=123456 RUBYGEMS_OTP=789012 bundle exec rake "release[patch]" # Skip OTP prompts
The rake release task automatically:
npm login if needed)react_on_rails/lib/react_on_rails/version.rb (Ruby gem version)package.json files (npm package versions - converted from Ruby format)react-on-railsreact-on-rails-proreact-on-rails-pro-node-renderercreate-react-on-rails-appreact_on_railsreact_on_rails_proThe release task publishes 6 packages with unified versioning:
PUBLIC (npmjs.org + rubygems.org):
The task updates versions in all the following files:
Core package:
react_on_rails/lib/react_on_rails/version.rb (source of truth for all packages)package.json (root workspace)packages/react-on-rails/package.jsonGemfile.lock (root)react_on_rails/spec/dummy/Gemfile.lockPro package:
react_on_rails_pro/lib/react_on_rails_pro/version.rb (VERSION only, not PROTOCOL_VERSION)packages/react-on-rails-pro/package.json (+ dependency version)packages/react-on-rails-pro-node-renderer/package.jsonpackages/create-react-on-rails-app/package.jsonreact_on_rails_pro/Gemfile.lockreact_on_rails_pro/spec/dummy/Gemfile.lockNote:
react_on_rails_pro.gemspec dynamically references ReactOnRails::VERSIONreact-on-rails-pro NPM dependency is pinned to exact version (e.g., "react-on-rails": "16.2.0")Important: Use Ruby gem version format (no dashes) when passing versions to the rake task:
16.1.0, 16.2.0.beta.1, 16.0.0.rc.216.1.0-beta.1, 16.0.0-rc.2The task automatically converts Ruby gem format to npm semver format:
16.2.0.beta.1 -> npm: 16.2.0-beta.116.0.0.rc.2 -> npm: 16.0.0-rc.2CHANGELOG.md headers use RubyGems dot format (without v prefix):
### [16.5.0.rc.1] -- correct (matches gem version format)CHANGELOG.md compare links at the bottom of the file MUST use the v prefix to match git tags:
[16.5.0.rc.1]: https://github.com/shakacode/react_on_rails/compare/v16.4.0...v16.5.0.rc.1 -- correctrake release with no version, confirm the version detected from CHANGELOG.md (or the computed patch version)Verify the release on:
If the changelog was updated before release (recommended), verify the GitHub release was auto-created with the correct notes.
If the changelog was NOT updated before release, update it now:
Option A - Use Claude Code (recommended):
Run /update-changelog 16.5.0 (using the already-released version) to analyze commits, write entries, and automatically open a PR. After the PR merges, pull the updated changelog and sync the GitHub release:
git pull --rebase
bundle exec rake "sync_github_release[16.5.0]"
Option B - Manual (headers only, you must write entries):
bundle exec rake "update_changelog[16.5.0]"
# Write entries manually, then:
git commit -a -m 'Update CHANGELOG.md'
git push
bundle exec rake "sync_github_release[16.5.0]"
If the automatic GitHub release creation was skipped (e.g., CHANGELOG.md section was missing during release), you can create it manually after updating the changelog:
CHANGELOG.md with the published version sectionCHANGELOG.md# Stable
bundle exec rake "sync_github_release[16.5.0]"
# Prerelease
bundle exec rake "sync_github_release[16.5.0.rc.1]"
# Dry run
bundle exec rake "sync_github_release[16.5.0,true]"
sync_github_release reads release notes from the matching CHANGELOG.md section and creates/updates the GitHub release for the corresponding tag.
Before running the release command, verify:
GitHub CLI: Run gh auth login and ensure your account/token has write access to the repository (required for automatic GitHub release creation)
NPM authentication: Run npm whoami to confirm you're logged in
npm login for youRubyGems authentication: Ensure you have valid credentials for gem push
No uncommitted changes: Run git status to verify clean working tree
You'll need to enter OTP tokens when prompted:
react-on-rails to NPM (reused for subsequent NPM packages if valid)react_on_rails to RubyGems (reused for react_on_rails_pro if valid)You must be logged in and have publish permissions:
For public packages (npmjs.org):
npm login
For public gem (rubygems.org):
gem pushThe script automatically detects and switches Ruby versions when needed:
RUBY_VERSION_MANAGER environment variable (default: rvm)This task depends on the gem-release Ruby gem, which is installed via bundle install.
Before releasing to production, always preview with a dry run:
bundle exec rake "release[16.5.0,true]"
This uses a temporary git worktree to show exactly what would be updated without making any changes.
Always test with a dry run before actually releasing:
bundle exec rake "release[16.2.0,true]"
This shows you exactly what would be updated without making any changes.
If you see errors like "Access token expired" or "E404 Not Found" during NPM publish:
npm login to refresh your credentialsThe release script now checks NPM authentication at the start and will automatically run npm login if needed, so this issue will be caught and handled before any changes are made.
If the release fails partway through (e.g., during NPM publish):
Check what was published:
npm view [email protected]gem list react_on_rails -r -aIf the git tag was created but packages weren't published:
git tag -d vX.Y.Z && git push origin :vX.Y.Zgit reset --hard HEAD~1 && git push -fbundle exec rake "release[X.Y.Z]"If GitHub release creation fails after successful publishing:
gh auth login) or permissionsCHANGELOG.md has matching header ### [X.Y.Z]bundle exec rake "sync_github_release[X.Y.Z]"If some packages were published but not others:
cd packages/react-on-rails && pnpm version X.Y.Z && pnpm publish
cd ../react-on-rails-pro && pnpm version X.Y.Z && pnpm publish
gem release
pnpm publish -r will publish all packages where current version isn't published yet.Running bundle exec rake "release[X.Y.Z]" will create a commit that looks like this:
commit abc123...
Author: Your Name <[email protected]>
Date: Mon Jan 1 12:00:00 2024 -0500
Bump version to 16.2.0
diff --git a/react_on_rails/lib/react_on_rails/version.rb b/react_on_rails/lib/react_on_rails/version.rb
index 1234567..abcdefg 100644
--- a/react_on_rails/lib/react_on_rails/version.rb
+++ b/react_on_rails/lib/react_on_rails/version.rb
@@ -1,3 +1,3 @@
module ReactOnRails
- VERSION = "16.1.1"
+ VERSION = "16.2.0"
end
diff --git a/package.json b/package.json
index 2345678..bcdefgh 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "react-on-rails-workspace",
- "version": "16.1.1",
+ "version": "16.2.0",
...
}