Skip to content

Commit c6eaca2

Browse files
authored
Merge pull request #3058 from ruby/claude/release-doc-new-minor
Update the release docs, and remove the release path they replaced
2 parents ba38b2a + a8913a8 commit c6eaca2

4 files changed

Lines changed: 107 additions & 76 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ Here is a list of some places you can talk with active maintainers.
196196

197197
After checking out the repo, run `bin/setup` to install dependencies. Then, run `bundle exec rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
198198

199-
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
199+
To install this gem onto your local machine, run `bundle exec rake install`. Releases are cut by the `Release gems` workflow rather than from a working copy -- see [docs/release.md](docs/release.md).
200200

201201
### C Code Formatting
202202

Rakefile

Lines changed: 0 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -438,73 +438,6 @@ task :test_generate_stdlib do
438438
sh "ruby -c /tmp/Thread_Mutex_test.rb"
439439
end
440440

441-
Rake::Task[:release].enhance do
442-
Rake::Task[:"release:note"].invoke
443-
end
444-
445-
namespace :release do
446-
desc "Explain the post-release steps automatically"
447-
task :note do
448-
version = Gem::Version.new(RBS::VERSION)
449-
major, minor, patch, *_ = RBS::VERSION.split(".")
450-
major = major.to_i
451-
minor = minor.to_i
452-
patch = patch.to_i
453-
454-
puts "🎉🎉🎉🎉 Congratulations for **#{version}** release! 🎉🎉🎉🎉"
455-
puts
456-
puts "There are a few things left to complete the release. 💪"
457-
puts
458-
459-
if patch == 0 || version.prerelease?
460-
puts "* [ ] Update release note: https://github.com/ruby/rbs/wiki/Release-Note-#{major}.#{minor}"
461-
end
462-
463-
if patch == 0 && !version.prerelease?
464-
puts "* [ ] Delete `RBS XYZ is the latest version of...` from release note: https://github.com/ruby/rbs/wiki/Release-Note-#{major}.#{minor}"
465-
end
466-
467-
puts "* [ ] Publish a release at GitHub"
468-
puts "* [ ] Make some announcements on Twitter/Mustdon/Slack/???"
469-
470-
puts
471-
puts
472-
473-
puts "✏️ Making a draft release on GitHub..."
474-
475-
content = File.read(File.join(__dir__, "CHANGELOG.md"))
476-
changelog = content.scan(/^## \d.*?(?=^## \d)/m)[0]
477-
changelog = changelog.sub(/^.*\n^.*\n/, "").rstrip
478-
479-
notes = <<NOTES
480-
[Release note](https://github.com/ruby/rbs/wiki/Release-Note-#{major}.#{minor})
481-
482-
#{changelog}
483-
NOTES
484-
485-
command = [
486-
"gh",
487-
"release",
488-
"create",
489-
"--draft",
490-
"v#{RBS::VERSION}",
491-
"--title=#{RBS::VERSION}",
492-
"--notes=#{notes}"
493-
]
494-
495-
if version.prerelease?
496-
command << "--prerelease"
497-
end
498-
499-
require "open3"
500-
output, status = Open3.capture2(*command)
501-
if status.success?
502-
puts " >> Done! Open #{output.chomp} and publish the release!"
503-
end
504-
end
505-
end
506-
507-
508441
# Pull requests with one of these labels are omitted from the changelog.
509442
CHANGELOG_SKIP_LABELS = ["skip-changelog"]
510443

docs/release.md

Lines changed: 73 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,14 @@ is what lets you dispatch the workflow.
3636

3737
## Steps
3838

39+
The release pull request in step 1 is merged by a person who has reviewed it. Its merge commit is
40+
what step 2 dispatches, tags, and pushes to RubyGems, and none of that can be taken back — so
41+
prepare that pull request and stop there, rather than merging it and carrying on to step 2.
42+
43+
The bump that starts a new minor is the only other pull request that sets `RBS::VERSION`. It
44+
publishes nothing and another bump undoes it, so one opened on an explicit request can go through
45+
on its own.
46+
3947
### 1. Prepare the release
4048

4149
Open a pull request that carries everything the release needs:
@@ -142,13 +150,67 @@ Checking the `dry_run` box runs everything up to the artifact and stops — no t
142150
no release — which is how the build is exercised without releasing. `version` still has to match
143151
the commit, so a dry run is also how a release is rehearsed before it is cut.
144152

145-
### 3. Start the next development cycle
153+
## The version on `master`
146154

147-
Open another pull request setting `RBS::VERSION` to the next prerelease (`4.1.1``4.1.2.pre`),
148-
with `Gemfile.lock` regenerated, labeled `skip-changelog` like the release pull request itself.
149-
Without it the version on `master` keeps claiming to be the released version for the whole
150-
development period, and `rake gem:changelog` reads that version to decide where the next changelog
151-
starts.
155+
`RBS::VERSION` on `master` is read one of two ways, told apart by how the version ends:
156+
157+
| On `master` | Means |
158+
| --- | --- |
159+
| `X.Y.0.dev` — a bare `.dev` | `X.Y.0` is being developed |
160+
| A complete version — `X.Y.Z`, `X.Y.Z.pre.N`, `X.Y.Z.dev.N` | The version *after* the one named is being developed |
161+
162+
So `4.1.1` on `master` is not a claim that `master` is 4.1.1. It says 4.1.1 has shipped and what
163+
comes after it is being worked on. `4.1.2.dev.1` says the same thing about itself: that release is
164+
out, and the line continues towards 4.1.2.
165+
166+
Both become true the moment the release is tagged, so **nothing has to be done to `master` after a
167+
release**. `4.0.1` was followed by `4.0.2` with no version change in between, and `4.1.2.dev.1` is
168+
what `master` carries today.
169+
170+
The bare `X.Y.0.dev` is the exception because it is the one version that names a target rather than
171+
a predecessor: a new minor is developed towards `X.Y.0` for a long time, before it is known whether
172+
the next thing to ship is `X.Y.0.pre.1` or `X.Y.0` itself. Setting it is the only version change
173+
that has to be made deliberately.
174+
175+
`rake gem:changelog` reads `RBS::VERSION` too, to decide where the next changelog starts — but the
176+
version is set to the one being released before the changelog is generated, so it sees that rather
177+
than whatever `master` was carrying.
178+
179+
## Starting a new minor
180+
181+
`master` is the development line of one minor at a time. Moving it from `X.Y` to `X.(Y+1)` is not
182+
part of any one release — it is the decision that the `X.Y` line is done, taken whenever that
183+
becomes true — and it is the one moment the version on `master` is changed by hand. Two changes, in
184+
opposite places:
185+
186+
1. **Branch the line being left behind**, from the last `master` commit that belongs to it:
187+
188+
```console
189+
$ git switch --create aaa-X.Y.x <that commit>
190+
$ git push -u origin aaa-X.Y.x
191+
```
192+
193+
Branch from the commit *before* the bump below, so the branch keeps the version its line was
194+
released under. Patch releases of `X.Y` are cut from here from now on, with their changes
195+
cherry-picked from `master` — see [Backports](#backports). The `aaa-` prefix carries no meaning
196+
beyond sorting the release branches to the top of the branch list.
197+
198+
2. **Bump `master`** to `X.(Y+1).0.dev`, in a pull request with `Gemfile.lock` regenerated and
199+
labeled `skip-changelog` like the release pull request itself. `4.1` was started exactly this
200+
way: `aaa-4.0.x` was branched at the commit before `Start 4.1 development`, which set
201+
`RBS::VERSION` to `4.1.0.dev`.
202+
203+
Two loose ends that are easy to forget:
204+
205+
- **The release note of the new line.** `rake gem:gh_release` links every published release to
206+
`https://github.com/ruby/rbs/wiki/Release-Note-X.Y`, built from the version number without
207+
checking that the page is there. Nothing has to be written when the line starts — the page comes
208+
together as the first release proper of the line comes into view — but it does have to exist by
209+
the time that release is published, or its notes link to an empty page.
210+
- **Release branches that are done.** A branch is worth keeping only while its line might still
211+
get a patch. The ones that exist do not cover every line that ever had one — `3.8.1` shipped and
212+
there is no `aaa-3.8.x` — so this is housekeeping rather than a rule, but starting a new minor is
213+
the natural moment to look at the bottom of the branch list and delete what has been superseded.
152214

153215
## Backports
154216

@@ -170,8 +232,11 @@ that is why the 4.0.3 changelog credits its three entries to the same pull reque
170232
- Prereleases (`X.Y.Z.pre.N`) are only installed with `gem install rbs --pre`;
171233
a plain `gem install rbs` is unaffected. On JRuby, `gem install rbs [--pre]`
172234
resolves to the `-java` gem automatically.
173-
- `Dockerfile.jruby` pins the WASI SDK / Chicory / ASM versions to match the
174-
`wasm`, `jruby`, and `release-gems` workflows. Keep them in sync when bumping.
235+
- The WASI SDK version is pinned in `wasm.yml`, `jruby.yml`, `release-gems.yml`, and
236+
`Dockerfile.jruby`, each carrying its own copy. Keep them in sync when bumping. The
237+
Chicory/ASM versions are not duplicated: they are the `jar` requirements in
238+
`rbs.gemspec`, which is where the workflow, `Dockerfile.jruby` and `gem install` all
239+
read them from.
175240
- `rake 'gem:check_release[X.Y.Z]'` and `rake gem:tag` are what the workflow runs to
176241
check the release and to create the tag. Both work locally, which is the fallback
177242
if the tag ever has to be created by hand.

wasm/README.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,39 @@ $ rake wasm:install_jars # download the Chicory/ASM jars into ~/.m2 (run on JRub
2727

2828
The compiled `rbs_parser.wasm` is a build artifact and is not checked in.
2929

30+
The WASI SDK is needed for the *build*, not for running the result — the host clang already
31+
knows the `wasm32` target, but there is no wasm32 libc on a normal machine, so it picks up the
32+
host headers and fails on the first `#include`. That is what the SDK supplies, along with the
33+
builtins the link step needs.
34+
35+
## Running the suite on JRuby
36+
37+
[`Dockerfile.jruby`](../Dockerfile.jruby) builds an image that has everything this needs, so no
38+
JRuby, JDK or WASI SDK has to be installed to work on the JRuby side:
39+
40+
```console
41+
$ docker build -f Dockerfile.jruby -t rbs-jruby .
42+
$ docker run --rm rbs-jruby # run the test suite
43+
$ docker run --rm -e RBS_PLATFORM=java rbs-jruby \
44+
gem build rbs.gemspec # build the -java gem
45+
```
46+
47+
Two things in it are not obvious:
48+
49+
- `build-essential` is for prism, which builds `libprism.so` and loads it through FFI on JRuby
50+
rather than as an MRI C extension. It needs `cc` and `make`.
51+
- Bundler is skipped. The development `Gemfile` pulls in CRuby-only C extensions (bigdecimal,
52+
stackprof, …) that cannot build on JRuby, so the few gems the suite needs are installed
53+
directly, in the same set as [`jruby.yml`](../.github/workflows/jruby.yml).
54+
55+
The image compiles `rbs_parser.wasm` itself, which is why it carries the WASI SDK. That is not
56+
the only arrangement: the build needs the SDK but not JRuby, and running the suite needs JRuby
57+
but not the SDK, so `jruby.yml` splits them instead — it compiles the module on CRuby and then
58+
switches engines to test against the result.
59+
60+
`rake wasm:install_jars` is the step that has to be on JRuby either way: it resolves the `jar`
61+
requirements from `rbs.gemspec` through the JVM.
62+
3063
## Exported functions
3164

3265
The module is built as a "reactor": it has no `main`, and the host calls

0 commit comments

Comments
 (0)