Skip to content

Commit 21560ff

Browse files
committed
Handle ruby and pm specific version requirements
This is an attempt to handle both ruby and package manager specific version requirements from ignore conditions in the package manager specific requirement class. We currently create ruby style ignore requirement when commenting on dependabot PRs with £dependabot ignore this major version for example. We also say to use the package manager specific requirement syntax when adding ignores to the config file. We also support specifying comma-separated ignore conditions as a single string, > 1.2.3, <= 2.0.0 and split these when parsing the ignore conditions. This works for most ecosystems except for gradle/maven that have special range syntax, we used to handle this specifically when parsing ignore conditions: https://github.com/dependabot/dependabot-core/pull/3368/files#diff-3107de50e63836063ddedc0b51b50e47d1dba7d517f060e051b1b4d9494dd2abL131-L135 All requirement classes now support splitting comma-separated strings, whereas only some did this in the past and those who didn't would raise from Gem::Requirement. Using the requirements_array method also means we'll properly deal with languages that support OR syntax, e.q. https://github.com/dependabot/dependabot-core/blob/main/maven/lib/dependabot/maven/requirement.rb#L28
1 parent 0352d54 commit 21560ff

File tree

40 files changed

+203
-78
lines changed

40 files changed

+203
-78
lines changed

bundler/lib/dependabot/bundler/requirement.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ def self.requirements_array(requirement_string)
1616
# "~> 4.2.5, >= 4.2.5.1" without first needing to split them.
1717
def initialize(*requirements)
1818
requirements = requirements.flatten.flat_map do |req_string|
19-
req_string.split(",")
19+
req_string.split(",").map(&:strip)
2020
end
2121

2222
super(requirements)

bundler/lib/dependabot/bundler/update_checker/latest_version_finder.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ def filter_prerelease_versions(versions_array)
7070

7171
def filter_ignored_versions(versions_array)
7272
filtered = versions_array.
73-
reject { |v| ignore_reqs.any? { |r| r.satisfied_by?(v) } }
73+
reject { |v| ignore_requirements.any? { |r| r.satisfied_by?(v) } }
7474
raise AllVersionsIgnored if @raise_on_ignored && filtered.empty? && versions_array.any?
7575

7676
filtered
@@ -110,8 +110,8 @@ def dependency_source
110110
)
111111
end
112112

113-
def ignore_reqs
114-
ignored_versions.map { |req| Gem::Requirement.new(req.split(",")) }
113+
def ignore_requirements
114+
ignored_versions.flat_map { |req| requirement_class.requirements_array(req) }
115115
end
116116

117117
def gemfile

cargo/lib/dependabot/cargo/requirement.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ def self.requirements_array(requirement_string)
4242

4343
def initialize(*requirements)
4444
requirements = requirements.flatten.flat_map do |req_string|
45-
req_string.split(",").map do |r|
45+
req_string.split(",").map(&:strip).map do |r|
4646
convert_rust_constraint_to_ruby_constraint(r.strip)
4747
end
4848
end

cargo/lib/dependabot/cargo/update_checker/latest_version_finder.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ def filter_prerelease_versions(versions_array)
5555

5656
def filter_ignored_versions(versions_array)
5757
filtered = versions_array.
58-
reject { |v| ignore_reqs.any? { |r| r.satisfied_by?(v) } }
58+
reject { |v| ignore_requirements.any? { |r| r.satisfied_by?(v) } }
5959
raise Dependabot::AllVersionsIgnored if @raise_on_ignored && filtered.empty? && versions_array.any?
6060

6161
filtered
@@ -108,8 +108,8 @@ def wants_prerelease?
108108
end
109109
end
110110

111-
def ignore_reqs
112-
ignored_versions.map { |req| requirement_class.new(req.split(",")) }
111+
def ignore_requirements
112+
ignored_versions.flat_map { |req| requirement_class.requirements_array(req) }
113113
end
114114

115115
def version_class

common/lib/dependabot/git_commit_checker.rb

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ def local_tag_for_latest_version
9292
local_tags.
9393
select { |t| version_tag?(t.name) && matches_existing_prefix?(t.name) }
9494
filtered = tags.
95-
reject { |t| tag_included_in_ignore_reqs?(t) }
95+
reject { |t| tag_included_in_ignore_requirements?(t) }
9696
raise Dependabot::AllVersionsIgnored if @raise_on_ignored && tags.any? && filtered.empty?
9797

9898
tag = filtered.
@@ -317,8 +317,8 @@ def listing_upload_pack
317317
listing_repo_git_metadata_fetcher.upload_pack
318318
end
319319

320-
def ignore_reqs
321-
ignored_versions.map { |req| requirement_class.new(req.split(",")) }
320+
def ignore_requirements
321+
ignored_versions.flat_map { |req| requirement_class.requirements_array(req) }
322322
end
323323

324324
def wants_prerelease?
@@ -330,9 +330,9 @@ def wants_prerelease?
330330
version_class.new(version).prerelease?
331331
end
332332

333-
def tag_included_in_ignore_reqs?(tag)
333+
def tag_included_in_ignore_requirements?(tag)
334334
version = tag.name.match(VERSION_REGEX).named_captures.fetch("version")
335-
ignore_reqs.any? { |r| r.satisfied_by?(version_class.new(version)) }
335+
ignore_requirements.any? { |r| r.satisfied_by?(version_class.new(version)) }
336336
end
337337

338338
def tag_is_prerelease?(tag)

common/lib/dependabot/update_checkers/base.rb

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ def up_to_date?
3838

3939
def can_update?(requirements_to_unlock:)
4040
# Can't update if all versions are being ignored
41-
return false if ignore_reqs.include?(requirement_class.new(">= 0"))
41+
return false if ignore_requirements.include?(requirement_class.new(">= 0"))
4242

4343
if dependency.version
4444
version_can_update?(requirements_to_unlock: requirements_to_unlock)
@@ -141,6 +141,10 @@ def vulnerable?
141141
security_advisories.any? { |a| a.vulnerable?(version) }
142142
end
143143

144+
def ignore_requirements
145+
ignored_versions.flat_map { |req| requirement_class.requirements_array(req) }
146+
end
147+
144148
private
145149

146150
def latest_version_resolvable_with_full_unlock?
@@ -296,10 +300,6 @@ def requirements_can_update?
296300

297301
changed_requirements.none? { |r| r[:requirement] == :unfixable }
298302
end
299-
300-
def ignore_reqs
301-
ignored_versions.map { |req| requirement_class.new(req.split(",")) }
302-
end
303303
end
304304
end
305305
end

common/spec/dependabot/git_commit_checker_spec.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -925,6 +925,11 @@
925925
its([:tag]) { is_expected.to eq("v1.11.1") }
926926
end
927927

928+
context "multiple ignore conditions" do
929+
let(:ignored_versions) { [">= 1.11.2, < 1.12.0"] }
930+
its([:tag]) { is_expected.to eq("v1.13.0") }
931+
end
932+
928933
context "all versions ignored" do
929934
let(:ignored_versions) { [">= 0"] }
930935
it "returns nil" do

common/spec/dependabot/update_checkers/base_spec.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
described_class.new(
1111
dependency: dependency,
1212
dependency_files: [],
13+
ignored_versions: ignored_versions,
1314
credentials: [{
1415
"type" => "git_source",
1516
"host" => "github.com",
@@ -26,6 +27,7 @@
2627
package_manager: "dummy"
2728
)
2829
end
30+
let(:ignored_versions) { [] }
2931
let(:latest_version) { Gem::Version.new("1.0.0") }
3032
let(:original_requirements) do
3133
[{ file: "Gemfile", requirement: ">= 0", groups: [], source: nil }]
@@ -600,4 +602,16 @@
600602
it { is_expected.to eq(false) }
601603
end
602604
end
605+
606+
describe "#ignore_requirements" do
607+
subject(:ignore_requirements) { updater_instance.ignore_requirements }
608+
609+
it { is_expected.to eq([]) }
610+
611+
context "with ignored versions" do
612+
let(:ignored_versions) { ["~> 1.0, < 2"] }
613+
614+
it { is_expected.to eq([updater_instance.requirement_class.new("~> 1.0", "< 2")]) }
615+
end
616+
end
603617
end

common/spec/dummy_package_manager/requirement.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,16 @@ class Requirement < Gem::Requirement
77
def self.requirements_array(requirement_string)
88
[new(requirement_string)]
99
end
10+
11+
# Patches Gem::Requirement to make it accept requirement strings like
12+
# "~> 4.2.5, >= 4.2.5.1" without first needing to split them.
13+
def initialize(*requirements)
14+
requirements = requirements.flatten.flat_map do |req_string|
15+
req_string.split(",").map(&:strip)
16+
end
17+
18+
super(requirements)
19+
end
1020
end
1121
end
1222

composer/lib/dependabot/composer/update_checker/latest_version_finder.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ def filter_prerelease_versions(versions_array)
6060
def filter_ignored_versions(versions_array)
6161
filtered =
6262
versions_array.
63-
reject { |v| ignore_reqs.any? { |r| r.satisfied_by?(v) } }
63+
reject { |v| ignore_requirements.any? { |r| r.satisfied_by?(v) } }
6464

6565
raise AllVersionsIgnored if @raise_on_ignored && filtered.empty? && versions_array.any?
6666

@@ -178,7 +178,7 @@ def auth_json
178178
dependency_files.find { |f| f.name == "auth.json" }
179179
end
180180

181-
def ignore_reqs
181+
def ignore_requirements
182182
ignored_versions.map { |req| requirement_class.new(req.split(",")) }
183183
end
184184

0 commit comments

Comments
 (0)