dependabot-dep 0.90.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/helpers/Makefile +9 -0
- data/helpers/build +26 -0
- data/helpers/go.mod +8 -0
- data/helpers/go.sum +2 -0
- data/helpers/importresolver/go.mod +1 -0
- data/helpers/importresolver/main.go +34 -0
- data/helpers/main.go +67 -0
- data/lib/dependabot/dep.rb +11 -0
- data/lib/dependabot/dep/file_fetcher.rb +70 -0
- data/lib/dependabot/dep/file_parser.rb +189 -0
- data/lib/dependabot/dep/file_updater.rb +78 -0
- data/lib/dependabot/dep/file_updater/lockfile_updater.rb +220 -0
- data/lib/dependabot/dep/file_updater/manifest_updater.rb +151 -0
- data/lib/dependabot/dep/metadata_finder.rb +57 -0
- data/lib/dependabot/dep/native_helpers.rb +20 -0
- data/lib/dependabot/dep/path_converter.rb +72 -0
- data/lib/dependabot/dep/requirement.rb +152 -0
- data/lib/dependabot/dep/update_checker.rb +312 -0
- data/lib/dependabot/dep/update_checker/file_preparer.rb +219 -0
- data/lib/dependabot/dep/update_checker/latest_version_finder.rb +167 -0
- data/lib/dependabot/dep/update_checker/requirements_updater.rb +221 -0
- data/lib/dependabot/dep/update_checker/version_resolver.rb +166 -0
- data/lib/dependabot/dep/version.rb +43 -0
- metadata +192 -0
@@ -0,0 +1,219 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "toml-rb"
|
4
|
+
require "dependabot/dependency_file"
|
5
|
+
require "dependabot/dep/file_parser"
|
6
|
+
require "dependabot/dep/update_checker"
|
7
|
+
|
8
|
+
module Dependabot
|
9
|
+
module Dep
|
10
|
+
class UpdateChecker
|
11
|
+
# This class takes a set of dependency files and prepares them for use
|
12
|
+
# in Dep::UpdateChecker.
|
13
|
+
class FilePreparer
|
14
|
+
def initialize(dependency_files:, dependency:,
|
15
|
+
remove_git_source: false,
|
16
|
+
unlock_requirement: true,
|
17
|
+
replacement_git_pin: nil,
|
18
|
+
latest_allowable_version: nil)
|
19
|
+
@dependency_files = dependency_files
|
20
|
+
@dependency = dependency
|
21
|
+
@unlock_requirement = unlock_requirement
|
22
|
+
@remove_git_source = remove_git_source
|
23
|
+
@replacement_git_pin = replacement_git_pin
|
24
|
+
@latest_allowable_version = latest_allowable_version
|
25
|
+
end
|
26
|
+
|
27
|
+
def prepared_dependency_files
|
28
|
+
files = []
|
29
|
+
|
30
|
+
files << manifest_for_update_check
|
31
|
+
files << lockfile if lockfile
|
32
|
+
|
33
|
+
files
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
attr_reader :dependency_files, :dependency, :replacement_git_pin,
|
39
|
+
:latest_allowable_version
|
40
|
+
|
41
|
+
def unlock_requirement?
|
42
|
+
@unlock_requirement
|
43
|
+
end
|
44
|
+
|
45
|
+
def remove_git_source?
|
46
|
+
@remove_git_source
|
47
|
+
end
|
48
|
+
|
49
|
+
def replace_git_pin?
|
50
|
+
!replacement_git_pin.nil?
|
51
|
+
end
|
52
|
+
|
53
|
+
def manifest_for_update_check
|
54
|
+
DependencyFile.new(
|
55
|
+
name: manifest.name,
|
56
|
+
content: manifest_content_for_update_check(manifest),
|
57
|
+
directory: manifest.directory
|
58
|
+
)
|
59
|
+
end
|
60
|
+
|
61
|
+
def manifest_content_for_update_check(file)
|
62
|
+
content = file.content
|
63
|
+
|
64
|
+
content = remove_git_source(content) if remove_git_source?
|
65
|
+
content = replace_git_pin(content) if replace_git_pin?
|
66
|
+
content = replace_version_constraint(content, file.name)
|
67
|
+
content = add_fsnotify_override(content)
|
68
|
+
|
69
|
+
content
|
70
|
+
end
|
71
|
+
|
72
|
+
def remove_git_source(content)
|
73
|
+
parsed_manifest = TomlRB.parse(content)
|
74
|
+
|
75
|
+
Dep::FileParser::REQUIREMENT_TYPES.each do |type|
|
76
|
+
(parsed_manifest[type] || []).each do |details|
|
77
|
+
next unless details["name"] == dependency.name
|
78
|
+
|
79
|
+
details.delete("revision")
|
80
|
+
details.delete("branch")
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
TomlRB.dump(parsed_manifest)
|
85
|
+
end
|
86
|
+
|
87
|
+
def replace_git_pin(content)
|
88
|
+
parsed_manifest = TomlRB.parse(content)
|
89
|
+
|
90
|
+
Dep::FileParser::REQUIREMENT_TYPES.each do |type|
|
91
|
+
(parsed_manifest[type] || []).each do |details|
|
92
|
+
next unless details["name"] == dependency.name
|
93
|
+
|
94
|
+
raise "Invalid details! #{details}" if details["branch"]
|
95
|
+
|
96
|
+
if details["version"]
|
97
|
+
details["version"] = replacement_git_pin
|
98
|
+
else
|
99
|
+
details["revision"] = replacement_git_pin
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
TomlRB.dump(parsed_manifest)
|
105
|
+
end
|
106
|
+
|
107
|
+
# Note: We don't need to care about formatting in this method, since
|
108
|
+
# we're only using the manifest to find the latest resolvable version
|
109
|
+
def replace_version_constraint(content, filename)
|
110
|
+
parsed_manifest = TomlRB.parse(content)
|
111
|
+
|
112
|
+
Dep::FileParser::REQUIREMENT_TYPES.each do |type|
|
113
|
+
(parsed_manifest[type] || []).each do |details|
|
114
|
+
next unless details["name"] == dependency.name
|
115
|
+
next if details["revision"] || details["branch"]
|
116
|
+
next if replacement_git_pin
|
117
|
+
|
118
|
+
updated_req = temporary_requirement_for_resolution(filename)
|
119
|
+
|
120
|
+
details["version"] = updated_req
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
TomlRB.dump(parsed_manifest)
|
125
|
+
end
|
126
|
+
|
127
|
+
# A dep bug means we have to specify a source for gopkg.in/fsnotify.v1
|
128
|
+
# or we get `panic: version queue is empty` errors
|
129
|
+
def add_fsnotify_override(content)
|
130
|
+
parsed_manifest = TomlRB.parse(content)
|
131
|
+
|
132
|
+
overrides = parsed_manifest.fetch("override", [])
|
133
|
+
dep_name = "gopkg.in/fsnotify.v1"
|
134
|
+
|
135
|
+
override = overrides.find { |s| s["name"] == dep_name }
|
136
|
+
if override.nil?
|
137
|
+
override = { "name" => dep_name }
|
138
|
+
overrides << override
|
139
|
+
end
|
140
|
+
|
141
|
+
unless override["source"]
|
142
|
+
override["source"] = "gopkg.in/fsnotify/fsnotify.v1"
|
143
|
+
end
|
144
|
+
|
145
|
+
parsed_manifest["override"] = overrides
|
146
|
+
TomlRB.dump(parsed_manifest)
|
147
|
+
end
|
148
|
+
|
149
|
+
def temporary_requirement_for_resolution(filename)
|
150
|
+
original_req = dependency.requirements.
|
151
|
+
find { |r| r.fetch(:file) == filename }&.
|
152
|
+
fetch(:requirement)
|
153
|
+
|
154
|
+
lower_bound_req =
|
155
|
+
if original_req && !unlock_requirement?
|
156
|
+
original_req
|
157
|
+
else
|
158
|
+
">= #{lower_bound_version}"
|
159
|
+
end
|
160
|
+
|
161
|
+
unless latest_allowable_version &&
|
162
|
+
version_class.correct?(latest_allowable_version) &&
|
163
|
+
version_class.new(latest_allowable_version) >=
|
164
|
+
version_class.new(lower_bound_version)
|
165
|
+
return lower_bound_req
|
166
|
+
end
|
167
|
+
|
168
|
+
lower_bound_req + ", <= #{latest_allowable_version}"
|
169
|
+
end
|
170
|
+
|
171
|
+
def lower_bound_version
|
172
|
+
@lower_bound_version ||=
|
173
|
+
if version_from_lockfile
|
174
|
+
version_from_lockfile
|
175
|
+
else
|
176
|
+
version_from_requirement =
|
177
|
+
dependency.requirements.map { |r| r.fetch(:requirement) }.
|
178
|
+
compact.
|
179
|
+
flat_map { |req_str| requirement_class.new(req_str) }.
|
180
|
+
flat_map(&:requirements).
|
181
|
+
reject { |req_array| req_array.first.start_with?("<") }.
|
182
|
+
map(&:last).
|
183
|
+
max&.to_s
|
184
|
+
|
185
|
+
version_from_requirement || 0
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
def version_from_lockfile
|
190
|
+
return unless lockfile
|
191
|
+
|
192
|
+
TomlRB.parse(lockfile.content).
|
193
|
+
fetch("projects", []).
|
194
|
+
find { |p| p["name"] == dependency.name }&.
|
195
|
+
fetch("version", nil)&.
|
196
|
+
sub(/^v?/, "")
|
197
|
+
end
|
198
|
+
|
199
|
+
def version_class
|
200
|
+
Utils.version_class_for_package_manager(dependency.package_manager)
|
201
|
+
end
|
202
|
+
|
203
|
+
def requirement_class
|
204
|
+
Utils.requirement_class_for_package_manager(
|
205
|
+
dependency.package_manager
|
206
|
+
)
|
207
|
+
end
|
208
|
+
|
209
|
+
def manifest
|
210
|
+
@manifest ||= dependency_files.find { |f| f.name == "Gopkg.toml" }
|
211
|
+
end
|
212
|
+
|
213
|
+
def lockfile
|
214
|
+
@lockfile ||= dependency_files.find { |f| f.name == "Gopkg.lock" }
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
@@ -0,0 +1,167 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "excon"
|
4
|
+
require "toml-rb"
|
5
|
+
|
6
|
+
require "dependabot/source"
|
7
|
+
require "dependabot/dep/update_checker"
|
8
|
+
require "dependabot/git_commit_checker"
|
9
|
+
require "dependabot/dep/path_converter"
|
10
|
+
|
11
|
+
module Dependabot
|
12
|
+
module Dep
|
13
|
+
class UpdateChecker
|
14
|
+
class LatestVersionFinder
|
15
|
+
def initialize(dependency:, dependency_files:, credentials:,
|
16
|
+
ignored_versions:)
|
17
|
+
@dependency = dependency
|
18
|
+
@dependency_files = dependency_files
|
19
|
+
@credentials = credentials
|
20
|
+
@ignored_versions = ignored_versions
|
21
|
+
end
|
22
|
+
|
23
|
+
def latest_version
|
24
|
+
@latest_version ||=
|
25
|
+
if git_dependency? then latest_version_for_git_dependency
|
26
|
+
else latest_release_tag_version
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
attr_reader :dependency, :dependency_files, :credentials,
|
33
|
+
:ignored_versions
|
34
|
+
|
35
|
+
def latest_release_tag_version
|
36
|
+
if @latest_release_tag_lookup_attempted
|
37
|
+
return @latest_release_tag_version
|
38
|
+
end
|
39
|
+
|
40
|
+
@latest_release_tag_lookup_attempted = true
|
41
|
+
|
42
|
+
latest_release_str = fetch_latest_release_tag&.sub(/^v?/, "")
|
43
|
+
return unless latest_release_str
|
44
|
+
return unless version_class.correct?(latest_release_str)
|
45
|
+
|
46
|
+
@latest_release_tag_version =
|
47
|
+
version_class.new(latest_release_str)
|
48
|
+
end
|
49
|
+
|
50
|
+
def fetch_latest_release_tag
|
51
|
+
# If this is a git dependency then getting the latest tag is trivial
|
52
|
+
if git_dependency?
|
53
|
+
return git_commit_checker.
|
54
|
+
local_tag_for_latest_version&.fetch(:tag)
|
55
|
+
end
|
56
|
+
|
57
|
+
# If not, we need to find the URL for the source code.
|
58
|
+
path = dependency.requirements.
|
59
|
+
map { |r| r.dig(:source, :source) }.compact.first
|
60
|
+
path ||= dependency.name
|
61
|
+
|
62
|
+
source_url = git_source(path)
|
63
|
+
return unless source_url
|
64
|
+
|
65
|
+
# Given a source, we want to find the latest tag. Piggy-back off the
|
66
|
+
# logic in GitCommitChecker to do so.
|
67
|
+
git_dep = Dependency.new(
|
68
|
+
name: dependency.name,
|
69
|
+
version: dependency.version,
|
70
|
+
requirements: [{
|
71
|
+
file: "Gopkg.toml",
|
72
|
+
groups: [],
|
73
|
+
requirement: nil,
|
74
|
+
source: { type: "git", url: source_url }
|
75
|
+
}],
|
76
|
+
package_manager: dependency.package_manager
|
77
|
+
)
|
78
|
+
|
79
|
+
GitCommitChecker.
|
80
|
+
new(dependency: git_dep, credentials: credentials).
|
81
|
+
local_tag_for_latest_version&.fetch(:tag)
|
82
|
+
end
|
83
|
+
|
84
|
+
def latest_version_for_git_dependency
|
85
|
+
latest_release = latest_release_tag_version
|
86
|
+
|
87
|
+
# If there's been a release that includes the current pinned ref or
|
88
|
+
# that the current branch is behind, we switch to that release.
|
89
|
+
return latest_release if branch_or_ref_in_release?(latest_release)
|
90
|
+
|
91
|
+
# Otherwise, if the gem isn't pinned, the latest version is just the
|
92
|
+
# latest commit for the specified branch.
|
93
|
+
unless git_commit_checker.pinned?
|
94
|
+
return git_commit_checker.head_commit_for_current_branch
|
95
|
+
end
|
96
|
+
|
97
|
+
# If the dependency is pinned to a tag that looks like a version
|
98
|
+
# then we want to update that tag.
|
99
|
+
if git_commit_checker.pinned_ref_looks_like_version?
|
100
|
+
latest_tag = git_commit_checker.local_tag_for_latest_version
|
101
|
+
return version_from_tag(latest_tag)
|
102
|
+
end
|
103
|
+
|
104
|
+
# If the dependency is pinned to a tag that doesn't look like a
|
105
|
+
# version then there's nothing we can do.
|
106
|
+
nil
|
107
|
+
end
|
108
|
+
|
109
|
+
def git_source(path)
|
110
|
+
Dependabot::Dep::PathConverter.git_url_for_path(path)
|
111
|
+
end
|
112
|
+
|
113
|
+
def version_from_tag(tag)
|
114
|
+
# To compare with the current version we either use the commit SHA
|
115
|
+
# (if that's what the parser picked up) of the tag name.
|
116
|
+
if dependency.version&.match?(/^[0-9a-f]{40}$/)
|
117
|
+
return tag&.fetch(:commit_sha)
|
118
|
+
end
|
119
|
+
|
120
|
+
tag&.fetch(:tag)
|
121
|
+
end
|
122
|
+
|
123
|
+
def branch_or_ref_in_release?(release)
|
124
|
+
return false unless release
|
125
|
+
|
126
|
+
git_commit_checker.branch_or_ref_in_release?(release)
|
127
|
+
end
|
128
|
+
|
129
|
+
def git_dependency?
|
130
|
+
git_commit_checker.git_dependency?
|
131
|
+
end
|
132
|
+
|
133
|
+
def git_commit_checker
|
134
|
+
@git_commit_checker ||=
|
135
|
+
GitCommitChecker.new(
|
136
|
+
dependency: dependency,
|
137
|
+
credentials: credentials,
|
138
|
+
ignored_versions: ignored_versions
|
139
|
+
)
|
140
|
+
end
|
141
|
+
|
142
|
+
def parsed_file(file)
|
143
|
+
@parsed_file ||= {}
|
144
|
+
@parsed_file[file.name] ||= TomlRB.parse(file.content)
|
145
|
+
end
|
146
|
+
|
147
|
+
def version_class
|
148
|
+
Utils.version_class_for_package_manager(dependency.package_manager)
|
149
|
+
end
|
150
|
+
|
151
|
+
def manifest
|
152
|
+
@manifest ||= dependency_files.find { |f| f.name == "Gopkg.toml" }
|
153
|
+
raise "No Gopkg.lock!" unless @manifest
|
154
|
+
|
155
|
+
@manifest
|
156
|
+
end
|
157
|
+
|
158
|
+
def lockfile
|
159
|
+
@lockfile = dependency_files.find { |f| f.name == "Gopkg.lock" }
|
160
|
+
raise "No Gopkg.lock!" unless @lockfile
|
161
|
+
|
162
|
+
@lockfile
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
@@ -0,0 +1,221 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dependabot/dep/update_checker"
|
4
|
+
require "dependabot/dep/requirement"
|
5
|
+
require "dependabot/dep/version"
|
6
|
+
|
7
|
+
module Dependabot
|
8
|
+
module Dep
|
9
|
+
class UpdateChecker
|
10
|
+
class RequirementsUpdater
|
11
|
+
class UnfixableRequirement < StandardError; end
|
12
|
+
|
13
|
+
VERSION_REGEX = /[0-9]+(?:\.[A-Za-z0-9\-*]+)*/.freeze
|
14
|
+
ALLOWED_UPDATE_STRATEGIES = %i(widen_ranges bump_versions).freeze
|
15
|
+
|
16
|
+
def initialize(requirements:, updated_source:, update_strategy:,
|
17
|
+
latest_version:, latest_resolvable_version:)
|
18
|
+
@requirements = requirements
|
19
|
+
@updated_source = updated_source
|
20
|
+
@update_strategy = update_strategy
|
21
|
+
|
22
|
+
check_update_strategy
|
23
|
+
|
24
|
+
if latest_version && version_class.correct?(latest_version)
|
25
|
+
@latest_version = version_class.new(latest_version)
|
26
|
+
end
|
27
|
+
|
28
|
+
return unless latest_resolvable_version
|
29
|
+
return unless version_class.correct?(latest_resolvable_version)
|
30
|
+
|
31
|
+
@latest_resolvable_version =
|
32
|
+
version_class.new(latest_resolvable_version)
|
33
|
+
end
|
34
|
+
|
35
|
+
def updated_requirements
|
36
|
+
requirements.map do |req|
|
37
|
+
req = req.merge(source: updated_source)
|
38
|
+
next req unless latest_resolvable_version
|
39
|
+
next initial_req_after_source_change(req) unless req[:requirement]
|
40
|
+
|
41
|
+
case update_strategy
|
42
|
+
when :widen_ranges then widen_requirement(req)
|
43
|
+
when :bump_versions then update_version(req)
|
44
|
+
else raise "Unexpected update strategy: #{update_strategy}"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
attr_reader :requirements, :updated_source, :update_strategy,
|
52
|
+
:latest_version, :latest_resolvable_version
|
53
|
+
|
54
|
+
def check_update_strategy
|
55
|
+
return if ALLOWED_UPDATE_STRATEGIES.include?(update_strategy)
|
56
|
+
|
57
|
+
raise "Unknown update strategy: #{update_strategy}"
|
58
|
+
end
|
59
|
+
|
60
|
+
def updating_from_git_to_version?
|
61
|
+
return false unless updated_source&.fetch(:type) == "default"
|
62
|
+
|
63
|
+
original_source = requirements.map { |r| r[:source] }.compact.first
|
64
|
+
original_source&.fetch(:type) == "git"
|
65
|
+
end
|
66
|
+
|
67
|
+
def initial_req_after_source_change(req)
|
68
|
+
return req unless updating_from_git_to_version?
|
69
|
+
return req unless req.fetch(:requirement).nil?
|
70
|
+
|
71
|
+
new_req =
|
72
|
+
if req.fetch(:file) == "go.mod"
|
73
|
+
"v#{latest_resolvable_version.to_s.gsub(/^v/, '')}"
|
74
|
+
else
|
75
|
+
"^#{latest_resolvable_version}"
|
76
|
+
end
|
77
|
+
req.merge(requirement: new_req)
|
78
|
+
end
|
79
|
+
|
80
|
+
def widen_requirement(req)
|
81
|
+
current_requirement = req[:requirement]
|
82
|
+
version = latest_resolvable_version
|
83
|
+
|
84
|
+
ruby_reqs = ruby_requirements(current_requirement)
|
85
|
+
return req if ruby_reqs.any? { |r| r.satisfied_by?(version) }
|
86
|
+
|
87
|
+
reqs = current_requirement.strip.split(",").map(&:strip)
|
88
|
+
|
89
|
+
updated_requirement =
|
90
|
+
if current_requirement.include?("||")
|
91
|
+
# Further widen the range by adding another OR condition
|
92
|
+
current_requirement + " || ^#{version}"
|
93
|
+
elsif reqs.any? { |r| r.match?(/(<|-\s)/) }
|
94
|
+
# Further widen the range by updating the upper bound
|
95
|
+
update_range_requirement(current_requirement)
|
96
|
+
else
|
97
|
+
# Convert existing requirement to a range
|
98
|
+
create_new_range_requirement(reqs)
|
99
|
+
end
|
100
|
+
|
101
|
+
req.merge(requirement: updated_requirement)
|
102
|
+
end
|
103
|
+
|
104
|
+
def update_version(req)
|
105
|
+
current_requirement = req[:requirement]
|
106
|
+
version = latest_resolvable_version
|
107
|
+
|
108
|
+
ruby_reqs = ruby_requirements(current_requirement)
|
109
|
+
reqs = current_requirement.strip.split(",").map(&:strip)
|
110
|
+
|
111
|
+
if ruby_reqs.any? { |r| r.satisfied_by?(version) } &&
|
112
|
+
current_requirement.match?(/(<|-\s|\|\|)/)
|
113
|
+
return req
|
114
|
+
end
|
115
|
+
|
116
|
+
updated_requirement =
|
117
|
+
if current_requirement.include?("||")
|
118
|
+
# Further widen the range by adding another OR condition
|
119
|
+
current_requirement + " || ^#{version}"
|
120
|
+
elsif reqs.any? { |r| r.match?(/(<|-\s)/) }
|
121
|
+
# Further widen the range by updating the upper bound
|
122
|
+
update_range_requirement(current_requirement)
|
123
|
+
else
|
124
|
+
update_version_requirement(reqs)
|
125
|
+
end
|
126
|
+
|
127
|
+
req.merge(requirement: updated_requirement)
|
128
|
+
end
|
129
|
+
|
130
|
+
def ruby_requirements(requirement_string)
|
131
|
+
requirement_class.requirements_array(requirement_string)
|
132
|
+
end
|
133
|
+
|
134
|
+
def update_range_requirement(req_string)
|
135
|
+
range_requirement = req_string.split(",").
|
136
|
+
find { |r| r.match?(/<|(\s+-\s+)/) }
|
137
|
+
|
138
|
+
versions = range_requirement.scan(VERSION_REGEX)
|
139
|
+
upper_bound = versions.map { |v| version_class.new(v) }.max
|
140
|
+
new_upper_bound = update_greatest_version(
|
141
|
+
upper_bound,
|
142
|
+
latest_resolvable_version
|
143
|
+
)
|
144
|
+
|
145
|
+
req_string.sub(
|
146
|
+
upper_bound.to_s,
|
147
|
+
new_upper_bound.to_s
|
148
|
+
)
|
149
|
+
end
|
150
|
+
|
151
|
+
def create_new_range_requirement(string_reqs)
|
152
|
+
version = latest_resolvable_version
|
153
|
+
|
154
|
+
lower_bound =
|
155
|
+
string_reqs.
|
156
|
+
map { |req| requirement_class.new(req) }.
|
157
|
+
flat_map { |req| req.requirements.map(&:last) }.
|
158
|
+
min.to_s
|
159
|
+
|
160
|
+
upper_bound =
|
161
|
+
if string_reqs.first.start_with?("~") &&
|
162
|
+
version.to_s.split(".").count > 1
|
163
|
+
create_upper_bound_for_tilda_req(string_reqs.first)
|
164
|
+
else
|
165
|
+
upper_bound_parts = [version.to_s.split(".").first.to_i + 1]
|
166
|
+
upper_bound_parts.
|
167
|
+
fill("0", 1..(lower_bound.split(".").count - 1)).
|
168
|
+
join(".")
|
169
|
+
end
|
170
|
+
|
171
|
+
">= #{lower_bound}, < #{upper_bound}"
|
172
|
+
end
|
173
|
+
|
174
|
+
def update_version_requirement(string_reqs)
|
175
|
+
version = latest_resolvable_version.to_s.gsub(/^v/, "")
|
176
|
+
current_req = string_reqs.first
|
177
|
+
|
178
|
+
current_req.gsub(VERSION_REGEX, version)
|
179
|
+
end
|
180
|
+
|
181
|
+
def create_upper_bound_for_tilda_req(string_req)
|
182
|
+
tilda_version = requirement_class.new(string_req).
|
183
|
+
requirements.map(&:last).
|
184
|
+
min.to_s
|
185
|
+
|
186
|
+
upper_bound_parts = latest_resolvable_version.to_s.split(".")
|
187
|
+
upper_bound_parts.slice(0, tilda_version.to_s.split(".").count)
|
188
|
+
upper_bound_parts[-1] = "0"
|
189
|
+
upper_bound_parts[-2] = (upper_bound_parts[-2].to_i + 1).to_s
|
190
|
+
|
191
|
+
upper_bound_parts.join(".")
|
192
|
+
end
|
193
|
+
|
194
|
+
def update_greatest_version(old_version, version_to_be_permitted)
|
195
|
+
version = version_class.new(old_version)
|
196
|
+
version = version.release if version.prerelease?
|
197
|
+
|
198
|
+
index_to_update =
|
199
|
+
version.segments.map.with_index { |seg, i| seg.zero? ? 0 : i }.max
|
200
|
+
|
201
|
+
version.segments.map.with_index do |_, index|
|
202
|
+
if index < index_to_update
|
203
|
+
version_to_be_permitted.segments[index]
|
204
|
+
elsif index == index_to_update
|
205
|
+
version_to_be_permitted.segments[index] + 1
|
206
|
+
else 0
|
207
|
+
end
|
208
|
+
end.join(".")
|
209
|
+
end
|
210
|
+
|
211
|
+
def version_class
|
212
|
+
Dep::Version
|
213
|
+
end
|
214
|
+
|
215
|
+
def requirement_class
|
216
|
+
Dep::Requirement
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|