Skip to content

Commit 67e521e

Browse files
authored
Merge branch 'master' into ksss/allow-non-ascii-identifiers
2 parents 60a6d6d + 7534c7e commit 67e521e

18 files changed

Lines changed: 928 additions & 226 deletions

File tree

.github/dependabot.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,4 @@ updates:
2121
schedule:
2222
interval: 'weekly'
2323
labels:
24-
- 'no-milestone'
24+
- 'skip-changelog'

.github/workflows/bundle-update.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,6 @@ jobs:
5858
--body "Automated weekly bundle update" \
5959
--head "$(git rev-parse --abbrev-ref HEAD)" \
6060
--base "${{ github.event.repository.default_branch }}" \
61-
--label "no-milestone"
61+
--label "skip-changelog"
6262
6363
gh pr merge --auto --merge "$(git rev-parse --abbrev-ref HEAD)"

.github/workflows/jruby.yml

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -64,12 +64,7 @@ jobs:
6464
ruby-version: jruby
6565
bundler: none
6666
- name: Install runtime and test gems
67-
# rdoc 8.0.0 added a runtime dependency on rbs, which pulls the released
68-
# C-extension rbs gem and fails to build on JRuby. Pin rdoc below 8 until
69-
# a -java rbs gem is published.
70-
run: |
71-
gem install prism rake rake-compiler test-unit rspec minitest json-schema pry --no-document
72-
gem install rdoc -v "< 8" --no-document
67+
run: gem install prism rake rake-compiler test-unit rdoc rspec minitest json-schema pry --no-document
7368
# jar-dependencies resolves through the JVM, so download the Chicory/ASM
7469
# jars into ~/.m2 here on JRuby (jar-dependencies is not available in the
7570
# CRuby step above).

.github/workflows/milestone.yml

Lines changed: 0 additions & 91 deletions
This file was deleted.

.github/workflows/release-gems.yml

Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
name: Release gems
2+
3+
# Builds, publishes, and announces a release. Dispatch it with the commit being
4+
# released and the version that commit declares.
5+
#
6+
# Everything is built from `commit`, not from wherever the default branch happens to
7+
# be when the run starts, so the release describes a state that is already immutable.
8+
# `version` is the same fact stated a second time -- the run stops before anything is
9+
# built unless it matches the `RBS::VERSION` of that commit, so dispatching the wrong
10+
# commit, or the right one under the wrong name, is a failed run rather than a gem
11+
# that has to be yanked.
12+
#
13+
# `dry_run` builds and checks both gems and stops before the tag, which is how the
14+
# build is exercised without releasing anything.
15+
#
16+
# | Gem | Platform | Parser |
17+
# | -------------------- | ------------- | -------------------------------- |
18+
# | `rbs-X.Y.Z.gem` | `ruby` (MRI) | C extension, compiled on install |
19+
# | `rbs-X.Y.Z-java.gem` | `java` (JRuby)| `rbs_parser.wasm`, prebuilt here |
20+
#
21+
# See docs/release.md. The `java` gem is built on CRuby: the platform comes from
22+
# `RBS_PLATFORM`, not from the engine running `gem build`. JRuby is only needed to
23+
# run the result, which the workflow does before it would publish anything.
24+
#
25+
# One job on purpose. Tagging, pushing the gems, and opening the GitHub release
26+
# all belong to a single release, and keeping them in one place keeps their order
27+
# readable -- the tag is created once both gems are known to build and run, and
28+
# before anything is published, so the reversible step comes before the irreversible
29+
# one.
30+
#
31+
# The file name is what the RubyGems trusted publisher for `rbs` is registered
32+
# against, so it cannot be renamed without registering the new name first.
33+
34+
on:
35+
workflow_dispatch:
36+
inputs:
37+
commit:
38+
description: "Commit to release, as a full 40-character SHA"
39+
required: true
40+
version:
41+
description: "Version to release, without the leading `v` (e.g. `4.1.2`)"
42+
required: true
43+
dry_run:
44+
description: "Build and check the gems without tagging or publishing anything"
45+
type: boolean
46+
default: false
47+
48+
permissions:
49+
contents: read
50+
51+
env:
52+
# Keep in sync with .github/workflows/wasm.yml and .github/workflows/jruby.yml.
53+
WASI_SDK_VERSION: "33"
54+
WASI_SDK_RELEASE: "33.0"
55+
56+
jobs:
57+
release:
58+
name: release
59+
runs-on: ubuntu-latest
60+
permissions:
61+
contents: write # push the tag, publish the GitHub release
62+
id-token: write # trusted publishing to RubyGems
63+
env:
64+
# The inputs are read through the environment rather than interpolated into
65+
# the scripts below.
66+
COMMIT: ${{ inputs.commit }}
67+
VERSION: ${{ inputs.version }}
68+
TAG: v${{ inputs.version }}
69+
steps:
70+
# The gemspec takes its file list from `git ls-files`, so both gems are built
71+
# from the committed state -- of the dispatched commit, since that is what is
72+
# checked out. The full history is needed to tell which branches contain it.
73+
- uses: actions/checkout@v7
74+
with:
75+
ref: ${{ inputs.commit }}
76+
fetch-depth: 0
77+
78+
# Before anything is installed or built: these are the two things the release
79+
# is named after and built from, and a mistake in either is cheapest to catch
80+
# here.
81+
- name: Check the inputs
82+
run: |
83+
if [[ ! "$COMMIT" =~ ^[0-9a-f]{40}$ ]]; then
84+
echo "::error::\`$COMMIT\` is not a full 40-character SHA. A release names one exact commit."
85+
exit 1
86+
fi
87+
if [[ ! "$VERSION" =~ ^[0-9][0-9a-zA-Z.]*$ ]]; then
88+
echo "::error::\`$VERSION\` is not a version number. Pass it without the leading \`v\`."
89+
exit 1
90+
fi
91+
92+
# A release proper is cut from the default branch, while a patch release can
93+
# be cut from a release branch, so which branch the commit is on is not this
94+
# workflow's business. That it is on one is: a commit no branch contains is
95+
# one that nothing in the repository leads to any more.
96+
git fetch --no-tags origin "+refs/heads/*:refs/remotes/origin/*"
97+
branches=$(git branch --remotes --contains "$COMMIT" --format "%(refname:lstrip=3)")
98+
if [ -z "$branches" ]; then
99+
echo "::error::$COMMIT is not on any branch."
100+
exit 1
101+
fi
102+
echo "Branches containing $COMMIT:"
103+
printf '%s\n' "$branches"
104+
105+
# A tag that already exists is a version that has already been released, and
106+
# pushing it would fail after the build rather than before it.
107+
- name: Check that the tag does not exist
108+
if: ${{ !inputs.dry_run }}
109+
run: |
110+
if git ls-remote --exit-code --tags origin "refs/tags/$TAG" > /dev/null; then
111+
echo "::error::$TAG already exists, so $VERSION has been released."
112+
exit 1
113+
fi
114+
115+
- name: Set up Ruby
116+
uses: ruby/setup-ruby@v1
117+
with:
118+
ruby-version: ruby
119+
bundler: none
120+
- name: Update rubygems & bundler
121+
run: gem update --system
122+
- name: Install gems
123+
run: |
124+
bundle config set --local without libs:profilers
125+
bundle install --jobs 4 --retry 3
126+
127+
# Fails before a minute is spent on the build, and before anything is pushed:
128+
# the version has to be the one the released commit declares, and -- unless
129+
# this is a `.dev.N` release -- the one CHANGELOG.md is written up for.
130+
- name: Check the version and the changelog
131+
run: bundle exec rake "gem:check_release[$VERSION]"
132+
133+
- name: Build the ruby gem
134+
run: |
135+
mkdir -p pkg
136+
gem build rbs.gemspec -o "pkg/rbs-$VERSION.gem"
137+
138+
# `rake wasm:jruby_setup` compiles src/**/*.c to WebAssembly and copies the
139+
# result to lib/rbs/wasm/, where the gemspec picks it up. clang runs as a
140+
# subprocess, so this works on CRuby.
141+
- name: Install the WASI SDK
142+
run: |
143+
url="https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-${WASI_SDK_VERSION}/wasi-sdk-${WASI_SDK_RELEASE}-x86_64-linux.tar.gz"
144+
mkdir -p "$HOME/wasi-sdk"
145+
curl -sSL "$url" | tar xz --strip-components=1 -C "$HOME/wasi-sdk"
146+
echo "WASI_SDK_PATH=$HOME/wasi-sdk" >> "$GITHUB_ENV"
147+
- name: Build rbs_parser.wasm
148+
run: bundle exec rake wasm:jruby_setup
149+
150+
- name: Build the java gem
151+
env:
152+
RBS_PLATFORM: java
153+
run: gem build rbs.gemspec -o "pkg/rbs-$VERSION-java.gem"
154+
155+
# `git ls-files` vouches for everything else, but rbs_parser.wasm is a build
156+
# artifact, so the java gem is the one that can come out quietly wrong.
157+
- name: Check the built gems
158+
run: |
159+
ruby -rrubygems/package -e '
160+
ruby_gem, java_gem = ARGV.map { Gem::Package.new(_1).spec }
161+
162+
raise "unexpected platform: #{ruby_gem.platform}" unless ruby_gem.platform.to_s == "ruby"
163+
raise "the C extension is not declared" if ruby_gem.extensions.empty?
164+
165+
raise "unexpected platform: #{java_gem.platform}" unless java_gem.platform.to_s == "java"
166+
raise "rbs_parser.wasm is missing" unless java_gem.files.include?("lib/rbs/wasm/rbs_parser.wasm")
167+
raise "the java gem must not declare an extension" unless java_gem.extensions.empty?
168+
169+
[ruby_gem, java_gem].each { puts "#{_1.full_name}: #{_1.files.size} files" }
170+
' "pkg/rbs-$VERSION.gem" "pkg/rbs-$VERSION-java.gem"
171+
172+
# The checks above cannot tell whether rbs_parser.wasm actually runs. Install
173+
# the gem the way a user would -- jar-dependencies fetches Chicory and ASM
174+
# from Maven during the install -- and parse something with it, so the
175+
# WebAssembly runtime is exercised end to end before anything is published.
176+
- name: Set up JRuby
177+
uses: ruby/setup-ruby@v1
178+
with:
179+
ruby-version: jruby
180+
bundler: none
181+
- name: Check the java gem on JRuby
182+
run: |
183+
gem install "pkg/rbs-$VERSION-java.gem"
184+
ruby -e '
185+
require "rbs"
186+
_, _, decls = RBS::Parser.parse_signature("class Foo end")
187+
names = decls.map { _1.name.to_s }
188+
raise "parsed #{names.inspect}, expected [\"Foo\"]" unless names == ["Foo"]
189+
puts "#{RUBY_ENGINE} #{RUBY_VERSION}: rbs #{RBS::VERSION} parses through the WebAssembly runtime"
190+
'
191+
192+
- name: Switch back to CRuby
193+
uses: ruby/setup-ruby@v1
194+
with:
195+
ruby-version: ruby
196+
bundler: none
197+
198+
# Uploaded before publishing, so a failed push still leaves the gems behind.
199+
# This is also where a dry run ends.
200+
- uses: actions/upload-artifact@v7
201+
with:
202+
name: gems
203+
path: pkg/*.gem
204+
if-no-files-found: error
205+
206+
# Everything below runs only for a real release.
207+
208+
# The tag comes after the gems are known to build and run, and before anything
209+
# is published: a tag can be deleted, while a version pushed to RubyGems can
210+
# only be yanked. What it names was decided by the checkout rather than by the
211+
# tagging, so nothing rests on it being created first.
212+
- name: Tag the release
213+
if: ${{ !inputs.dry_run }}
214+
run: |
215+
git config user.name "github-actions[bot]"
216+
git config user.email "github-actions[bot]@users.noreply.github.com"
217+
bundle exec rake gem:tag
218+
219+
- name: Configure RubyGems credentials
220+
if: ${{ !inputs.dry_run }}
221+
# No floating major tag on this action, so the exact release is pinned.
222+
uses: rubygems/configure-rubygems-credentials@v2.1.0
223+
224+
- name: Push the gems
225+
if: ${{ !inputs.dry_run }}
226+
run: |
227+
gem push "pkg/rbs-$VERSION.gem"
228+
gem push "pkg/rbs-$VERSION-java.gem"
229+
230+
# Last, so that a failed push never announces a release that has no gems.
231+
- name: Publish the GitHub release
232+
if: ${{ !inputs.dry_run }}
233+
env:
234+
GH_TOKEN: ${{ github.token }}
235+
run: bundle exec rake gem:gh_release

CHANGELOG.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,16 @@
11
# CHANGELOG
22

3+
## 4.1.1 (2026-07-30)
4+
5+
### Library changes
6+
7+
* Include the trailing `?` in a keyword key's symbol location ([#3043](https://github.com/ruby/rbs/pull/3043))
8+
* Mark `type_name` as optional on the alias annotations ([#3039](https://github.com/ruby/rbs/pull/3039))
9+
10+
### Miscellaneous
11+
12+
* Fix template drift for ext/rbs_extension/ast_translation.c ([#3038](https://github.com/ruby/rbs/pull/3038))
13+
314
## 4.1.0 (2026-07-27)
415

516
RBS 4.1 ships with JRuby support. The RBS parser is written in plain C without depending on the Ruby C API, so it is compiled to WebAssembly and runs on a Wasm runtime, with the parsed AST serialized in a binary format and decoded into RBS objects. The full test suite runs on JRuby in CI.
@@ -88,6 +99,14 @@ This release also introduces `RBS::Rewriter`, an API to edit RBS source text whi
8899
* ci: skip Gemfile.lock BUNDLED WITH on ruby-head ([#2952](https://github.com/ruby/rbs/pull/2952))
89100
* Remove `logger` from sig dependencies ([#2904](https://github.com/ruby/rbs/pull/2904))
90101

102+
## 4.0.3 (2026-06-18)
103+
104+
### Miscellaneous
105+
106+
* Fix Ruby CI failure with compressed `Zlib::GzipReader` test fixtures. ([#3005](https://github.com/ruby/rbs/pull/3005))
107+
* Fix flaky `DirSingletonTest#test_fchdir` and `DirSingletonTest#test_for_fd` under aggressive GC. ([#3005](https://github.com/ruby/rbs/pull/3005))
108+
* Fix Ruby head CI failure caused by the lockfile-pinned Bundler version. ([#3005](https://github.com/ruby/rbs/pull/3005))
109+
91110
## 4.0.2 (2026-03-25)
92111

93112
### Library changes

Gemfile.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ GIT
2222
PATH
2323
remote: .
2424
specs:
25-
rbs (4.1.0)
25+
rbs (4.1.2.dev.1)
2626
logger
2727
prism (>= 1.6.0)
2828
tsort

0 commit comments

Comments
 (0)