dependabot-bundler 0.280.0 → 0.281.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/dependabot/bundler/helpers.rb +1 -13
- data/lib/dependabot/bundler/package_manager.rb +6 -6
- data/lib/dependabot/bundler/update_checker/shared_bundler_helpers.rb +1 -2
- metadata +8 -33
- data/helpers/v1/.gitignore +0 -8
- data/helpers/v1/Gemfile +0 -7
- data/helpers/v1/build +0 -29
- data/helpers/v1/lib/functions/conflicting_dependency_resolver.rb +0 -89
- data/helpers/v1/lib/functions/dependency_source.rb +0 -90
- data/helpers/v1/lib/functions/file_parser.rb +0 -119
- data/helpers/v1/lib/functions/force_updater.rb +0 -173
- data/helpers/v1/lib/functions/lockfile_updater.rb +0 -218
- data/helpers/v1/lib/functions/version_resolver.rb +0 -141
- data/helpers/v1/lib/functions.rb +0 -172
- data/helpers/v1/monkey_patches/definition_bundler_version_patch.rb +0 -16
- data/helpers/v1/monkey_patches/definition_ruby_version_patch.rb +0 -22
- data/helpers/v1/monkey_patches/fileutils_keyword_splat_patch.rb +0 -20
- data/helpers/v1/monkey_patches/git_source_patch.rb +0 -62
- data/helpers/v1/monkey_patches/object_untaint_patch.rb +0 -17
- data/helpers/v1/monkey_patches/resolver_spec_group_sane_eql.rb +0 -18
- data/helpers/v1/patched_bundler +0 -34
- data/helpers/v1/run.rb +0 -38
- data/helpers/v1/spec/functions/conflicting_dependency_resolver_spec.rb +0 -118
- data/helpers/v1/spec/functions/dependency_source_spec.rb +0 -188
- data/helpers/v1/spec/functions/file_parser_spec.rb +0 -75
- data/helpers/v1/spec/functions/force_updater_spec.rb +0 -59
- data/helpers/v1/spec/functions/version_resolver_spec.rb +0 -105
- data/helpers/v1/spec/native_spec_helper.rb +0 -56
- data/helpers/v1/spec/shared_contexts.rb +0 -60
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ced4096906c6340adbf69f1a72b3c84069622b1bf0c1e249a02419baae29b0c2
|
4
|
+
data.tar.gz: dc9d382839349a530ff0677c03791ebfa1b8e1013a72b93d9bb61677dc3a914d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b1e2d121706fcc5fcbc097677b64c3800741ff124ad92f0c6c49e0a5c233723a3a06a7302128072b128f69aea7618235c4ea67657b4d0e33a89654a7bc223477
|
7
|
+
data.tar.gz: 46e5908f2d55e1a315ba940fc1da53209354474c83c2b5e93f8dfb15452b83410aeaf8482c75ff9fcf955b93a562ca1bbc2d92ba66a0b104c462678d3edbf5d8
|
@@ -20,23 +20,11 @@ module Dependabot
|
|
20
20
|
|
21
21
|
if (matches = lockfile.content&.match(BUNDLER_MAJOR_VERSION_REGEX))
|
22
22
|
matches[:version].to_i >= 2 ? V2 : V1
|
23
|
-
elsif Dependabot::Experiments.enabled?(:bundler_v1_unsupported_error)
|
24
|
-
DEFAULT
|
25
23
|
else
|
26
|
-
|
24
|
+
DEFAULT
|
27
25
|
end
|
28
26
|
end
|
29
27
|
|
30
|
-
# If we are updating a project with a Gemfile.lock that does not specify
|
31
|
-
# the version it was bundled with, we failover to V1 on the assumption
|
32
|
-
# it was created with an old version that didn't add this information
|
33
|
-
sig { returns(String) }
|
34
|
-
def self.failover_version
|
35
|
-
return V2 if Dependabot::Experiments.enabled?(:bundler_v1_unsupported_error)
|
36
|
-
|
37
|
-
V1
|
38
|
-
end
|
39
|
-
|
40
28
|
sig { params(lockfile: T.nilable(Dependabot::DependencyFile)).returns(String) }
|
41
29
|
def self.detected_bundler_version(lockfile)
|
42
30
|
return "unknown" unless lockfile
|
@@ -12,9 +12,11 @@ module Dependabot
|
|
12
12
|
# Keep versions in ascending order
|
13
13
|
SUPPORTED_BUNDLER_VERSIONS = T.let([Version.new("2")].freeze, T::Array[Dependabot::Version])
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
|
15
|
+
# Currently, we don't support any deprecated versions of Bundler
|
16
|
+
# When a version is going to be unsupported, it will be added here for a while to give users time to upgrade
|
17
|
+
# Example for deprecation:
|
18
|
+
# DEPRECATED_BUNDLER_VERSIONS = T.let([Version.new("1")].freeze, T::Array[Dependabot::Version])
|
19
|
+
DEPRECATED_BUNDLER_VERSIONS = T.let([].freeze, T::Array[Dependabot::Version])
|
18
20
|
|
19
21
|
class PackageManager < PackageManagerBase
|
20
22
|
extend T::Sig
|
@@ -41,9 +43,7 @@ module Dependabot
|
|
41
43
|
|
42
44
|
sig { override.returns(T::Boolean) }
|
43
45
|
def unsupported?
|
44
|
-
# Check if the
|
45
|
-
return false unless Dependabot::Experiments.enabled?(:bundler_v1_unsupported_error)
|
46
|
-
|
46
|
+
# Check if the version is not supported
|
47
47
|
supported_versions.all? { |supported| supported > version }
|
48
48
|
end
|
49
49
|
end
|
@@ -31,8 +31,7 @@ module Dependabot
|
|
31
31
|
PATH_REGEX = /The path `(?<path>.*)` does not exist/
|
32
32
|
|
33
33
|
module BundlerErrorPatterns
|
34
|
-
|
35
|
-
MISSING_AUTH_REGEX = /bundle config (?:set --global )?(?<source>.*) username:password/
|
34
|
+
MISSING_AUTH_REGEX = /bundle config set --global (?<source>.*) username:password/
|
36
35
|
|
37
36
|
BAD_AUTH_REGEX = /Bad username or password for (?<source>.*)\.$/
|
38
37
|
FORBIDDEN_AUTH_REGEX = /Access token could not be authenticated for (?<source>.*)\.$/
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dependabot-bundler
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.281.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dependabot
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-10-
|
11
|
+
date: 2024-10-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: dependabot-common
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - '='
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 0.
|
19
|
+
version: 0.281.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - '='
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 0.
|
26
|
+
version: 0.281.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: parallel
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -257,31 +257,6 @@ extensions: []
|
|
257
257
|
extra_rdoc_files: []
|
258
258
|
files:
|
259
259
|
- helpers/spec_helpers/gem_net_http_adapter.rb
|
260
|
-
- helpers/v1/.gitignore
|
261
|
-
- helpers/v1/Gemfile
|
262
|
-
- helpers/v1/build
|
263
|
-
- helpers/v1/lib/functions.rb
|
264
|
-
- helpers/v1/lib/functions/conflicting_dependency_resolver.rb
|
265
|
-
- helpers/v1/lib/functions/dependency_source.rb
|
266
|
-
- helpers/v1/lib/functions/file_parser.rb
|
267
|
-
- helpers/v1/lib/functions/force_updater.rb
|
268
|
-
- helpers/v1/lib/functions/lockfile_updater.rb
|
269
|
-
- helpers/v1/lib/functions/version_resolver.rb
|
270
|
-
- helpers/v1/monkey_patches/definition_bundler_version_patch.rb
|
271
|
-
- helpers/v1/monkey_patches/definition_ruby_version_patch.rb
|
272
|
-
- helpers/v1/monkey_patches/fileutils_keyword_splat_patch.rb
|
273
|
-
- helpers/v1/monkey_patches/git_source_patch.rb
|
274
|
-
- helpers/v1/monkey_patches/object_untaint_patch.rb
|
275
|
-
- helpers/v1/monkey_patches/resolver_spec_group_sane_eql.rb
|
276
|
-
- helpers/v1/patched_bundler
|
277
|
-
- helpers/v1/run.rb
|
278
|
-
- helpers/v1/spec/functions/conflicting_dependency_resolver_spec.rb
|
279
|
-
- helpers/v1/spec/functions/dependency_source_spec.rb
|
280
|
-
- helpers/v1/spec/functions/file_parser_spec.rb
|
281
|
-
- helpers/v1/spec/functions/force_updater_spec.rb
|
282
|
-
- helpers/v1/spec/functions/version_resolver_spec.rb
|
283
|
-
- helpers/v1/spec/native_spec_helper.rb
|
284
|
-
- helpers/v1/spec/shared_contexts.rb
|
285
260
|
- helpers/v2/.gitignore
|
286
261
|
- helpers/v2/Gemfile
|
287
262
|
- helpers/v2/build
|
@@ -346,8 +321,8 @@ licenses:
|
|
346
321
|
- MIT
|
347
322
|
metadata:
|
348
323
|
bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
|
349
|
-
changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.
|
350
|
-
post_install_message:
|
324
|
+
changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.281.0
|
325
|
+
post_install_message:
|
351
326
|
rdoc_options: []
|
352
327
|
require_paths:
|
353
328
|
- lib
|
@@ -363,7 +338,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
363
338
|
version: 3.1.0
|
364
339
|
requirements: []
|
365
340
|
rubygems_version: 3.5.9
|
366
|
-
signing_key:
|
341
|
+
signing_key:
|
367
342
|
specification_version: 4
|
368
343
|
summary: Provides Dependabot support for Ruby (bundler)
|
369
344
|
test_files: []
|
data/helpers/v1/.gitignore
DELETED
data/helpers/v1/Gemfile
DELETED
data/helpers/v1/build
DELETED
@@ -1,29 +0,0 @@
|
|
1
|
-
#!/usr/bin/env bash
|
2
|
-
|
3
|
-
set -e
|
4
|
-
|
5
|
-
helpers_dir=$(cd -P "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
6
|
-
|
7
|
-
if [ -z "$DEPENDABOT_NATIVE_HELPERS_PATH" ]; then
|
8
|
-
install_dir="$helpers_dir"
|
9
|
-
else
|
10
|
-
install_dir="$DEPENDABOT_NATIVE_HELPERS_PATH/bundler/v1"
|
11
|
-
mkdir -p "$install_dir"
|
12
|
-
|
13
|
-
cp -r \
|
14
|
-
"$helpers_dir/lib" \
|
15
|
-
"$helpers_dir/monkey_patches" \
|
16
|
-
"$helpers_dir/run.rb" \
|
17
|
-
"$helpers_dir/patched_bundler" \
|
18
|
-
"$install_dir"
|
19
|
-
fi
|
20
|
-
|
21
|
-
cd "$install_dir"
|
22
|
-
|
23
|
-
export GEM_HOME=$install_dir/.bundle
|
24
|
-
|
25
|
-
gem install bundler -v 1.17.3 --no-document
|
26
|
-
|
27
|
-
if [ -z "$DEPENDABOT_NATIVE_HELPERS_PATH" ]; then
|
28
|
-
BUNDLER_VERSION=1.17.3 ./patched_bundler install
|
29
|
-
fi
|
@@ -1,89 +0,0 @@
|
|
1
|
-
# typed: true
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
module Functions
|
5
|
-
class ConflictingDependencyResolver
|
6
|
-
def initialize(dependency_name:, target_version:, lockfile_name:)
|
7
|
-
@dependency_name = dependency_name
|
8
|
-
@target_version = target_version
|
9
|
-
@lockfile_name = lockfile_name
|
10
|
-
end
|
11
|
-
|
12
|
-
# Finds any dependencies in the lockfile that have a subdependency on the
|
13
|
-
# given dependency that does not satisfly the target_version.
|
14
|
-
# @return [Array<Hash{String => String}]
|
15
|
-
# * explanation [String] a sentence explaining the conflict
|
16
|
-
# * name [String] the blocking dependencies name
|
17
|
-
# * version [String] the version of the blocking dependency
|
18
|
-
# * requirement [String] the requirement on the target_dependency
|
19
|
-
def conflicting_dependencies
|
20
|
-
Bundler.settings.set_command_option("only_update_to_newer_versions", true)
|
21
|
-
|
22
|
-
parent_specs.flat_map do |parent_spec|
|
23
|
-
top_level_specs_for(parent_spec).map do |top_level|
|
24
|
-
dependency = parent_spec.dependencies.find { |bd| bd.name == dependency_name }
|
25
|
-
{
|
26
|
-
"explanation" => explanation(parent_spec, dependency, top_level),
|
27
|
-
"name" => parent_spec.name,
|
28
|
-
"version" => parent_spec.version.to_s,
|
29
|
-
"requirement" => dependency.requirement.to_s
|
30
|
-
}
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
private
|
36
|
-
|
37
|
-
attr_reader :dependency_name
|
38
|
-
attr_reader :target_version
|
39
|
-
attr_reader :lockfile_name
|
40
|
-
|
41
|
-
def parent_specs
|
42
|
-
version = Gem::Version.new(target_version)
|
43
|
-
parsed_lockfile.specs.filter do |spec|
|
44
|
-
spec.dependencies.any? do |dep|
|
45
|
-
dep.name == dependency_name &&
|
46
|
-
!dep.requirement.satisfied_by?(version)
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
def top_level_specs_for(parent_spec)
|
52
|
-
return [parent_spec] if top_level?(parent_spec)
|
53
|
-
|
54
|
-
parsed_lockfile.specs.filter do |spec|
|
55
|
-
spec.dependencies.any? do |dep|
|
56
|
-
dep.name == parent_spec.name && top_level?(spec)
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
def top_level?(spec)
|
62
|
-
parsed_lockfile.dependencies.key?(spec.name)
|
63
|
-
end
|
64
|
-
|
65
|
-
def explanation(spec, dependency, top_level)
|
66
|
-
if spec.name == top_level.name
|
67
|
-
"#{spec.name} (#{spec.version}) requires #{dependency_name} (#{dependency.requirement})"
|
68
|
-
else
|
69
|
-
"#{top_level.name} (#{top_level.version}) requires #{dependency_name} " \
|
70
|
-
"(#{dependency.requirement}) via #{spec.name} (#{spec.version})"
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
def parsed_lockfile
|
75
|
-
@parsed_lockfile ||= Bundler::LockfileParser.new(lockfile)
|
76
|
-
end
|
77
|
-
|
78
|
-
def lockfile
|
79
|
-
return @lockfile if defined?(@lockfile)
|
80
|
-
|
81
|
-
@lockfile =
|
82
|
-
begin
|
83
|
-
return unless lockfile_name && File.exist?(lockfile_name)
|
84
|
-
|
85
|
-
File.read(lockfile_name)
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
@@ -1,90 +0,0 @@
|
|
1
|
-
# typed: true
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
module Functions
|
5
|
-
class DependencySource
|
6
|
-
attr_reader :gemfile_name
|
7
|
-
attr_reader :dependency_name
|
8
|
-
|
9
|
-
RUBYGEMS = "rubygems"
|
10
|
-
PRIVATE_REGISTRY = "private"
|
11
|
-
GIT = "git"
|
12
|
-
OTHER = "other"
|
13
|
-
|
14
|
-
def initialize(gemfile_name:, dependency_name:)
|
15
|
-
@gemfile_name = gemfile_name
|
16
|
-
@dependency_name = dependency_name
|
17
|
-
end
|
18
|
-
|
19
|
-
def type
|
20
|
-
bundler_source = specified_source || default_source
|
21
|
-
type_of(bundler_source)
|
22
|
-
end
|
23
|
-
|
24
|
-
def latest_git_version(dependency_source_url:, dependency_source_branch:)
|
25
|
-
source = Bundler::Source::Git.new(
|
26
|
-
"uri" => dependency_source_url,
|
27
|
-
"branch" => dependency_source_branch,
|
28
|
-
"name" => dependency_name,
|
29
|
-
"submodules" => true
|
30
|
-
)
|
31
|
-
|
32
|
-
# Tell Bundler we're fine with fetching the source remotely
|
33
|
-
source.instance_variable_set(:@allow_remote, true)
|
34
|
-
|
35
|
-
spec = source.specs.first
|
36
|
-
{ version: spec.version, commit_sha: spec.source.revision }
|
37
|
-
end
|
38
|
-
|
39
|
-
def private_registry_versions
|
40
|
-
bundler_source = specified_source || default_source
|
41
|
-
|
42
|
-
bundler_source
|
43
|
-
.fetchers.flat_map do |fetcher|
|
44
|
-
fetcher
|
45
|
-
.specs_with_retry([dependency_name], bundler_source)
|
46
|
-
.search_all(dependency_name)
|
47
|
-
end
|
48
|
-
.map(&:version)
|
49
|
-
end
|
50
|
-
|
51
|
-
private
|
52
|
-
|
53
|
-
def type_of(bundler_source)
|
54
|
-
case bundler_source
|
55
|
-
when Bundler::Source::Rubygems
|
56
|
-
remote = bundler_source.remotes.first
|
57
|
-
if remote.nil? || remote.to_s == "https://rubygems.org/"
|
58
|
-
RUBYGEMS
|
59
|
-
else
|
60
|
-
PRIVATE_REGISTRY
|
61
|
-
end
|
62
|
-
when Bundler::Source::Git
|
63
|
-
GIT
|
64
|
-
else
|
65
|
-
OTHER
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
def specified_source
|
70
|
-
return @specified_source if defined? @specified_source
|
71
|
-
|
72
|
-
@specified_source = definition.dependencies
|
73
|
-
.find { |dep| dep.name == dependency_name }&.source
|
74
|
-
end
|
75
|
-
|
76
|
-
def default_source
|
77
|
-
definition.send(:sources).default_source
|
78
|
-
end
|
79
|
-
|
80
|
-
def definition
|
81
|
-
@definition ||= Bundler::Definition.build(gemfile_name, nil, {})
|
82
|
-
end
|
83
|
-
|
84
|
-
def serialize_bundler_source(source)
|
85
|
-
{
|
86
|
-
type: source.class.to_s
|
87
|
-
}
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|
@@ -1,119 +0,0 @@
|
|
1
|
-
# typed: true
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
require "uri"
|
5
|
-
|
6
|
-
module Functions
|
7
|
-
class FileParser
|
8
|
-
def initialize(lockfile_name:)
|
9
|
-
@lockfile_name = lockfile_name
|
10
|
-
end
|
11
|
-
|
12
|
-
attr_reader :lockfile_name
|
13
|
-
|
14
|
-
def parsed_gemfile(gemfile_name:)
|
15
|
-
Bundler::Definition.build(gemfile_name, nil, {})
|
16
|
-
.dependencies.select(&:current_platform?)
|
17
|
-
.reject { |dep| local_sources.include?(dep.source.class) }
|
18
|
-
.map { |dep| serialize_bundler_dependency(dep) }
|
19
|
-
end
|
20
|
-
|
21
|
-
def parsed_gemspec(gemspec_name:)
|
22
|
-
Bundler.load_gemspec_uncached(gemspec_name)
|
23
|
-
.dependencies
|
24
|
-
.map { |dep| serialize_bundler_dependency(dep) }
|
25
|
-
end
|
26
|
-
|
27
|
-
private
|
28
|
-
|
29
|
-
def lockfile
|
30
|
-
return @lockfile if defined?(@lockfile)
|
31
|
-
|
32
|
-
@lockfile =
|
33
|
-
begin
|
34
|
-
return unless lockfile_name && File.exist?(lockfile_name)
|
35
|
-
|
36
|
-
File.read(lockfile_name)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
def parsed_lockfile
|
41
|
-
return unless lockfile
|
42
|
-
|
43
|
-
@parsed_lockfile ||= Bundler::LockfileParser.new(lockfile)
|
44
|
-
end
|
45
|
-
|
46
|
-
def source_from_lockfile(dependency_name)
|
47
|
-
parsed_lockfile&.specs&.find { |s| s.name == dependency_name }&.source
|
48
|
-
end
|
49
|
-
|
50
|
-
def source_for(dependency)
|
51
|
-
source = dependency.source
|
52
|
-
if lockfile && default_rubygems?(source)
|
53
|
-
# If there's a lockfile and the Gemfile doesn't have anything
|
54
|
-
# interesting to say about the source, check that.
|
55
|
-
source = source_from_lockfile(dependency.name)
|
56
|
-
end
|
57
|
-
raise "Bad source: #{source}" unless sources.include?(source.class)
|
58
|
-
|
59
|
-
return nil if default_rubygems?(source)
|
60
|
-
|
61
|
-
details = { type: source.class.name.split("::").last.downcase }
|
62
|
-
details.merge!(git_source_details(source)) if source.is_a?(Bundler::Source::Git)
|
63
|
-
details[:url] = source.remotes.first.to_s if source.is_a?(Bundler::Source::Rubygems)
|
64
|
-
details
|
65
|
-
end
|
66
|
-
|
67
|
-
def git_source_details(source)
|
68
|
-
{
|
69
|
-
url: source.uri,
|
70
|
-
branch: source.branch,
|
71
|
-
ref: source.ref
|
72
|
-
}
|
73
|
-
end
|
74
|
-
|
75
|
-
RUBYGEMS_HOSTS = [
|
76
|
-
"rubygems.org",
|
77
|
-
"www.rubygems.org"
|
78
|
-
].freeze
|
79
|
-
|
80
|
-
def default_rubygems?(source)
|
81
|
-
return true if source.nil?
|
82
|
-
return false unless source.is_a?(Bundler::Source::Rubygems)
|
83
|
-
|
84
|
-
source.remotes.any? do |r|
|
85
|
-
RUBYGEMS_HOSTS.include?(URI(r.to_s).host)
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
def serialize_bundler_dependency(dependency)
|
90
|
-
{
|
91
|
-
name: dependency.name,
|
92
|
-
requirement: dependency.requirement,
|
93
|
-
groups: dependency.groups,
|
94
|
-
source: source_for(dependency),
|
95
|
-
type: dependency.type
|
96
|
-
}
|
97
|
-
end
|
98
|
-
|
99
|
-
# Can't be a constant because some of these don't exist in bundler
|
100
|
-
# 1.15, which used to cause issues on Heroku (causing exception on boot).
|
101
|
-
# TODO: Check if this will be an issue with multiple bundler versions
|
102
|
-
def sources
|
103
|
-
[
|
104
|
-
NilClass,
|
105
|
-
Bundler::Source::Rubygems,
|
106
|
-
Bundler::Source::Git,
|
107
|
-
*local_sources,
|
108
|
-
Bundler::Source::Metadata
|
109
|
-
]
|
110
|
-
end
|
111
|
-
|
112
|
-
def local_sources
|
113
|
-
[
|
114
|
-
Bundler::Source::Path,
|
115
|
-
Bundler::Source::Gemspec
|
116
|
-
]
|
117
|
-
end
|
118
|
-
end
|
119
|
-
end
|
@@ -1,173 +0,0 @@
|
|
1
|
-
# typed: true
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
module Functions
|
5
|
-
class ForceUpdater
|
6
|
-
class TransitiveDependencyError < StandardError; end
|
7
|
-
|
8
|
-
def initialize(dependency_name:, target_version:, gemfile_name:,
|
9
|
-
lockfile_name:, update_multiple_dependencies:)
|
10
|
-
@dependency_name = dependency_name
|
11
|
-
@target_version = target_version
|
12
|
-
@gemfile_name = gemfile_name
|
13
|
-
@lockfile_name = lockfile_name
|
14
|
-
@update_multiple_dependencies = update_multiple_dependencies
|
15
|
-
end
|
16
|
-
|
17
|
-
def run
|
18
|
-
# Only allow upgrades. Otherwise it's unlikely that this
|
19
|
-
# resolution will be found by the FileUpdater
|
20
|
-
Bundler.settings.set_command_option(
|
21
|
-
"only_update_to_newer_versions",
|
22
|
-
true
|
23
|
-
)
|
24
|
-
|
25
|
-
dependencies_to_unlock = []
|
26
|
-
|
27
|
-
begin
|
28
|
-
definition = build_definition(dependencies_to_unlock: dependencies_to_unlock)
|
29
|
-
definition.resolve_remotely!
|
30
|
-
specs = definition.resolve
|
31
|
-
updates = [{ name: dependency_name }] +
|
32
|
-
dependencies_to_unlock.map { |dep| { name: dep.name } }
|
33
|
-
specs = specs.map do |dep|
|
34
|
-
{
|
35
|
-
name: dep.name,
|
36
|
-
version: dep.version
|
37
|
-
}
|
38
|
-
end
|
39
|
-
[updates, specs]
|
40
|
-
rescue Bundler::VersionConflict => e
|
41
|
-
raise unless update_multiple_dependencies?
|
42
|
-
|
43
|
-
# TODO: Not sure this won't unlock way too many things...
|
44
|
-
new_dependencies_to_unlock =
|
45
|
-
new_dependencies_to_unlock_from(
|
46
|
-
error: e,
|
47
|
-
already_unlocked: dependencies_to_unlock
|
48
|
-
)
|
49
|
-
|
50
|
-
raise if new_dependencies_to_unlock.none?
|
51
|
-
|
52
|
-
dependencies_to_unlock += new_dependencies_to_unlock
|
53
|
-
retry
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
private
|
58
|
-
|
59
|
-
attr_reader :dependency_name
|
60
|
-
attr_reader :target_version
|
61
|
-
attr_reader :gemfile_name
|
62
|
-
attr_reader :lockfile_name
|
63
|
-
attr_reader :credentials
|
64
|
-
attr_reader :update_multiple_dependencies
|
65
|
-
alias update_multiple_dependencies? update_multiple_dependencies
|
66
|
-
|
67
|
-
def new_dependencies_to_unlock_from(error:, already_unlocked:)
|
68
|
-
potentials_deps =
|
69
|
-
relevant_conflicts(error, already_unlocked)
|
70
|
-
.flat_map(&:requirement_trees)
|
71
|
-
.reject do |tree|
|
72
|
-
# If the final requirement wasn't specific, it can't be binding
|
73
|
-
next true if tree.last.requirement == Gem::Requirement.new(">= 0")
|
74
|
-
|
75
|
-
# If the conflict wasn't for the dependency we're updating then
|
76
|
-
# we don't have enough info to reject it
|
77
|
-
next false unless tree.last.name == dependency_name
|
78
|
-
|
79
|
-
# If the final requirement *was* for the dependency we're updating
|
80
|
-
# then we can ignore the tree if it permits the target version
|
81
|
-
tree.last.requirement.satisfied_by?(
|
82
|
-
Gem::Version.new(target_version)
|
83
|
-
)
|
84
|
-
end.map(&:first)
|
85
|
-
|
86
|
-
potentials_deps
|
87
|
-
.reject { |dep| already_unlocked.map(&:name).include?(dep.name) }
|
88
|
-
.reject { |dep| [dependency_name, "ruby\0"].include?(dep.name) }
|
89
|
-
.uniq
|
90
|
-
end
|
91
|
-
|
92
|
-
def relevant_conflicts(error, dependencies_being_unlocked)
|
93
|
-
names = [*dependencies_being_unlocked.map(&:name), dependency_name]
|
94
|
-
|
95
|
-
# For a conflict to be relevant to the updates we're making it must be
|
96
|
-
# 1) caused by a new requirement introduced by our unlocking, or
|
97
|
-
# 2) caused by an old requirement that prohibits the update.
|
98
|
-
# Hence, we look at the beginning and end of the requirement trees
|
99
|
-
error.cause.conflicts.values
|
100
|
-
.select do |conflict|
|
101
|
-
conflict.requirement_trees.any? do |t|
|
102
|
-
names.include?(t.last.name) || names.include?(t.first.name)
|
103
|
-
end
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
def build_definition(dependencies_to_unlock:)
|
108
|
-
gems_to_unlock = dependencies_to_unlock.map(&:name) + [dependency_name]
|
109
|
-
definition = Bundler::Definition.build(
|
110
|
-
gemfile_name,
|
111
|
-
lockfile_name,
|
112
|
-
gems: gems_to_unlock + subdependencies,
|
113
|
-
lock_shared_dependencies: true
|
114
|
-
)
|
115
|
-
|
116
|
-
# Remove the Gemfile / gemspec requirements on the gems we're
|
117
|
-
# unlocking (i.e., completely unlock them)
|
118
|
-
gems_to_unlock.each do |gem_name|
|
119
|
-
unlock_gem(definition: definition, gem_name: gem_name)
|
120
|
-
end
|
121
|
-
|
122
|
-
dep = definition.dependencies
|
123
|
-
.find { |d| d.name == dependency_name }
|
124
|
-
|
125
|
-
# If the dependency is not found in the Gemfile it means this is a
|
126
|
-
# transitive dependency that we can't force update.
|
127
|
-
raise TransitiveDependencyError unless dep
|
128
|
-
|
129
|
-
# Set the requirement for the gem we're forcing an update of
|
130
|
-
new_req = Gem::Requirement.create("= #{target_version}")
|
131
|
-
dep.instance_variable_set(:@requirement, new_req)
|
132
|
-
dep.source = nil if dep.source.is_a?(Bundler::Source::Git)
|
133
|
-
|
134
|
-
definition
|
135
|
-
end
|
136
|
-
|
137
|
-
def lockfile
|
138
|
-
return @lockfile if defined?(@lockfile)
|
139
|
-
|
140
|
-
@lockfile =
|
141
|
-
begin
|
142
|
-
return unless lockfile_name && File.exist?(lockfile_name)
|
143
|
-
|
144
|
-
File.read(lockfile_name)
|
145
|
-
end
|
146
|
-
end
|
147
|
-
|
148
|
-
def subdependencies
|
149
|
-
# If there's no lockfile we don't need to worry about
|
150
|
-
# subdependencies
|
151
|
-
return [] unless lockfile
|
152
|
-
|
153
|
-
all_deps = Bundler::LockfileParser.new(lockfile)
|
154
|
-
.specs.map { |x| x.name.to_s }
|
155
|
-
top_level = Bundler::Definition
|
156
|
-
.build(gemfile_name, lockfile_name, {})
|
157
|
-
.dependencies.map { |x| x.name.to_s }
|
158
|
-
|
159
|
-
all_deps - top_level
|
160
|
-
end
|
161
|
-
|
162
|
-
def unlock_gem(definition:, gem_name:)
|
163
|
-
dep = definition.dependencies.find { |d| d.name == gem_name }
|
164
|
-
version = definition.locked_gems.specs
|
165
|
-
.find { |d| d.name == gem_name }.version
|
166
|
-
|
167
|
-
dep&.instance_variable_set(
|
168
|
-
:@requirement,
|
169
|
-
Gem::Requirement.create(">= #{version}")
|
170
|
-
)
|
171
|
-
end
|
172
|
-
end
|
173
|
-
end
|