dependabot-bundler 0.134.1 → 0.137.1
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 +4 -4
- data/helpers/v1/.bundle/config +2 -0
- data/helpers/v1/.gitignore +2 -1
- data/helpers/v1/Gemfile +8 -12
- data/helpers/v1/build +3 -6
- data/helpers/v1/spec/functions/conflicting_dependency_resolver_spec.rb +133 -0
- data/helpers/v1/spec/functions/dependency_source_spec.rb +187 -0
- data/helpers/v1/spec/functions/file_parser_spec.rb +77 -0
- data/helpers/v1/spec/functions/version_resolver_spec.rb +97 -0
- data/helpers/v1/spec/native_spec_helper.rb +49 -0
- data/helpers/v1/spec/shared_contexts.rb +59 -0
- data/lib/dependabot/bundler/file_updater/gemspec_sanitizer.rb +26 -5
- data/lib/dependabot/bundler/native_helpers.rb +16 -20
- metadata +13 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9250fba22b9b1d480c1a2e9c9d47887fbcedc6204ef8f9a874af781b4b5e3bdf
|
4
|
+
data.tar.gz: 0ec5ea2610ce9cd805ea259234d0bf1050b0db6390ab7611201452f83f365798
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 59690230cb90627b8fce31ecdb43e17ec7a1acb4c95c417444534661106bd9a84d5dbfa2f3f3ced1f0f35cbd67be93a60204f41daac0af8d039533b4bf0f28e2
|
7
|
+
data.tar.gz: c103d732b44c9f7eb9cbbfd94d68b3c207f0b153660d2dec9588cbc1126a8bb066144ff287a28458f9fec110fe93bf28e55ff92f23dcdd9970169875c097f30c
|
data/helpers/v1/.gitignore
CHANGED
data/helpers/v1/Gemfile
CHANGED
@@ -1,16 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# TODO: Look into removing this. "find" used to get required from common's
|
4
|
-
# gemspec so we've added it here for backwards compatability during bundler 2
|
5
|
-
# rollout.
|
6
|
-
#
|
7
|
-
# NOTE: If we don't require it and a customers `.gemspec` uses Find without
|
8
|
-
# requiring it, we'll start raising a DependencyFileNotEvaluatable error which
|
9
|
-
# is probably the right thing to do
|
10
|
-
require "find"
|
11
|
-
|
12
3
|
source "https://rubygems.org"
|
13
4
|
|
14
|
-
# NOTE:
|
15
|
-
|
16
|
-
|
5
|
+
# NOTE: Used to run native helper specs
|
6
|
+
group :test do
|
7
|
+
gem "byebug", "11.1.3"
|
8
|
+
gem "rspec", "3.10.0"
|
9
|
+
gem "rspec-its", "1.3.0"
|
10
|
+
gem "vcr", "6.0.0"
|
11
|
+
gem "webmock", "3.12.1"
|
12
|
+
end
|
data/helpers/v1/build
CHANGED
@@ -8,12 +8,9 @@ if [ -z "$install_dir" ]; then
|
|
8
8
|
exit 1
|
9
9
|
fi
|
10
10
|
|
11
|
-
if [ ! -d "$install_dir" ]; then
|
12
|
-
mkdir -p "$install_dir"
|
13
|
-
fi
|
14
|
-
|
15
11
|
helpers_dir="$(dirname "${BASH_SOURCE[0]}")"
|
16
12
|
cp -r \
|
13
|
+
"$helpers_dir/.bundle" \
|
17
14
|
"$helpers_dir/lib" \
|
18
15
|
"$helpers_dir/monkey_patches" \
|
19
16
|
"$helpers_dir/run.rb" \
|
@@ -23,5 +20,5 @@ cp -r \
|
|
23
20
|
cd "$install_dir"
|
24
21
|
|
25
22
|
# NOTE: Sets `BUNDLED WITH` to match the installed v1 version in Gemfile.lock
|
26
|
-
# forcing
|
27
|
-
BUNDLER_VERSION=1 bundle install
|
23
|
+
# forcing native helpers to run with the same version
|
24
|
+
BUNDLER_VERSION=1 bundle install --without test
|
@@ -0,0 +1,133 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "native_spec_helper"
|
4
|
+
require "shared_contexts"
|
5
|
+
|
6
|
+
RSpec.describe Functions::ConflictingDependencyResolver do
|
7
|
+
include_context "in a temporary bundler directory"
|
8
|
+
|
9
|
+
let(:conflicting_dependency_resolver) do
|
10
|
+
described_class.new(
|
11
|
+
dependency_name: dependency_name,
|
12
|
+
target_version: target_version,
|
13
|
+
lockfile_name: "Gemfile.lock"
|
14
|
+
)
|
15
|
+
end
|
16
|
+
|
17
|
+
let(:dependency_name) { "dummy-pkg-a" }
|
18
|
+
let(:target_version) { "2.0.0" }
|
19
|
+
|
20
|
+
let(:project_name) { "blocked_by_subdep" }
|
21
|
+
|
22
|
+
describe "#conflicting_dependencies" do
|
23
|
+
subject(:conflicting_dependencies) do
|
24
|
+
in_tmp_folder { conflicting_dependency_resolver.conflicting_dependencies }
|
25
|
+
end
|
26
|
+
|
27
|
+
it "returns a list of dependencies that block the update" do
|
28
|
+
expect(conflicting_dependencies).to eq(
|
29
|
+
[{
|
30
|
+
"explanation" => "dummy-pkg-b (1.0.0) requires dummy-pkg-a (< 2.0.0)",
|
31
|
+
"name" => "dummy-pkg-b",
|
32
|
+
"version" => "1.0.0",
|
33
|
+
"requirement" => "< 2.0.0"
|
34
|
+
}]
|
35
|
+
)
|
36
|
+
end
|
37
|
+
|
38
|
+
context "for nested transitive dependencies" do
|
39
|
+
let(:project_name) { "transitive_blocking" }
|
40
|
+
let(:dependency_name) { "activesupport" }
|
41
|
+
let(:target_version) { "6.0.0" }
|
42
|
+
|
43
|
+
it "returns a list of dependencies that block the update" do
|
44
|
+
expect(conflicting_dependencies).to match_array(
|
45
|
+
[
|
46
|
+
{
|
47
|
+
"explanation" => "rails (5.2.0) requires activesupport (= 5.2.0)",
|
48
|
+
"name" => "rails",
|
49
|
+
"requirement" => "= 5.2.0",
|
50
|
+
"version" => "5.2.0"
|
51
|
+
},
|
52
|
+
{
|
53
|
+
"explanation" => "rails (5.2.0) requires activesupport (= 5.2.0) via actionpack (5.2.0)",
|
54
|
+
"name" => "actionpack",
|
55
|
+
"version" => "5.2.0",
|
56
|
+
"requirement" => "= 5.2.0"
|
57
|
+
},
|
58
|
+
{
|
59
|
+
"explanation" => "rails (5.2.0) requires activesupport (= 5.2.0) via actionview (5.2.0)",
|
60
|
+
"name" => "actionview",
|
61
|
+
"version" => "5.2.0",
|
62
|
+
"requirement" => "= 5.2.0"
|
63
|
+
},
|
64
|
+
{
|
65
|
+
"explanation" => "rails (5.2.0) requires activesupport (= 5.2.0) via activejob (5.2.0)",
|
66
|
+
"name" => "activejob",
|
67
|
+
"version" => "5.2.0",
|
68
|
+
"requirement" => "= 5.2.0"
|
69
|
+
},
|
70
|
+
{
|
71
|
+
"explanation" => "rails (5.2.0) requires activesupport (= 5.2.0) via activemodel (5.2.0)",
|
72
|
+
"name" => "activemodel",
|
73
|
+
"version" => "5.2.0",
|
74
|
+
"requirement" => "= 5.2.0"
|
75
|
+
},
|
76
|
+
{
|
77
|
+
"explanation" => "rails (5.2.0) requires activesupport (= 5.2.0) via activerecord (5.2.0)",
|
78
|
+
"name" => "activerecord",
|
79
|
+
"version" => "5.2.0",
|
80
|
+
"requirement" => "= 5.2.0"
|
81
|
+
},
|
82
|
+
{
|
83
|
+
"explanation" => "rails (5.2.0) requires activesupport (= 5.2.0) via railties (5.2.0)",
|
84
|
+
"name" => "railties",
|
85
|
+
"version" => "5.2.0",
|
86
|
+
"requirement" => "= 5.2.0"
|
87
|
+
}
|
88
|
+
]
|
89
|
+
)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
context "with multiple blocking dependencies" do
|
94
|
+
let(:dependency_name) { "activesupport" }
|
95
|
+
let(:current_version) { "5.0.0" }
|
96
|
+
let(:target_version) { "6.0.0" }
|
97
|
+
let(:project_name) { "multiple_blocking" }
|
98
|
+
|
99
|
+
it "returns all of the blocking dependencies" do
|
100
|
+
expect(conflicting_dependencies).to match_array(
|
101
|
+
[
|
102
|
+
{
|
103
|
+
"explanation" => "actionmailer (5.0.0) requires activesupport (= 5.0.0) via actionpack (5.0.0)",
|
104
|
+
"name" => "actionpack",
|
105
|
+
"version" => "5.0.0",
|
106
|
+
"requirement" => "= 5.0.0"
|
107
|
+
},
|
108
|
+
{
|
109
|
+
"explanation" => "actionview (5.0.0) requires activesupport (= 5.0.0)",
|
110
|
+
"name" => "actionview",
|
111
|
+
"version" => "5.0.0",
|
112
|
+
"requirement" => "= 5.0.0"
|
113
|
+
},
|
114
|
+
{
|
115
|
+
"explanation" => "actionmailer (5.0.0) requires activesupport (= 5.0.0) via activejob (5.0.0)",
|
116
|
+
"name" => "activejob",
|
117
|
+
"version" => "5.0.0",
|
118
|
+
"requirement" => "= 5.0.0"
|
119
|
+
}
|
120
|
+
]
|
121
|
+
)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
context "without any blocking dependencies" do
|
126
|
+
let(:target_version) { "1.0.0" }
|
127
|
+
|
128
|
+
it "returns an empty list" do
|
129
|
+
expect(conflicting_dependencies).to eq([])
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
@@ -0,0 +1,187 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "native_spec_helper"
|
4
|
+
require "shared_contexts"
|
5
|
+
|
6
|
+
RSpec.describe Functions::DependencySource do
|
7
|
+
include_context "in a temporary bundler directory"
|
8
|
+
|
9
|
+
let(:dependency_source) do
|
10
|
+
described_class.new(
|
11
|
+
gemfile_name: "Gemfile",
|
12
|
+
dependency_name: dependency_name
|
13
|
+
)
|
14
|
+
end
|
15
|
+
|
16
|
+
let(:dependency_name) { "business" }
|
17
|
+
|
18
|
+
let(:project_name) { "specified_source_no_lockfile" }
|
19
|
+
let(:registry_url) { "https://repo.fury.io/greysteil/" }
|
20
|
+
let(:gemfury_business_url) do
|
21
|
+
"https://repo.fury.io/greysteil/api/v1/dependencies?gems=business"
|
22
|
+
end
|
23
|
+
|
24
|
+
before do
|
25
|
+
stub_request(:get, registry_url + "versions").
|
26
|
+
with(basic_auth: ["SECRET_CODES", ""]).
|
27
|
+
to_return(status: 404)
|
28
|
+
stub_request(:get, registry_url + "api/v1/dependencies").
|
29
|
+
with(basic_auth: ["SECRET_CODES", ""]).
|
30
|
+
to_return(status: 200)
|
31
|
+
stub_request(:get, gemfury_business_url).
|
32
|
+
with(basic_auth: ["SECRET_CODES", ""]).
|
33
|
+
to_return(status: 200, body: fixture("ruby", "gemfury_response"))
|
34
|
+
end
|
35
|
+
|
36
|
+
describe "#private_registry_versions" do
|
37
|
+
subject(:private_registry_versions) do
|
38
|
+
in_tmp_folder { dependency_source.private_registry_versions }
|
39
|
+
end
|
40
|
+
|
41
|
+
it "returns all versions from the private source" do
|
42
|
+
is_expected.to eq([
|
43
|
+
Gem::Version.new("1.5.0"),
|
44
|
+
Gem::Version.new("1.9.0"),
|
45
|
+
Gem::Version.new("1.10.0.beta")
|
46
|
+
])
|
47
|
+
end
|
48
|
+
|
49
|
+
context "specified as the default source" do
|
50
|
+
let(:project_name) { "specified_default_source_no_lockfile" }
|
51
|
+
|
52
|
+
it "returns all versions from the private source" do
|
53
|
+
is_expected.to eq([
|
54
|
+
Gem::Version.new("1.5.0"),
|
55
|
+
Gem::Version.new("1.9.0"),
|
56
|
+
Gem::Version.new("1.10.0.beta")
|
57
|
+
])
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
context "that we don't have authentication details for" do
|
62
|
+
before do
|
63
|
+
stub_request(:get, registry_url + "versions").
|
64
|
+
with(basic_auth: ["SECRET_CODES", ""]).
|
65
|
+
to_return(status: 401)
|
66
|
+
stub_request(:get, registry_url + "api/v1/dependencies").
|
67
|
+
with(basic_auth: ["SECRET_CODES", ""]).
|
68
|
+
to_return(status: 401)
|
69
|
+
stub_request(:get, registry_url + "specs.4.8.gz").
|
70
|
+
with(basic_auth: ["SECRET_CODES", ""]).
|
71
|
+
to_return(status: 401)
|
72
|
+
end
|
73
|
+
|
74
|
+
it "blows up with a useful error" do
|
75
|
+
error_class = Bundler::Fetcher::AuthenticationRequiredError
|
76
|
+
error_message = "Authentication is required for repo.fury.io"
|
77
|
+
expect { private_registry_versions }.
|
78
|
+
to raise_error do |error|
|
79
|
+
expect(error).to be_a(error_class)
|
80
|
+
expect(error.message).to include(error_message)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
context "that we have bad authentication details for" do
|
86
|
+
before do
|
87
|
+
stub_request(:get, registry_url + "versions").
|
88
|
+
with(basic_auth: ["SECRET_CODES", ""]).
|
89
|
+
to_return(status: 403)
|
90
|
+
stub_request(:get, registry_url + "api/v1/dependencies").
|
91
|
+
with(basic_auth: ["SECRET_CODES", ""]).
|
92
|
+
to_return(status: 403)
|
93
|
+
stub_request(:get, registry_url + "specs.4.8.gz").
|
94
|
+
with(basic_auth: ["SECRET_CODES", ""]).
|
95
|
+
to_return(status: 403)
|
96
|
+
end
|
97
|
+
|
98
|
+
it "blows up with a useful error" do
|
99
|
+
error_class = Bundler::Fetcher::BadAuthenticationError
|
100
|
+
expect { private_registry_versions }.
|
101
|
+
to raise_error do |error|
|
102
|
+
expect(error).to be_a(error_class)
|
103
|
+
expect(error.message).
|
104
|
+
to include("Bad username or password for")
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
context "that bad-requested, but was a private repo" do
|
110
|
+
before do
|
111
|
+
stub_request(:get, registry_url + "versions").
|
112
|
+
with(basic_auth: ["SECRET_CODES", ""]).
|
113
|
+
to_return(status: 400)
|
114
|
+
stub_request(:get, registry_url + "api/v1/dependencies").
|
115
|
+
with(basic_auth: ["SECRET_CODES", ""]).
|
116
|
+
to_return(status: 400)
|
117
|
+
stub_request(:get, registry_url + "specs.4.8.gz").
|
118
|
+
with(basic_auth: ["SECRET_CODES", ""]).
|
119
|
+
to_return(status: 400)
|
120
|
+
end
|
121
|
+
|
122
|
+
it "blows up with a useful error" do
|
123
|
+
expect { private_registry_versions }.
|
124
|
+
to raise_error do |error|
|
125
|
+
expect(error).to be_a(Bundler::HTTPError)
|
126
|
+
expect(error.message).
|
127
|
+
to include("Could not fetch specs from")
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
context "that doesn't have details of the gem" do
|
133
|
+
before do
|
134
|
+
stub_request(:get, gemfury_business_url).
|
135
|
+
with(basic_auth: ["SECRET_CODES", ""]).
|
136
|
+
to_return(status: 404)
|
137
|
+
|
138
|
+
# Stub indexes to return details of other gems (but not this one)
|
139
|
+
stub_request(:get, registry_url + "specs.4.8.gz").
|
140
|
+
to_return(
|
141
|
+
status: 200,
|
142
|
+
body: fixture("ruby", "contribsys_old_index_response")
|
143
|
+
)
|
144
|
+
stub_request(:get, registry_url + "prerelease_specs.4.8.gz").
|
145
|
+
to_return(
|
146
|
+
status: 200,
|
147
|
+
body: fixture("ruby", "contribsys_old_index_prerelease_response")
|
148
|
+
)
|
149
|
+
end
|
150
|
+
|
151
|
+
it { is_expected.to be_empty }
|
152
|
+
end
|
153
|
+
|
154
|
+
context "that only implements the old Bundler index format..." do
|
155
|
+
let(:project_name) { "sidekiq_pro" }
|
156
|
+
let(:dependency_name) { "sidekiq-pro" }
|
157
|
+
let(:registry_url) { "https://gems.contribsys.com/" }
|
158
|
+
|
159
|
+
before do
|
160
|
+
stub_request(:get, registry_url + "versions").
|
161
|
+
with(basic_auth: %w(username password)).
|
162
|
+
to_return(status: 404)
|
163
|
+
stub_request(:get, registry_url + "api/v1/dependencies").
|
164
|
+
with(basic_auth: %w(username password)).
|
165
|
+
to_return(status: 404)
|
166
|
+
stub_request(:get, registry_url + "specs.4.8.gz").
|
167
|
+
with(basic_auth: %w(username password)).
|
168
|
+
to_return(
|
169
|
+
status: 200,
|
170
|
+
body: fixture("ruby", "contribsys_old_index_response")
|
171
|
+
)
|
172
|
+
stub_request(:get, registry_url + "prerelease_specs.4.8.gz").
|
173
|
+
with(basic_auth: %w(username password)).
|
174
|
+
to_return(
|
175
|
+
status: 200,
|
176
|
+
body: fixture("ruby", "contribsys_old_index_prerelease_response")
|
177
|
+
)
|
178
|
+
end
|
179
|
+
|
180
|
+
it "returns all versions from the private source" do
|
181
|
+
expect(private_registry_versions.length).to eql(70)
|
182
|
+
expect(private_registry_versions.min).to eql(Gem::Version.new("1.0.0"))
|
183
|
+
expect(private_registry_versions.max).to eql(Gem::Version.new("3.5.2"))
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "native_spec_helper"
|
4
|
+
require "shared_contexts"
|
5
|
+
|
6
|
+
RSpec.describe Functions::FileParser do
|
7
|
+
include_context "in a temporary bundler directory"
|
8
|
+
|
9
|
+
let(:dependency_source) do
|
10
|
+
described_class.new(
|
11
|
+
lockfile_name: "Gemfile.lock"
|
12
|
+
)
|
13
|
+
end
|
14
|
+
|
15
|
+
let(:project_name) { "gemfile" }
|
16
|
+
|
17
|
+
describe "#parsed_gemfile" do
|
18
|
+
subject(:parsed_gemfile) do
|
19
|
+
in_tmp_folder do
|
20
|
+
dependency_source.parsed_gemfile(gemfile_name: "Gemfile")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
it "parses gemfile" do
|
25
|
+
parsed_gemfile = [
|
26
|
+
{
|
27
|
+
groups: [:default],
|
28
|
+
name: "business",
|
29
|
+
requirement: Gem::Requirement.new("~> 1.4.0"),
|
30
|
+
source: nil,
|
31
|
+
type: :runtime
|
32
|
+
},
|
33
|
+
{
|
34
|
+
groups: [:default],
|
35
|
+
name: "statesman",
|
36
|
+
requirement: Gem::Requirement.new("~> 1.2.0"),
|
37
|
+
source: nil,
|
38
|
+
type: :runtime
|
39
|
+
}
|
40
|
+
]
|
41
|
+
is_expected.to eq(parsed_gemfile)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "#parsed_gemspec" do
|
46
|
+
let!(:gemspec_fixture) do
|
47
|
+
fixture("ruby", "gemspecs", "exact")
|
48
|
+
end
|
49
|
+
|
50
|
+
subject(:parsed_gemspec) do
|
51
|
+
in_tmp_folder do |tmp_path|
|
52
|
+
File.write(File.join(tmp_path, "test.gemspec"), gemspec_fixture)
|
53
|
+
dependency_source.parsed_gemspec(gemspec_name: "test.gemspec")
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
it "parses gemspec" do
|
58
|
+
parsed_gemspec = [
|
59
|
+
{
|
60
|
+
groups: nil,
|
61
|
+
name: "business",
|
62
|
+
requirement: Gem::Requirement.new("= 1.0.0"),
|
63
|
+
source: nil,
|
64
|
+
type: :runtime
|
65
|
+
},
|
66
|
+
{
|
67
|
+
groups: nil,
|
68
|
+
name: "statesman",
|
69
|
+
requirement: Gem::Requirement.new("= 1.0.0"),
|
70
|
+
source: nil,
|
71
|
+
type: :runtime
|
72
|
+
}
|
73
|
+
]
|
74
|
+
is_expected.to eq(parsed_gemspec)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "native_spec_helper"
|
4
|
+
require "shared_contexts"
|
5
|
+
|
6
|
+
RSpec.describe Functions::VersionResolver do
|
7
|
+
include_context "in a temporary bundler directory"
|
8
|
+
include_context "stub rubygems compact index"
|
9
|
+
|
10
|
+
let(:version_resolver) do
|
11
|
+
described_class.new(
|
12
|
+
dependency_name: dependency_name,
|
13
|
+
dependency_requirements: dependency_requirements,
|
14
|
+
gemfile_name: "Gemfile",
|
15
|
+
lockfile_name: "Gemfile.lock"
|
16
|
+
)
|
17
|
+
end
|
18
|
+
|
19
|
+
let(:dependency_name) { "business" }
|
20
|
+
let(:dependency_requirements) do
|
21
|
+
[{
|
22
|
+
file: "Gemfile",
|
23
|
+
requirement: requirement_string,
|
24
|
+
groups: [],
|
25
|
+
source: source
|
26
|
+
}]
|
27
|
+
end
|
28
|
+
let(:source) { nil }
|
29
|
+
|
30
|
+
let(:rubygems_url) { "https://index.rubygems.org/api/v1/" }
|
31
|
+
let(:old_index_url) { rubygems_url + "dependencies" }
|
32
|
+
|
33
|
+
describe "#version_details" do
|
34
|
+
subject do
|
35
|
+
in_tmp_folder { version_resolver.version_details }
|
36
|
+
end
|
37
|
+
|
38
|
+
let(:project_name) { "gemfile" }
|
39
|
+
let(:requirement_string) { " >= 0" }
|
40
|
+
|
41
|
+
its([:version]) { is_expected.to eq(Gem::Version.new("1.4.0")) }
|
42
|
+
its([:fetcher]) { is_expected.to eq("Bundler::Fetcher::CompactIndex") }
|
43
|
+
|
44
|
+
context "with a private gemserver source" do
|
45
|
+
include_context "stub rubygems compact index"
|
46
|
+
|
47
|
+
let(:project_name) { "specified_source" }
|
48
|
+
let(:requirement_string) { ">= 0" }
|
49
|
+
|
50
|
+
before do
|
51
|
+
gemfury_url = "https://repo.fury.io/greysteil/"
|
52
|
+
gemfury_deps_url = gemfury_url + "api/v1/dependencies"
|
53
|
+
|
54
|
+
stub_request(:get, gemfury_url + "versions").
|
55
|
+
to_return(status: 200, body: fixture("ruby", "gemfury-index"))
|
56
|
+
stub_request(:get, gemfury_url + "info/business").to_return(status: 404)
|
57
|
+
stub_request(:get, gemfury_deps_url).to_return(status: 200)
|
58
|
+
stub_request(:get, gemfury_deps_url + "?gems=business,statesman").
|
59
|
+
to_return(status: 200, body: fixture("ruby", "gemfury_response"))
|
60
|
+
stub_request(:get, gemfury_deps_url + "?gems=business").
|
61
|
+
to_return(status: 200, body: fixture("ruby", "gemfury_response"))
|
62
|
+
stub_request(:get, gemfury_deps_url + "?gems=statesman").
|
63
|
+
to_return(status: 200, body: fixture("ruby", "gemfury_response"))
|
64
|
+
end
|
65
|
+
|
66
|
+
its([:version]) { is_expected.to eq(Gem::Version.new("1.9.0")) }
|
67
|
+
its([:fetcher]) { is_expected.to eq("Bundler::Fetcher::Dependency") }
|
68
|
+
end
|
69
|
+
|
70
|
+
context "with a git source" do
|
71
|
+
let(:project_name) { "git_source" }
|
72
|
+
|
73
|
+
its([:version]) { is_expected.to eq(Gem::Version.new("1.6.0")) }
|
74
|
+
its([:fetcher]) { is_expected.to be_nil }
|
75
|
+
end
|
76
|
+
|
77
|
+
context "when Bundler's compact index is down" do
|
78
|
+
before do
|
79
|
+
stub_request(:get, "https://index.rubygems.org/versions").
|
80
|
+
to_return(status: 500, body: "We'll be back soon")
|
81
|
+
stub_request(:get, "https://index.rubygems.org/info/public_suffix").
|
82
|
+
to_return(status: 500, body: "We'll be back soon")
|
83
|
+
stub_request(:get, old_index_url).to_return(status: 200)
|
84
|
+
stub_request(:get, old_index_url + "?gems=business,statesman").
|
85
|
+
to_return(
|
86
|
+
status: 200,
|
87
|
+
body: fixture("ruby",
|
88
|
+
"rubygems_responses",
|
89
|
+
"dependencies-default-gemfile")
|
90
|
+
)
|
91
|
+
end
|
92
|
+
|
93
|
+
its([:version]) { is_expected.to eq(Gem::Version.new("1.4.0")) }
|
94
|
+
its([:fetcher]) { is_expected.to eq("Bundler::Fetcher::Dependency") }
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rspec/its"
|
4
|
+
require "webmock/rspec"
|
5
|
+
require "byebug"
|
6
|
+
|
7
|
+
$LOAD_PATH.unshift(File.expand_path("../lib", __dir__))
|
8
|
+
$LOAD_PATH.unshift(File.expand_path("../monkey_patches", __dir__))
|
9
|
+
|
10
|
+
# Bundler monkey patches
|
11
|
+
require "definition_ruby_version_patch"
|
12
|
+
require "definition_bundler_version_patch"
|
13
|
+
require "git_source_patch"
|
14
|
+
|
15
|
+
require "functions"
|
16
|
+
|
17
|
+
RSpec.configure do |config|
|
18
|
+
config.color = true
|
19
|
+
config.order = :rand
|
20
|
+
config.mock_with(:rspec) { |mocks| mocks.verify_partial_doubles = true }
|
21
|
+
config.raise_errors_for_deprecations!
|
22
|
+
end
|
23
|
+
|
24
|
+
# Duplicated in lib/dependabot/bundler/file_updater/lockfile_updater.rb
|
25
|
+
# TODO: Stop sanitizing the lockfile once we have bundler 2 installed
|
26
|
+
LOCKFILE_ENDING = /(?<ending>\s*(?:RUBY VERSION|BUNDLED WITH).*)/m.freeze
|
27
|
+
|
28
|
+
def project_dependency_files(project)
|
29
|
+
project_path = File.expand_path(File.join("../../spec/fixtures/projects/bundler1", project))
|
30
|
+
Dir.chdir(project_path) do
|
31
|
+
# NOTE: Include dotfiles (e.g. .npmrc)
|
32
|
+
files = Dir.glob("**/*", File::FNM_DOTMATCH)
|
33
|
+
files = files.select { |f| File.file?(f) }
|
34
|
+
files.map do |filename|
|
35
|
+
content = File.read(filename)
|
36
|
+
if filename == "Gemfile.lock"
|
37
|
+
content = content.gsub(LOCKFILE_ENDING, "")
|
38
|
+
end
|
39
|
+
{
|
40
|
+
name: filename,
|
41
|
+
content: content
|
42
|
+
}
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def fixture(*name)
|
48
|
+
File.read(File.join("../../spec/fixtures", File.join(*name)))
|
49
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "bundler/compact_index_client"
|
4
|
+
require "bundler/compact_index_client/updater"
|
5
|
+
|
6
|
+
TMP_DIR_PATH = File.expand_path("../tmp", __dir__)
|
7
|
+
|
8
|
+
RSpec.shared_context "in a temporary bundler directory" do
|
9
|
+
let(:project_name) { "gemfile" }
|
10
|
+
|
11
|
+
let(:tmp_path) do
|
12
|
+
Dir.mkdir(TMP_DIR_PATH) unless Dir.exist?(TMP_DIR_PATH)
|
13
|
+
dir = Dir.mktmpdir("native_helper_spec_", TMP_DIR_PATH)
|
14
|
+
Pathname.new(dir).expand_path
|
15
|
+
end
|
16
|
+
|
17
|
+
before do
|
18
|
+
project_dependency_files(project_name).each do |file|
|
19
|
+
File.write(File.join(tmp_path, file[:name]), file[:content])
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def in_tmp_folder(&block)
|
24
|
+
Dir.chdir(tmp_path, &block)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
RSpec.shared_context "without caching rubygems" do
|
29
|
+
before do
|
30
|
+
# Stub Bundler to stop it using a cached versions of Rubygems
|
31
|
+
allow_any_instance_of(Bundler::CompactIndexClient::Updater).
|
32
|
+
to receive(:etag_for).and_return("")
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
RSpec.shared_context "stub rubygems compact index" do
|
37
|
+
include_context "without caching rubygems"
|
38
|
+
|
39
|
+
before do
|
40
|
+
# Stub the Rubygems index
|
41
|
+
stub_request(:get, "https://index.rubygems.org/versions").
|
42
|
+
to_return(
|
43
|
+
status: 200,
|
44
|
+
body: fixture("ruby", "rubygems_responses", "index")
|
45
|
+
)
|
46
|
+
|
47
|
+
# Stub the Rubygems response for each dependency we have a fixture for
|
48
|
+
fixtures =
|
49
|
+
Dir[File.join("../../spec", "fixtures", "ruby", "rubygems_responses", "info-*")]
|
50
|
+
fixtures.each do |path|
|
51
|
+
dep_name = path.split("/").last.gsub("info-", "")
|
52
|
+
stub_request(:get, "https://index.rubygems.org/info/#{dep_name}").
|
53
|
+
to_return(
|
54
|
+
status: 200,
|
55
|
+
body: fixture("ruby", "rubygems_responses", "info-#{dep_name}")
|
56
|
+
)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -234,11 +234,8 @@ module Dependabot
|
|
234
234
|
def remove_unnecessary_assignments(node)
|
235
235
|
return unless node.is_a?(Parser::AST::Node)
|
236
236
|
|
237
|
-
if unnecessary_assignment?(node) &&
|
238
|
-
|
239
|
-
range_to_remove = node.loc.expression.join(
|
240
|
-
node.children.last.location.heredoc_end
|
241
|
-
)
|
237
|
+
if unnecessary_assignment?(node) && node_includes_heredoc?(node)
|
238
|
+
range_to_remove = node.loc.expression.join(find_heredoc_end_range(node))
|
242
239
|
return replace(range_to_remove, '"sanitized"')
|
243
240
|
elsif unnecessary_assignment?(node)
|
244
241
|
return replace(node.loc.expression, '"sanitized"')
|
@@ -249,6 +246,30 @@ module Dependabot
|
|
249
246
|
end
|
250
247
|
end
|
251
248
|
|
249
|
+
def node_includes_heredoc?(node)
|
250
|
+
find_heredoc_end_range(node)
|
251
|
+
end
|
252
|
+
|
253
|
+
# Performs a depth-first search for the first heredoc in the given
|
254
|
+
# Parser::AST::Node.
|
255
|
+
#
|
256
|
+
# Returns a Parser::Source::Range identifying the location of the end
|
257
|
+
# of the heredoc, or nil if no heredoc was found.
|
258
|
+
def find_heredoc_end_range(node)
|
259
|
+
return unless node.is_a?(Parser::AST::Node)
|
260
|
+
|
261
|
+
node.children.each do |child|
|
262
|
+
next unless child.is_a?(Parser::AST::Node)
|
263
|
+
|
264
|
+
return child.location.heredoc_end if child.location.respond_to?(:heredoc_end)
|
265
|
+
|
266
|
+
range = find_heredoc_end_range(child)
|
267
|
+
return range if range
|
268
|
+
end
|
269
|
+
|
270
|
+
nil
|
271
|
+
end
|
272
|
+
|
252
273
|
def unnecessary_assignment?(node)
|
253
274
|
return false unless node.is_a?(Parser::AST::Node)
|
254
275
|
return false unless node.children.first.is_a?(Parser::AST::Node)
|
@@ -1,30 +1,26 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "bundler"
|
3
4
|
require "dependabot/shared_helpers"
|
4
5
|
|
5
6
|
module Dependabot
|
6
7
|
module Bundler
|
7
8
|
module NativeHelpers
|
8
9
|
def self.run_bundler_subprocess(function:, args:, bundler_version:)
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
"RUBYOPT" => nil,
|
24
|
-
"GEM_PATH" => nil,
|
25
|
-
"GEM_HOME" => nil
|
26
|
-
}
|
27
|
-
)
|
10
|
+
# Run helper suprocess with all bundler-related ENV variables removed
|
11
|
+
::Bundler.with_original_env do
|
12
|
+
SharedHelpers.run_helper_subprocess(
|
13
|
+
command: helper_path(bundler_version: bundler_version),
|
14
|
+
function: function,
|
15
|
+
args: args,
|
16
|
+
env: {
|
17
|
+
# Bundler will pick the matching installed major version
|
18
|
+
"BUNDLER_VERSION" => bundler_version,
|
19
|
+
"BUNDLE_GEMFILE" => File.join(versioned_helper_path(bundler_version: bundler_version), "Gemfile"),
|
20
|
+
"BUNDLE_PATH" => File.join(versioned_helper_path(bundler_version: bundler_version), ".bundle")
|
21
|
+
}
|
22
|
+
)
|
23
|
+
end
|
28
24
|
end
|
29
25
|
|
30
26
|
def self.versioned_helper_path(bundler_version:)
|
@@ -33,7 +29,7 @@ module Dependabot
|
|
33
29
|
end
|
34
30
|
|
35
31
|
def self.helper_path(bundler_version:)
|
36
|
-
"
|
32
|
+
"ruby #{File.join(versioned_helper_path(bundler_version: bundler_version), 'run.rb')}"
|
37
33
|
end
|
38
34
|
|
39
35
|
def self.native_helpers_root
|
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.137.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dependabot
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-03-
|
11
|
+
date: 2021-03-15 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.137.1
|
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.137.1
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: byebug
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -100,14 +100,14 @@ dependencies:
|
|
100
100
|
requirements:
|
101
101
|
- - "~>"
|
102
102
|
- !ruby/object:Gem::Version
|
103
|
-
version: 1.
|
103
|
+
version: 1.11.0
|
104
104
|
type: :development
|
105
105
|
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
108
|
- - "~>"
|
109
109
|
- !ruby/object:Gem::Version
|
110
|
-
version: 1.
|
110
|
+
version: 1.11.0
|
111
111
|
- !ruby/object:Gem::Dependency
|
112
112
|
name: simplecov
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
@@ -185,6 +185,7 @@ executables: []
|
|
185
185
|
extensions: []
|
186
186
|
extra_rdoc_files: []
|
187
187
|
files:
|
188
|
+
- helpers/v1/.bundle/config
|
188
189
|
- helpers/v1/.gitignore
|
189
190
|
- helpers/v1/Gemfile
|
190
191
|
- helpers/v1/build
|
@@ -199,6 +200,12 @@ files:
|
|
199
200
|
- helpers/v1/monkey_patches/definition_ruby_version_patch.rb
|
200
201
|
- helpers/v1/monkey_patches/git_source_patch.rb
|
201
202
|
- helpers/v1/run.rb
|
203
|
+
- helpers/v1/spec/functions/conflicting_dependency_resolver_spec.rb
|
204
|
+
- helpers/v1/spec/functions/dependency_source_spec.rb
|
205
|
+
- helpers/v1/spec/functions/file_parser_spec.rb
|
206
|
+
- helpers/v1/spec/functions/version_resolver_spec.rb
|
207
|
+
- helpers/v1/spec/native_spec_helper.rb
|
208
|
+
- helpers/v1/spec/shared_contexts.rb
|
202
209
|
- lib/dependabot/bundler.rb
|
203
210
|
- lib/dependabot/bundler/file_fetcher.rb
|
204
211
|
- lib/dependabot/bundler/file_fetcher/child_gemfile_finder.rb
|