Skip to content

Skip bundler self-checksum for unreleased bundlers#9501

Open
hsbt wants to merge 3 commits intomasterfrom
fix-dev-lockfile-bundler-checksum
Open

Skip bundler self-checksum for unreleased bundlers#9501
hsbt wants to merge 3 commits intomasterfrom
fix-dev-lockfile-bundler-checksum

Conversation

@hsbt
Copy link
Copy Markdown
Member

@hsbt hsbt commented Apr 23, 2026

What was the end-user or developer problem that led to this PR?

Using Bundler.gem_version.end_with?(".dev") only skips the own checksum on master, but patch releases run from a source checkout (e.g., bumping bundler/lib/bundler/version.rb to 4.0.11 on a release branch) still record the checksum, which is environment dependent on the local gem cache and causes frozen-lock drift on CI.

https://github.com/ruby/rubygems/actions/runs/24831299384/job/72680209697

What is your fix for the problem, implemented in this PR?

Generalize the guard with released_bundler?, which returns false for any prerelease version and for bundlers loaded outside of an installed gem location (/specifications/), so dev workflows don't record self-checksums while released installs still do.

@Edouard-chin Could you review this?

Make sure the following tasks are checked

Using `Bundler.gem_version.end_with?(".dev")` only skips the own
checksum on master, but patch releases run from a source checkout
(e.g., bumping bundler/lib/bundler/version.rb to 4.0.11 on a release
branch) still record the checksum, which is environment dependent on
the local gem cache and causes frozen-lock drift on CI.

Generalize the guard with `released_bundler?`, which returns false for
any prerelease version and for bundlers loaded outside of an installed
gem location (`/specifications/`), so dev workflows don't record
self-checksums while released installs still do.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings April 23, 2026 11:42
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adjusts Bundler lockfile checksum generation to avoid recording Bundler’s own checksum when Bundler is being run from an unreleased/prerelease build or from a source checkout, preventing environment-dependent checksum drift in frozen CI workflows.

Changes:

  • Replace the previous .dev-only guard with a generalized released_bundler? predicate.
  • Skip generating Bundler’s self-checksum unless Bundler appears to be a released, installed gem (and not a prerelease).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +121 to +123
# Released gem specs live under .../specifications/; source checkouts don't.
Gem.loaded_specs["bundler"]&.loaded_from.to_s.include?("/specifications/")
end
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

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

released_bundler? relies on loaded_from.to_s.include?("/specifications/"), which is not portable to Windows paths ("\specifications\") and is also a brittle substring check. Consider determining whether the bundler spec is installed by comparing File.dirname(loaded_from) against Gem::Specification.dirs and Gem.default_specifications_dir (or otherwise normalizing separators and doing an anchored path check).

Suggested change
# Released gem specs live under .../specifications/; source checkouts don't.
Gem.loaded_specs["bundler"]&.loaded_from.to_s.include?("/specifications/")
end
bundler_spec = Gem.loaded_specs["bundler"]
return false unless bundler_spec&.loaded_from
released_bundler_spec_dirs.include?(File.expand_path(File.dirname(bundler_spec.loaded_from)))
end
def released_bundler_spec_dirs
@released_bundler_spec_dirs ||= begin
dirs = Gem::Specification.dirs.map {|dir| File.expand_path(dir) }
dirs << File.expand_path(Gem.default_specifications_dir) if Gem.respond_to?(:default_specifications_dir)
dirs.uniq
end
end

Copilot uses AI. Check for mistakes.
Comment on lines +121 to +123
# Released gem specs live under .../specifications/; source checkouts don't.
Gem.loaded_specs["bundler"]&.loaded_from.to_s.include?("/specifications/")
end
Copy link

Copilot AI Apr 23, 2026

Choose a reason for hiding this comment

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

This change alters when Bundler writes its own checksum (now based on version prerelease status and where Bundler is loaded from). There are existing specs around lockfile checksums; please add coverage for the new behavior (e.g., a released version running from a source checkout should not record the bundler self-checksum, while an installed released bundler still should).

Suggested change
# Released gem specs live under .../specifications/; source checkouts don't.
Gem.loaded_specs["bundler"]&.loaded_from.to_s.include?("/specifications/")
end
# Released gem specs live under a "specifications" directory; source checkouts don't.
path_components(Gem.loaded_specs["bundler"]&.loaded_from).include?("specifications")
end
def path_components(path)
separators = [File::SEPARATOR, File::ALT_SEPARATOR].compact.uniq
path.to_s.split(Regexp.union(separators))
end

Copilot uses AI. Check for mistakes.
@Edouard-chin
Copy link
Copy Markdown
Collaborator

Edouard-chin commented Apr 24, 2026

@hsbt I'm trying to understand why the .lock had the checksum included on your release branch at #9498.

I tried to run the command GITHUB_RELEASE_PAT=<token> DRYRUN=1 rake "prepare_release[4.0.11]" to check myself, and the lock don't include the checksum.
I was assuming this is the command you'd run when making a release and that you'd have no bundler-<VERSION_TO_RELEASE>.gem anywhere on your system before you start the releasing process. Is it possible that you ran rake bundler:install before ? Eg. does gem list bundler shows 4.0.11 ?

If my assumption is incorrect and that you package/install bundler on your system before starting the release process, then I think we should just skip the checksum using an env variable. Basically, this codepath should never end up including bundler checksum for our development lockfile, even when we make a release.

Spec::Rubygems.dev_bundle("lock", "--update", "--bundler", version, gemfile: file)

FWIW this is the lockfiles diff after running GITHUB_RELEASE_PAT=<token> DRYRUN=1 rake "prepare_release[4.0.11]"

diff --git a/tool/bundler/dev_gems.rb.lock b/tool/bundler/dev_gems.rb.lock
index ad3e6542cf..0b3f62595d 100644
--- a/tool/bundler/dev_gems.rb.lock
+++ b/tool/bundler/dev_gems.rb.lock
@@ -141,4 +141,4 @@ CHECKSUMS
   turbo_tests (2.2.5) sha256=3fa31497d12976d11ccc298add29107b92bda94a90d8a0a5783f06f05102509f
 
 BUNDLED WITH
-  4.1.0.dev
+  4.0.11
diff --git a/tool/bundler/lint_gems.rb.lock b/tool/bundler/lint_gems.rb.lock
index bc42c930ed..a63e8d8ecb 100644
--- a/tool/bundler/lint_gems.rb.lock
+++ b/tool/bundler/lint_gems.rb.lock
@@ -119,4 +119,4 @@ CHECKSUMS
   wmi-lite (1.0.7) sha256=116ef5bb470dbe60f58c2db9047af3064c16245d6562c646bc0d90877e27ddda
 
 BUNDLED WITH
-  4.1.0.dev
+  4.0.11
diff --git a/tool/bundler/release_gems.rb.lock b/tool/bundler/release_gems.rb.lock
index dbaec076d5..ea72e17083 100644
--- a/tool/bundler/release_gems.rb.lock
+++ b/tool/bundler/release_gems.rb.lock
@@ -87,4 +87,4 @@ CHECKSUMS
   uri (1.1.1) sha256=379fa58d27ffb1387eaada68c749d1426738bd0f654d812fcc07e7568f5c57c6
 
 BUNDLED WITH
-  4.1.0.dev
+  4.0.11
diff --git a/tool/bundler/rubocop_gems.rb.lock b/tool/bundler/rubocop_gems.rb.lock
index d0c3120e11..07127c25bf 100644
--- a/tool/bundler/rubocop_gems.rb.lock
+++ b/tool/bundler/rubocop_gems.rb.lock
@@ -156,4 +156,4 @@ CHECKSUMS
   unicode-emoji (4.2.0) sha256=519e69150f75652e40bf736106cfbc8f0f73aa3fb6a65afe62fefa7f80b0f80f
 
 BUNDLED WITH
-  4.1.0.dev
+  4.0.11
diff --git a/tool/bundler/standard_gems.rb.lock b/tool/bundler/standard_gems.rb.lock
index f3792f8611..57a455a0df 100644
--- a/tool/bundler/standard_gems.rb.lock
+++ b/tool/bundler/standard_gems.rb.lock
@@ -176,4 +176,4 @@ CHECKSUMS
   unicode-emoji (4.2.0) sha256=519e69150f75652e40bf736106cfbc8f0f73aa3fb6a65afe62fefa7f80b0f80f
 
 BUNDLED WITH
-  4.1.0.dev
+  4.0.11
diff --git a/tool/bundler/test_gems.rb.lock b/tool/bundler/test_gems.rb.lock
index fdffc1f09d..17e62dc42e 100644
--- a/tool/bundler/test_gems.rb.lock
+++ b/tool/bundler/test_gems.rb.lock
@@ -103,4 +103,4 @@ CHECKSUMS
   tilt (2.6.1) sha256=35a99bba2adf7c1e362f5b48f9b581cce4edfba98117e34696dde6d308d84770
 
 BUNDLED WITH
-  4.1.0.dev
+  4.0.11
diff --git a/tool/bundler/vendor_gems.rb.lock b/tool/bundler/vendor_gems.rb.lock
index e2cc184c7a..a03074938f 100644
--- a/tool/bundler/vendor_gems.rb.lock
+++ b/tool/bundler/vendor_gems.rb.lock
@@ -72,4 +72,4 @@ CHECKSUMS
   uri (1.1.1) sha256=379fa58d27ffb1387eaada68c749d1426738bd0f654d812fcc07e7568f5c57c6
 
 BUNDLED WITH
-  4.1.0.dev
+  4.0.11

- Our development lockfile should not include the checksum of bundler
  itself. No matter if we are doing a release.
  The problem being that including a checksum in our development
  lockfile create issues as some rake tasks don't run the same way on
  CI.

  For example, some rake tasks, build bundler.gem and some other
  don't. I explained in more details the issue here 2c40b8d

  This commit here is motivated by the fact that when the release
  manager runs `version:update_locked_bundler`, if a
  `bundler-<VERSION>.gem` exists on its system (e.g it previously ran
  `rake bundler:install`), then the lockfile will include a checksum
  entry.
@Edouard-chin
Copy link
Copy Markdown
Collaborator

I pushed a commit to skip the checksum entry when rake version:update_locked_bundler is called.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants