dependabot-core 0.89.5 → 0.90.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.
@@ -1,169 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "excon"
4
- require "toml-rb"
5
-
6
- require "dependabot/source"
7
- require "dependabot/update_checkers/go/dep"
8
- require "dependabot/git_commit_checker"
9
- require "dependabot/utils/go/path_converter"
10
-
11
- module Dependabot
12
- module UpdateCheckers
13
- module Go
14
- class Dep
15
- class LatestVersionFinder
16
- def initialize(dependency:, dependency_files:, credentials:,
17
- ignored_versions:)
18
- @dependency = dependency
19
- @dependency_files = dependency_files
20
- @credentials = credentials
21
- @ignored_versions = ignored_versions
22
- end
23
-
24
- def latest_version
25
- @latest_version ||=
26
- if git_dependency? then latest_version_for_git_dependency
27
- else latest_release_tag_version
28
- end
29
- end
30
-
31
- private
32
-
33
- attr_reader :dependency, :dependency_files, :credentials,
34
- :ignored_versions
35
-
36
- def latest_release_tag_version
37
- if @latest_release_tag_lookup_attempted
38
- return @latest_release_tag_version
39
- end
40
-
41
- @latest_release_tag_lookup_attempted = true
42
-
43
- latest_release_str = fetch_latest_release_tag&.sub(/^v?/, "")
44
- return unless latest_release_str
45
- return unless version_class.correct?(latest_release_str)
46
-
47
- @latest_release_tag_version =
48
- version_class.new(latest_release_str)
49
- end
50
-
51
- def fetch_latest_release_tag
52
- # If this is a git dependency then getting the latest tag is trivial
53
- if git_dependency?
54
- return git_commit_checker.
55
- local_tag_for_latest_version&.fetch(:tag)
56
- end
57
-
58
- # If not, we need to find the URL for the source code.
59
- path = dependency.requirements.
60
- map { |r| r.dig(:source, :source) }.compact.first
61
- path ||= dependency.name
62
-
63
- source_url = git_source(path)
64
- return unless source_url
65
-
66
- # Given a source, we want to find the latest tag. Piggy-back off the
67
- # logic in GitCommitChecker to do so.
68
- git_dep = Dependency.new(
69
- name: dependency.name,
70
- version: dependency.version,
71
- requirements: [{
72
- file: "Gopkg.toml",
73
- groups: [],
74
- requirement: nil,
75
- source: { type: "git", url: source_url }
76
- }],
77
- package_manager: dependency.package_manager
78
- )
79
-
80
- GitCommitChecker.
81
- new(dependency: git_dep, credentials: credentials).
82
- local_tag_for_latest_version&.fetch(:tag)
83
- end
84
-
85
- def latest_version_for_git_dependency
86
- latest_release = latest_release_tag_version
87
-
88
- # If there's been a release that includes the current pinned ref or
89
- # that the current branch is behind, we switch to that release.
90
- return latest_release if branch_or_ref_in_release?(latest_release)
91
-
92
- # Otherwise, if the gem isn't pinned, the latest version is just the
93
- # latest commit for the specified branch.
94
- unless git_commit_checker.pinned?
95
- return git_commit_checker.head_commit_for_current_branch
96
- end
97
-
98
- # If the dependency is pinned to a tag that looks like a version
99
- # then we want to update that tag.
100
- if git_commit_checker.pinned_ref_looks_like_version?
101
- latest_tag = git_commit_checker.local_tag_for_latest_version
102
- return version_from_tag(latest_tag)
103
- end
104
-
105
- # If the dependency is pinned to a tag that doesn't look like a
106
- # version then there's nothing we can do.
107
- nil
108
- end
109
-
110
- def git_source(path)
111
- Dependabot::Utils::Go::PathConverter.git_url_for_path(path)
112
- end
113
-
114
- def version_from_tag(tag)
115
- # To compare with the current version we either use the commit SHA
116
- # (if that's what the parser picked up) of the tag name.
117
- if dependency.version&.match?(/^[0-9a-f]{40}$/)
118
- return tag&.fetch(:commit_sha)
119
- end
120
-
121
- tag&.fetch(:tag)
122
- end
123
-
124
- def branch_or_ref_in_release?(release)
125
- return false unless release
126
-
127
- git_commit_checker.branch_or_ref_in_release?(release)
128
- end
129
-
130
- def git_dependency?
131
- git_commit_checker.git_dependency?
132
- end
133
-
134
- def git_commit_checker
135
- @git_commit_checker ||=
136
- GitCommitChecker.new(
137
- dependency: dependency,
138
- credentials: credentials,
139
- ignored_versions: ignored_versions
140
- )
141
- end
142
-
143
- def parsed_file(file)
144
- @parsed_file ||= {}
145
- @parsed_file[file.name] ||= TomlRB.parse(file.content)
146
- end
147
-
148
- def version_class
149
- Utils.version_class_for_package_manager(dependency.package_manager)
150
- end
151
-
152
- def manifest
153
- @manifest ||= dependency_files.find { |f| f.name == "Gopkg.toml" }
154
- raise "No Gopkg.lock!" unless @manifest
155
-
156
- @manifest
157
- end
158
-
159
- def lockfile
160
- @lockfile = dependency_files.find { |f| f.name == "Gopkg.lock" }
161
- raise "No Gopkg.lock!" unless @lockfile
162
-
163
- @lockfile
164
- end
165
- end
166
- end
167
- end
168
- end
169
- end
@@ -1,223 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "dependabot/update_checkers/go/dep"
4
- require "dependabot/utils/go/requirement"
5
- require "dependabot/utils/go/version"
6
-
7
- module Dependabot
8
- module UpdateCheckers
9
- module Go
10
- class Dep
11
- class RequirementsUpdater
12
- class UnfixableRequirement < StandardError; end
13
-
14
- VERSION_REGEX = /[0-9]+(?:\.[A-Za-z0-9\-*]+)*/.freeze
15
- ALLOWED_UPDATE_STRATEGIES = %i(widen_ranges bump_versions).freeze
16
-
17
- def initialize(requirements:, updated_source:, update_strategy:,
18
- latest_version:, latest_resolvable_version:)
19
- @requirements = requirements
20
- @updated_source = updated_source
21
- @update_strategy = update_strategy
22
-
23
- check_update_strategy
24
-
25
- if latest_version && version_class.correct?(latest_version)
26
- @latest_version = version_class.new(latest_version)
27
- end
28
-
29
- return unless latest_resolvable_version
30
- return unless version_class.correct?(latest_resolvable_version)
31
-
32
- @latest_resolvable_version =
33
- version_class.new(latest_resolvable_version)
34
- end
35
-
36
- def updated_requirements
37
- requirements.map do |req|
38
- req = req.merge(source: updated_source)
39
- next req unless latest_resolvable_version
40
- next initial_req_after_source_change(req) unless req[:requirement]
41
-
42
- case update_strategy
43
- when :widen_ranges then widen_requirement(req)
44
- when :bump_versions then update_version(req)
45
- else raise "Unexpected update strategy: #{update_strategy}"
46
- end
47
- end
48
- end
49
-
50
- private
51
-
52
- attr_reader :requirements, :updated_source, :update_strategy,
53
- :latest_version, :latest_resolvable_version
54
-
55
- def check_update_strategy
56
- return if ALLOWED_UPDATE_STRATEGIES.include?(update_strategy)
57
-
58
- raise "Unknown update strategy: #{update_strategy}"
59
- end
60
-
61
- def updating_from_git_to_version?
62
- return false unless updated_source&.fetch(:type) == "default"
63
-
64
- original_source = requirements.map { |r| r[:source] }.compact.first
65
- original_source&.fetch(:type) == "git"
66
- end
67
-
68
- def initial_req_after_source_change(req)
69
- return req unless updating_from_git_to_version?
70
- return req unless req.fetch(:requirement).nil?
71
-
72
- new_req =
73
- if req.fetch(:file) == "go.mod"
74
- "v#{latest_resolvable_version.to_s.gsub(/^v/, '')}"
75
- else
76
- "^#{latest_resolvable_version}"
77
- end
78
- req.merge(requirement: new_req)
79
- end
80
-
81
- def widen_requirement(req)
82
- current_requirement = req[:requirement]
83
- version = latest_resolvable_version
84
-
85
- ruby_reqs = ruby_requirements(current_requirement)
86
- return req if ruby_reqs.any? { |r| r.satisfied_by?(version) }
87
-
88
- reqs = current_requirement.strip.split(",").map(&:strip)
89
-
90
- updated_requirement =
91
- if current_requirement.include?("||")
92
- # Further widen the range by adding another OR condition
93
- current_requirement + " || ^#{version}"
94
- elsif reqs.any? { |r| r.match?(/(<|-\s)/) }
95
- # Further widen the range by updating the upper bound
96
- update_range_requirement(current_requirement)
97
- else
98
- # Convert existing requirement to a range
99
- create_new_range_requirement(reqs)
100
- end
101
-
102
- req.merge(requirement: updated_requirement)
103
- end
104
-
105
- def update_version(req)
106
- current_requirement = req[:requirement]
107
- version = latest_resolvable_version
108
-
109
- ruby_reqs = ruby_requirements(current_requirement)
110
- reqs = current_requirement.strip.split(",").map(&:strip)
111
-
112
- if ruby_reqs.any? { |r| r.satisfied_by?(version) } &&
113
- current_requirement.match?(/(<|-\s|\|\|)/)
114
- return req
115
- end
116
-
117
- updated_requirement =
118
- if current_requirement.include?("||")
119
- # Further widen the range by adding another OR condition
120
- current_requirement + " || ^#{version}"
121
- elsif reqs.any? { |r| r.match?(/(<|-\s)/) }
122
- # Further widen the range by updating the upper bound
123
- update_range_requirement(current_requirement)
124
- else
125
- update_version_requirement(reqs)
126
- end
127
-
128
- req.merge(requirement: updated_requirement)
129
- end
130
-
131
- def ruby_requirements(requirement_string)
132
- requirement_class.requirements_array(requirement_string)
133
- end
134
-
135
- def update_range_requirement(req_string)
136
- range_requirement = req_string.split(",").
137
- find { |r| r.match?(/<|(\s+-\s+)/) }
138
-
139
- versions = range_requirement.scan(VERSION_REGEX)
140
- upper_bound = versions.map { |v| version_class.new(v) }.max
141
- new_upper_bound = update_greatest_version(
142
- upper_bound,
143
- latest_resolvable_version
144
- )
145
-
146
- req_string.sub(
147
- upper_bound.to_s,
148
- new_upper_bound.to_s
149
- )
150
- end
151
-
152
- def create_new_range_requirement(string_reqs)
153
- version = latest_resolvable_version
154
-
155
- lower_bound =
156
- string_reqs.
157
- map { |req| requirement_class.new(req) }.
158
- flat_map { |req| req.requirements.map(&:last) }.
159
- min.to_s
160
-
161
- upper_bound =
162
- if string_reqs.first.start_with?("~") &&
163
- version.to_s.split(".").count > 1
164
- create_upper_bound_for_tilda_req(string_reqs.first)
165
- else
166
- upper_bound_parts = [version.to_s.split(".").first.to_i + 1]
167
- upper_bound_parts.
168
- fill("0", 1..(lower_bound.split(".").count - 1)).
169
- join(".")
170
- end
171
-
172
- ">= #{lower_bound}, < #{upper_bound}"
173
- end
174
-
175
- def update_version_requirement(string_reqs)
176
- version = latest_resolvable_version.to_s.gsub(/^v/, "")
177
- current_req = string_reqs.first
178
-
179
- current_req.gsub(VERSION_REGEX, version)
180
- end
181
-
182
- def create_upper_bound_for_tilda_req(string_req)
183
- tilda_version = requirement_class.new(string_req).
184
- requirements.map(&:last).
185
- min.to_s
186
-
187
- upper_bound_parts = latest_resolvable_version.to_s.split(".")
188
- upper_bound_parts.slice(0, tilda_version.to_s.split(".").count)
189
- upper_bound_parts[-1] = "0"
190
- upper_bound_parts[-2] = (upper_bound_parts[-2].to_i + 1).to_s
191
-
192
- upper_bound_parts.join(".")
193
- end
194
-
195
- def update_greatest_version(old_version, version_to_be_permitted)
196
- version = version_class.new(old_version)
197
- version = version.release if version.prerelease?
198
-
199
- index_to_update =
200
- version.segments.map.with_index { |seg, i| seg.zero? ? 0 : i }.max
201
-
202
- version.segments.map.with_index do |_, index|
203
- if index < index_to_update
204
- version_to_be_permitted.segments[index]
205
- elsif index == index_to_update
206
- version_to_be_permitted.segments[index] + 1
207
- else 0
208
- end
209
- end.join(".")
210
- end
211
-
212
- def version_class
213
- Utils::Go::Version
214
- end
215
-
216
- def requirement_class
217
- Utils::Go::Requirement
218
- end
219
- end
220
- end
221
- end
222
- end
223
- end
@@ -1,168 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "toml-rb"
4
- require "open3"
5
- require "dependabot/shared_helpers"
6
- require "dependabot/update_checkers/go/dep"
7
- require "dependabot/errors"
8
-
9
- module Dependabot
10
- module UpdateCheckers
11
- module Go
12
- class Dep
13
- class VersionResolver
14
- NOT_FOUND_REGEX =
15
- /failed to list versions for (?<repo_url>.*?):\s+/.freeze
16
- INDEX_OUT_OF_RANGE_REGEX =
17
- /panic: runtime error: index out of range.*findValidVersion/m.freeze
18
-
19
- def initialize(dependency:, dependency_files:, credentials:)
20
- @dependency = dependency
21
- @dependency_files = dependency_files
22
- @credentials = credentials
23
- end
24
-
25
- def latest_resolvable_version
26
- if defined?(@latest_resolvable_version)
27
- return @latest_resolvable_version
28
- end
29
-
30
- @latest_resolvable_version = fetch_latest_resolvable_version
31
- end
32
-
33
- private
34
-
35
- attr_reader :dependency, :dependency_files, :credentials
36
-
37
- def fetch_latest_resolvable_version
38
- base_directory = File.join("src", "project",
39
- dependency_files.first.directory)
40
- base_parts = base_directory.split("/").length
41
- updated_version =
42
- SharedHelpers.in_a_temporary_directory(base_directory) do |dir|
43
- write_temporary_dependency_files
44
-
45
- SharedHelpers.with_git_configured(credentials: credentials) do
46
- # Shell out to dep, which handles everything for us, and does
47
- # so without doing an install (so it's fast).
48
- command = "dep ensure -update --no-vendor #{dependency.name}"
49
- dir_parts = dir.realpath.to_s.split("/")
50
- gopath = File.join(dir_parts[0..-(base_parts + 1)])
51
- run_shell_command(command, "GOPATH" => gopath)
52
- end
53
-
54
- new_lockfile_content = File.read("Gopkg.lock")
55
-
56
- get_version_from_lockfile(new_lockfile_content)
57
- end
58
-
59
- updated_version
60
- rescue SharedHelpers::HelperSubprocessFailed => error
61
- handle_dep_errors(error)
62
- end
63
-
64
- def get_version_from_lockfile(lockfile_content)
65
- package = TomlRB.parse(lockfile_content).fetch("projects").
66
- find { |p| p["name"] == dependency.name }
67
-
68
- version = package["version"]
69
-
70
- if version && version_class.correct?(version.sub(/^v?/, ""))
71
- version_class.new(version.sub(/^v?/, ""))
72
- elsif version
73
- version
74
- else
75
- package.fetch("revision")
76
- end
77
- end
78
-
79
- def handle_dep_errors(error)
80
- if error.message.match?(NOT_FOUND_REGEX)
81
- url = error.message.match(NOT_FOUND_REGEX).
82
- named_captures.fetch("repo_url")
83
-
84
- raise Dependabot::GitDependenciesNotReachable, url
85
- end
86
-
87
- # A dep bug that probably isn't going to be fixed any time soon :-(
88
- # - https://github.com/golang/dep/issues/1437
89
- # - https://github.com/golang/dep/issues/649
90
- # - https://github.com/golang/dep/issues/2041
91
- # - https://twitter.com/miekg/status/996682296739745792
92
- return if error.message.match?(INDEX_OUT_OF_RANGE_REGEX)
93
-
94
- raise
95
- end
96
-
97
- def run_shell_command(command, env = {})
98
- start = Time.now
99
- stdout, process = Open3.capture2e(env, command)
100
- time_taken = start - Time.now
101
-
102
- # Raise an error with the output from the shell session if dep
103
- # returns a non-zero status
104
- return if process.success?
105
-
106
- raise SharedHelpers::HelperSubprocessFailed.new(
107
- message: stdout,
108
- error_context: {
109
- command: command,
110
- time_taken: time_taken,
111
- process_exit_value: process.to_s
112
- }
113
- )
114
- end
115
-
116
- def write_temporary_dependency_files
117
- dependency_files.each do |file|
118
- path = file.name
119
- FileUtils.mkdir_p(Pathname.new(path).dirname)
120
- File.write(file.name, file.content)
121
- end
122
-
123
- File.write("hello.go", dummy_app_content)
124
- end
125
-
126
- def dummy_app_content
127
- base = "package main\n\n"\
128
- "import \"fmt\"\n\n"
129
-
130
- packages_to_import.each { |nm| base += "import \"#{nm}\"\n\n" }
131
-
132
- base + "func main() {\n fmt.Printf(\"hello, world\\n\")\n}"
133
- end
134
-
135
- def packages_to_import
136
- return [] unless lockfile
137
-
138
- parsed_lockfile = TomlRB.parse(lockfile.content)
139
-
140
- # If the lockfile was created using dep v0.5.0+ then it will tell us
141
- # exactly which packages to import
142
- if parsed_lockfile.dig("solve-meta", "input-imports")
143
- return parsed_lockfile.dig("solve-meta", "input-imports")
144
- end
145
-
146
- # Otherwise we have no way of knowing, so import everything in the
147
- # lockfile that isn't marked as internal
148
- parsed_lockfile.fetch("projects").flat_map do |dep|
149
- dep["packages"].map do |package|
150
- next if package.start_with?("internal")
151
-
152
- package == "." ? dep["name"] : File.join(dep["name"], package)
153
- end.compact
154
- end
155
- end
156
-
157
- def lockfile
158
- @lockfile = dependency_files.find { |f| f.name == "Gopkg.lock" }
159
- end
160
-
161
- def version_class
162
- Utils.version_class_for_package_manager(dependency.package_manager)
163
- end
164
- end
165
- end
166
- end
167
- end
168
- end