dependabot-bundler 0.384.0 → 0.386.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3daa49f0b7badcac1b05d18da5a85120669028a0e05217e9f25909841c90593c
4
- data.tar.gz: 86a858104d17f0050cbede5e5d9d815a47b2c0ee36ba844d4777f71a70840549
3
+ metadata.gz: 0f0e20b61f6f25f9cab555ba872e5f1e087435c8262e077340dbd54ffc4d06b6
4
+ data.tar.gz: f25535c60a1fbb733644a2e0429cc9cac5a63150b757ac0b4f14788884f62f31
5
5
  SHA512:
6
- metadata.gz: 57636ebdc4fa11bebb74e6839df1d363dcb6db1e381b2070c5e81f76301ada8d747c36965c85c269cc25cd6a4ecc5b2d7312d3d9f3eeadc7c9b48e2d61fdedb1
7
- data.tar.gz: 7907b9f4b766c2e080a0d2842c5cf3b10fc8c02dbfdfdf2f545366ecdf4c6566e8dcffa89783e83d6b65c4884da627624f98a469a8b93a24d20f9ac28752427f
6
+ metadata.gz: 0c80cce29ae7d8641213f9f6189627f3ef2e4d005b5039286638e7b7de35693744161b9c8668983ce46bc814c912c6264665060649f33c2ee43ad951f2faf399
7
+ data.tar.gz: 32a6267dd3b4e3682a726dafdcfc043e0259b3fee6881f8fbee7b35ab85ad9393a3d21a54ea39024f8ca70796a725d85fe05e76e479a9925e391e8ee0d049198
@@ -72,6 +72,15 @@ module Functions
72
72
  lockfile_specs.include?(spec)
73
73
  end.map(&:name).uniq
74
74
 
75
+ cache_path = Bundler.app_cache
76
+
77
+ # Snapshot the gems already vendored in the repo before we re-cache.
78
+ # `cache_all_platforms` re-fetches every platform variant of every gem,
79
+ # which adds gem files for platforms the repo may never have vendored.
80
+ # We only want to add platform variants for gems this update actually
81
+ # changed, so anything else newly added is reverted below.
82
+ pre_existing_gems = Dir["#{cache_path}/*.gem"]
83
+
75
84
  bundler_opts = {
76
85
  cache_all: true,
77
86
  cache_all_platforms: true,
@@ -84,10 +93,30 @@ module Functions
84
93
 
85
94
  # Only prune updated gems (the original implementation is in
86
95
  # Bundler::Runtime)
87
- cache_path = Bundler.app_cache
88
96
  prune_gem_cache(resolve, cache_path, updated_gems)
89
97
  prune_git_and_path_cache(resolve, cache_path)
90
98
  end
99
+
100
+ # Revert gem files newly added by the all-platforms re-cache that belong
101
+ # to dependencies this update didn't touch. Without this a single-gem
102
+ # update re-vendors missing platform variants for *every* gem, producing
103
+ # large diffs unrelated to the update on repos that don't vendor every
104
+ # platform.
105
+ prune_unrequested_gem_additions(cache_path, pre_existing_gems, updated_gems)
106
+ end
107
+
108
+ # Removes gem files added by the all-platforms re-cache that were not
109
+ # present before and don't belong to an updated dependency (including
110
+ # sub-dependencies). Pre-existing vendored gems are always left untouched.
111
+ def prune_unrequested_gem_additions(cache_path, pre_existing_gems, updated_gems)
112
+ Dir["#{cache_path}/*.gem"].each do |path|
113
+ next if pre_existing_gems.include?(path)
114
+
115
+ spec = Bundler.rubygems.spec_from_gem(path)
116
+ next if updated_gems.include?(spec.name)
117
+
118
+ File.delete(path)
119
+ end
91
120
  end
92
121
 
93
122
  # Copied from Bundler::Runtime: Modified to only prune gems that have
@@ -0,0 +1,33 @@
1
+ # typed: false
2
+ # frozen_string_literal: true
3
+
4
+ require "bundler/endpoint_specification"
5
+
6
+ # Bundler parses the metadata a registry's compact index (`/info/<gem>`)
7
+ # returns per gem version. Its guard is `next unless v`, but an empty array
8
+ # `[]` is truthy, so for an empty `checksum` it calls `Checksum.from_api(nil)`
9
+ # -> `nil.match?(...)` and raises `Bundler::GemspecError` ("There was an error
10
+ # parsing the metadata for the gem ..."), aborting the whole resolution.
11
+ #
12
+ # GitHub Packages serves this empty-checksum shape for some old gems (e.g.
13
+ # failbot 2.0.1), so one such gem blocks every update for the repo. Compact-
14
+ # index checksum verification landed in Bundler 2.5, so both the Bundler 2 and
15
+ # Bundler 4 helpers parse checksums and need this patch (the Bundler 2 helper
16
+ # activates ">= 2.4, < 3", i.e. a checksum-parsing 2.5+).
17
+ #
18
+ # Drop nil/empty metadata values before Bundler parses them. An empty checksum
19
+ # carries nothing to verify, so skipping it is safe; well-formed values (and
20
+ # genuinely malformed ones, which still raise) are untouched.
21
+ module BundlerEndpointSpecificationMetadataPatch
22
+ def parse_metadata(data)
23
+ if data.respond_to?(:reject)
24
+ data = data.reject do |_key, value|
25
+ value.nil? || (value.respond_to?(:empty?) && value.empty?)
26
+ end
27
+ end
28
+
29
+ super
30
+ end
31
+ end
32
+
33
+ Bundler::EndpointSpecification.prepend(BundlerEndpointSpecificationMetadataPatch)
data/helpers/v2/run.rb CHANGED
@@ -25,6 +25,7 @@ end
25
25
  require "definition_ruby_version_patch"
26
26
  require "definition_bundler_version_patch"
27
27
  require "git_source_patch"
28
+ require "endpoint_specification_metadata_patch"
28
29
 
29
30
  require "functions"
30
31
 
@@ -0,0 +1,49 @@
1
+ # typed: false
2
+ # frozen_string_literal: true
3
+
4
+ require "native_spec_helper"
5
+
6
+ RSpec.describe BundlerEndpointSpecificationMetadataPatch do
7
+ let(:spec_fetcher) { instance_double(Bundler::Fetcher, uri: URI("https://example.com")) }
8
+
9
+ def build_spec(metadata)
10
+ Bundler::EndpointSpecification.new("failbot", "2.0.1", "ruby", spec_fetcher, [], metadata)
11
+ end
12
+
13
+ it "does not raise when the registry serves an empty checksum array" do
14
+ expect { build_spec([["checksum", []]]) }.not_to raise_error
15
+ end
16
+
17
+ it "leaves the checksum unset for an empty checksum array" do
18
+ spec = build_spec([["checksum", []]])
19
+ expect(spec.checksum).to be_nil
20
+ end
21
+
22
+ # The compact-index parser can emit a value-less entry (`["checksum"]`) rather
23
+ # than an empty array, depending on the RubyGems GemParser version. Both shapes
24
+ # reach this code, so both must be tolerated.
25
+ it "does not raise when the checksum entry has no value at all" do
26
+ expect { build_spec([["checksum"]]) }.not_to raise_error
27
+ end
28
+
29
+ it "ignores nil and blank metadata values" do
30
+ expect { build_spec([["checksum", nil], ["ruby", []]]) }.not_to raise_error
31
+ end
32
+
33
+ it "still parses a well-formed checksum" do
34
+ digest = "f" * 64
35
+ spec = build_spec([["checksum", [digest]]])
36
+ expect(spec.checksum).not_to be_nil
37
+ end
38
+
39
+ it "still parses ruby and rubygems requirements" do
40
+ spec = build_spec([["ruby", [">= 3.1"]], ["rubygems", [">= 3.0"]], ["checksum", []]])
41
+ expect(spec.required_ruby_version.to_s).to eq(">= 3.1")
42
+ expect(spec.required_rubygems_version.to_s).to eq(">= 3.0")
43
+ end
44
+
45
+ it "still raises on a genuinely malformed (non-empty) checksum" do
46
+ expect { build_spec([["checksum", ["not-a-valid-digest"]]]) }
47
+ .to raise_error(Bundler::GemspecError)
48
+ end
49
+ end
@@ -21,6 +21,7 @@ $LOAD_PATH.unshift(File.expand_path("../../spec_helpers", __dir__))
21
21
  require "definition_ruby_version_patch"
22
22
  require "definition_bundler_version_patch"
23
23
  require "git_source_patch"
24
+ require "endpoint_specification_metadata_patch"
24
25
 
25
26
  require "functions"
26
27
 
@@ -72,6 +72,15 @@ module Functions
72
72
  lockfile_specs.include?(spec)
73
73
  end.map(&:name).uniq
74
74
 
75
+ cache_path = Bundler.app_cache
76
+
77
+ # Snapshot the gems already vendored in the repo before we re-cache.
78
+ # `cache_all_platforms` re-fetches every platform variant of every gem,
79
+ # which adds gem files for platforms the repo may never have vendored.
80
+ # We only want to add platform variants for gems this update actually
81
+ # changed, so anything else newly added is reverted below.
82
+ pre_existing_gems = Dir["#{cache_path}/*.gem"]
83
+
75
84
  bundler_opts = {
76
85
  cache_all: true,
77
86
  cache_all_platforms: true,
@@ -84,10 +93,30 @@ module Functions
84
93
 
85
94
  # Only prune updated gems (the original implementation is in
86
95
  # Bundler::Runtime)
87
- cache_path = Bundler.app_cache
88
96
  prune_gem_cache(resolve, cache_path, updated_gems)
89
97
  prune_git_and_path_cache(resolve, cache_path)
90
98
  end
99
+
100
+ # Revert gem files newly added by the all-platforms re-cache that belong
101
+ # to dependencies this update didn't touch. Without this a single-gem
102
+ # update re-vendors missing platform variants for *every* gem, producing
103
+ # large diffs unrelated to the update on repos that don't vendor every
104
+ # platform.
105
+ prune_unrequested_gem_additions(cache_path, pre_existing_gems, updated_gems)
106
+ end
107
+
108
+ # Removes gem files added by the all-platforms re-cache that were not
109
+ # present before and don't belong to an updated dependency (including
110
+ # sub-dependencies). Pre-existing vendored gems are always left untouched.
111
+ def prune_unrequested_gem_additions(cache_path, pre_existing_gems, updated_gems)
112
+ Dir["#{cache_path}/*.gem"].each do |path|
113
+ next if pre_existing_gems.include?(path)
114
+
115
+ spec = Bundler.rubygems.spec_from_gem(path)
116
+ next if updated_gems.include?(spec.name)
117
+
118
+ File.delete(path)
119
+ end
91
120
  end
92
121
 
93
122
  # Copied from Bundler::Runtime: Modified to only prune gems that have
@@ -8,6 +8,7 @@ require "uri"
8
8
  require "dependabot/bundler/update_checker"
9
9
  require "dependabot/bundler/native_helpers"
10
10
  require "dependabot/bundler/helpers"
11
+ require "dependabot/logger"
11
12
  require "dependabot/registry_client"
12
13
  require "dependabot/shared_helpers"
13
14
  require "dependabot/errors"
@@ -41,9 +42,11 @@ module Dependabot
41
42
  # Raised by Bundler when a registry's compact index (`/info/<gem>`) returns
42
43
  # gem metadata it can't parse (e.g. an illformed `ruby:`/`rubygems:`
43
44
  # requirement). This means the *registry* served bad data, not that the
44
- # user's dependency files are broken.
45
+ # user's dependency files are broken. The trailing `detail` capture keeps
46
+ # Bundler's own explanation (e.g. `Illformed requirement [...]`) so the
47
+ # exact parse failure is preserved rather than discarded.
45
48
  REGISTRY_METADATA_ERROR_REGEX =
46
- /error parsing the metadata for the gem (?<gem>\S+) \((?<version>[^)]+)\)/
49
+ /error parsing the metadata for the gem (?<gem>\S+) \((?<version>[^)]+)\):?\s*(?<detail>.*)/m
47
50
 
48
51
  module BundlerErrorPatterns
49
52
  MISSING_AUTH_REGEX = /bundle config set --global (?<source>.*) username:password/
@@ -217,8 +220,22 @@ module Dependabot
217
220
  source = private_registry_source
218
221
  return nil unless source
219
222
 
223
+ # Bundler's original message identifies which gem/version the registry
224
+ # served unparseable metadata for, and why (e.g. the illformed
225
+ # requirement string). The structured job error only records the source
226
+ # host, so log the full message here to keep the offending gem
227
+ # diagnosable from the updater logs.
228
+ Dependabot.logger.error(
229
+ "Registry #{source} returned unparseable compact-index metadata for " \
230
+ "#{match[:gem]} (#{match[:version]}); raising PrivateSourceBadResponse. " \
231
+ "Original Bundler error: #{error.message.strip}"
232
+ )
233
+
234
+ parse_detail = match[:detail].to_s.strip.gsub(/\s*\n\s*/, "; ")
220
235
  detail = "Invalid gem metadata returned for #{match[:gem]} (#{match[:version]}) " \
221
236
  "by the source: #{source}"
237
+ detail += " (#{parse_detail})" unless parse_detail.empty?
238
+
222
239
  Dependabot::PrivateSourceBadResponse.new(source, detail)
223
240
  end
224
241
 
@@ -255,10 +255,8 @@ module Dependabot
255
255
  # If the dependency is pinned to a tag that looks like a version then
256
256
  # we want to update that tag. The latest version will then be the SHA
257
257
  # of the latest tag that looks like a version.
258
- if git_commit_checker.pinned_ref_looks_like_version?
259
- latest_tag = git_commit_checker.local_tag_for_latest_version
260
- return latest_tag&.fetch(:tag_sha) || dependency.version
261
- end
258
+ latest_tag = git_commit_checker.local_tag_for_pinned_version_ref(update_cooldown)
259
+ return latest_tag.fetch(:tag_sha) || dependency.version if latest_tag
262
260
 
263
261
  # If the dependency is pinned to a tag that doesn't look like a
264
262
  # version then there's nothing we can do.
@@ -280,9 +278,8 @@ module Dependabot
280
278
  # If the dependency is pinned to a tag that looks like a version then
281
279
  # we want to update that tag. The latest version will then be the SHA
282
280
  # of the latest tag that looks like a version.
283
- if git_commit_checker.pinned_ref_looks_like_version? &&
284
- latest_git_tag_is_resolvable?
285
- new_tag = git_commit_checker.local_tag_for_latest_version
281
+ if latest_git_tag_is_resolvable?
282
+ new_tag = git_commit_checker.local_tag_for_pinned_version_ref(update_cooldown)
286
283
  return new_tag&.fetch(:tag_sha)
287
284
  end
288
285
 
@@ -317,7 +314,7 @@ module Dependabot
317
314
 
318
315
  sig { returns(T::Boolean) }
319
316
  def latest_git_tag_is_resolvable?
320
- latest_tag_details = git_commit_checker.local_tag_for_latest_version
317
+ latest_tag_details = git_commit_checker.local_tag_for_pinned_version_ref(update_cooldown)
321
318
  return false unless latest_tag_details
322
319
 
323
320
  git_tag_resolvable?(latest_tag_details.fetch(:tag))
@@ -336,9 +333,8 @@ module Dependabot
336
333
  return dependency_source_details unless git_dependency?
337
334
 
338
335
  # Update the git tag if updating a pinned version
339
- if git_commit_checker.pinned_ref_looks_like_version? &&
340
- latest_git_tag_is_resolvable?
341
- new_tag = git_commit_checker.local_tag_for_latest_version
336
+ if latest_git_tag_is_resolvable?
337
+ new_tag = git_commit_checker.local_tag_for_pinned_version_ref(update_cooldown)
342
338
  return T.must(dependency_source_details).merge(ref: T.must(new_tag).fetch(:tag))
343
339
  end
344
340
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dependabot-bundler
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.384.0
4
+ version: 0.386.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dependabot
@@ -15,14 +15,14 @@ dependencies:
15
15
  requirements:
16
16
  - - '='
17
17
  - !ruby/object:Gem::Version
18
- version: 0.384.0
18
+ version: 0.386.0
19
19
  type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
23
  - - '='
24
24
  - !ruby/object:Gem::Version
25
- version: 0.384.0
25
+ version: 0.386.0
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: parallel
28
28
  requirement: !ruby/object:Gem::Requirement
@@ -269,8 +269,10 @@ files:
269
269
  - helpers/v2/lib/functions/version_resolver.rb
270
270
  - helpers/v2/monkey_patches/definition_bundler_version_patch.rb
271
271
  - helpers/v2/monkey_patches/definition_ruby_version_patch.rb
272
+ - helpers/v2/monkey_patches/endpoint_specification_metadata_patch.rb
272
273
  - helpers/v2/monkey_patches/git_source_patch.rb
273
274
  - helpers/v2/run.rb
275
+ - helpers/v2/spec/bundler_endpoint_specification_metadata_patch_spec.rb
274
276
  - helpers/v2/spec/bundler_version_constraint_spec.rb
275
277
  - helpers/v2/spec/functions/conflicting_dependency_resolver_spec.rb
276
278
  - helpers/v2/spec/functions/dependency_source_spec.rb
@@ -351,7 +353,7 @@ licenses:
351
353
  - MIT
352
354
  metadata:
353
355
  bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
354
- changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.384.0
356
+ changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.386.0
355
357
  rdoc_options: []
356
358
  require_paths:
357
359
  - lib