Skip to content

[pull] master from ruby:master#1127

Merged
pull[bot] merged 25 commits into
turkdevops:masterfrom
ruby:master
Jun 18, 2026
Merged

[pull] master from ruby:master#1127
pull[bot] merged 25 commits into
turkdevops:masterfrom
ruby:master

Conversation

@pull

@pull pull Bot commented Jun 18, 2026

Copy link
Copy Markdown

See Commits and Changes for more details.


Created by pull[bot] (v2.0.0-alpha.4)

Can you help keep this open source service alive? 💖 Please sponsor : )

jeremyevans and others added 25 commits June 17, 2026 18:18
This is implied by the fact that non-main ractors use the M:N thread
scheduler, but I expect that some users are not aware of this.

Bump all man page dates as CI requires it.
First piece of a RubyGems-side compact index client, ported from
Bundler::CompactIndexClient. The two implementations are intentionally
kept separate so that gem commands can adopt the compact index without
touching Bundler.

ruby/rubygems@5228def195

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Keeps cached compact index files in sync with the server using ETag
conditional requests and ranged requests, verifying Repr-Digest
checksums. Unlike the Bundler version, checksum and gzip failures
raise Gem::CompactIndexClient errors instead of Bundler::HTTPError.

ruby/rubygems@c46aa9e5c7

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Manages the on-disk cache layout (versions, names, info/*, etags) and
delegates fetching to the Updater, deduplicating endpoint fetches per
process. Also adds the DEBUG_COMPACT_INDEX debug logger to the client.

ruby/rubygems@5e87453b36

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Parses the versions index (including deletion lines and per-gem info
checksums) and info files. Reuses Gem::Resolver::APISet::GemParser for
info lines, which already preserves compact index v2 metadata such as
created_at.

ruby/rubygems@234ca8b3ad

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Completes the client facade: names, versions, info, dependencies,
latest_version, available? and reset! on top of Cache and Parser.

ruby/rubygems@ded1a5e54a

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adapts Gem::RemoteFetcher to the fetcher interface expected by the
compact index client. RemoteFetcher#fetch_path only supports
If-Modified-Since, while the compact index needs ETag conditional
requests and ranged requests, so this issues requests directly through
RemoteFetcher#request.

ruby/rubygems@d85a75eb85

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
util_setup_compact_index serves versions, names and info/NAME on the
FakeFetcher with consistent MD5/SHA-256 checksums, ETags and optional
created_at v2 metadata, so functional tests can drive gem commands
against a stubbed compact index. Verified against the real
Gem::CompactIndexClient.

ruby/rubygems@38c019a06a

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Fetches a single gem's info file with an ETag conditional request,
without consulting the versions index. The versions index download
only pays off when most gems are needed; for gem install, fetching
just the required info files keeps the first-use cost at the current
level while still benefiting from the disk cache.

ruby/rubygems@e37983c228

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…tIndexClient

Info files are now cached on disk under Gem.spec_cache_dir and
refreshed with ETag conditional requests instead of being downloaded
in full on every resolution. APISet keeps fetching only the info files
it needs (via fetch_info) rather than the whole versions index, so the
first-use cost stays at the current level. When the user's home is not
safely writable the cache falls back to a temporary directory.

ruby/rubygems@f393a11cb4

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The compact index v2 publishes per-version creation timestamps which
the parser already preserves. Keep them on resolver specifications so
features like cooldown can consult publish dates during resolution.
Sources without timestamps leave created_at nil.

ruby/rubygems@2060dd6ed2

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The compact index info file carries everything needed to download and
install a gem, so materializing the resolved specification no longer
fetches the Marshal gemspec from /quick/. Development dependencies are
not part of the info file; fetch_development_dependencies still
fetches the full gemspec for --development installs.

ruby/rubygems@eaf2522e4f

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…Source

Gem::Source#load_specs now builds the released, latest and prerelease
name tuple lists from the compact index versions file, falling back to
the Marshal spec indexes when the source does not provide a usable
compact index. This moves gem update, outdated, list and search off
Marshal data for compact index sources. The client construction moves
to Gem::Source so APISet and load_specs share one client and disk
cache per source.

ruby/rubygems@e5e9a13e14

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…dated

End-to-end tests driving both commands against a stubbed compact index
with no usable Marshal data, proving the SpecFetcher path works through
Gem::Source#load_specs. The stubbed versions response now carries a
response uri so the dependency_resolver_set probe and the compact index
fetch share one endpoint, as on real servers.

ruby/rubygems@ab8d4b477a

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A Digest or Repr-Digest parameter without a value (no "=") made
byte_sequence raise NoMethodError on nil, failing the whole fetch when
a mirror or proxy sends a broken header. The same flaw exists in the
Bundler implementation this was ported from.

ruby/rubygems@d22a059d01

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Both methods computed the rubygems.org to index.rubygems.org rewrite
independently; keep the logic in one place.

ruby/rubygems@22103a6bcc

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Pathname is built into Ruby 4.0+, so only require the library when the
constant is not already available.

ruby/rubygems@e5b9b15646

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Pathname#write uses text mode, so on Windows the LF in fixture data
became CRLF, shifting the file size the Range header is computed from
and breaking the MD5/SHA-256 checksums. The client itself is
unaffected since CacheFile always writes in binary mode.

ruby/rubygems@4e6953e919

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ct index

A single unparseable version line in /versions made
Gem::Source#load_specs raise ArgumentError and fall back to the
Marshal indexes for the whole source. Guard each row with
Gem::Version.correct? so only the bad version is skipped.

ruby/rubygems@0bf8967250

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ot writable

When the gem home is not writable, compact_index_cache_dir falls back
to Dir.mktmpdir but never removed it, leaking a directory under the
system temp on every gem command. Remove it at process exit.

ruby/rubygems@8daf0d1f7d

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Time.new accepts a bare year like "2026" and returns a local-time
value instead of raising, so a malformed created_at was silently
turned into a wrong timestamp. Use Time.iso8601 so anything that is
not a real ISO8601 string falls back to nil.

ruby/rubygems@995e21e891

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Previously, the inliner conservatively refused any callee that interacted with a block. `can_inline` rejected callees whose parameters included a block parameter, and separately scanned the callee bytecode and bailed on `invokeblock`, `getblockparam`, and `getblockparamproxy`. Together these excluded the common case of a small method that simply yields to a passed block.

This lifts those restrictions so such a method can itself be inlined. Only the enclosing method is inlined; the block body is still invoked through the normal block-dispatch path rather than being inlined in turn.

Removing the bytecode scan exposed a latent bug in the `invokeblock` lowering. The block-handler level was computed with `get_lvar_level(fun.iseq)`, but `fun.iseq` is the outer compiled function rather than the callee that contains the `invokeblock`. Under inlining the two diverge, so the level could be computed against the wrong frame. It now uses `exit_state.iseq`: the ISEQ of the frame actually executing the instruction.
Bumps the github-actions group with 1 update in the / directory: [taiki-e/install-action](https://github.com/taiki-e/install-action).


Updates `taiki-e/install-action` from 2.81.11 to 2.82.0
- [Release notes](https://github.com/taiki-e/install-action/releases)
- [Changelog](https://github.com/taiki-e/install-action/blob/main/CHANGELOG.md)
- [Commits](taiki-e/install-action@15449e3...b8cecb8)

---
updated-dependencies:
- dependency-name: taiki-e/install-action
  dependency-version: 2.82.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Calling connect_nonblock a second time to confirm a non-blocking
connect is not portable. On BSD-based systems such as macOS the second
connect returns EISCONN even after the asynchronous connect failed with
ECONNREFUSED, so a down mirror was reported as reachable. Check the
pending socket error with getsockopt(SO_ERROR) once IO.select reports
the socket writable instead.

ruby/rubygems@b953dbd3c8

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@pull pull Bot locked and limited conversation to collaborators Jun 18, 2026
@pull pull Bot added the ⤵️ pull label Jun 18, 2026
@pull pull Bot merged commit 0f4f0b6 into turkdevops:master Jun 18, 2026
1 of 3 checks passed
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants