dependabot-common 0.215.0 → 0.216.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/clients/azure.rb +69 -0
- data/lib/dependabot/clients/bitbucket.rb +3 -1
- data/lib/dependabot/clients/github_with_retries.rb +6 -0
- data/lib/dependabot/config/file_fetcher.rb +1 -1
- data/lib/dependabot/config/ignore_condition.rb +20 -13
- data/lib/dependabot/dependency.rb +63 -2
- data/lib/dependabot/dependency_file.rb +1 -1
- data/lib/dependabot/errors.rb +1 -1
- data/lib/dependabot/file_fetchers/base.rb +15 -4
- data/lib/dependabot/file_parsers/base/dependency_set.rb +19 -12
- data/lib/dependabot/file_parsers/base.rb +0 -2
- data/lib/dependabot/git_metadata_fetcher.rb +30 -25
- data/lib/dependabot/group_rule.rb +11 -0
- data/lib/dependabot/metadata_finders/README.md +1 -1
- data/lib/dependabot/metadata_finders/base/changelog_finder.rb +53 -11
- data/lib/dependabot/metadata_finders/base/commits_finder.rb +40 -3
- data/lib/dependabot/metadata_finders/base/release_finder.rb +1 -1
- data/lib/dependabot/pull_request_creator/branch_namer/group_rule_strategy.rb +28 -0
- data/lib/dependabot/pull_request_creator/branch_namer/solo_strategy.rb +208 -0
- data/lib/dependabot/pull_request_creator/branch_namer.rb +28 -179
- data/lib/dependabot/pull_request_creator/labeler.rb +5 -1
- data/lib/dependabot/pull_request_creator/message_builder/link_and_mention_sanitizer.rb +3 -1
- data/lib/dependabot/pull_request_creator/message_builder/metadata_presenter.rb +1 -1
- data/lib/dependabot/pull_request_creator/message_builder.rb +22 -81
- data/lib/dependabot/pull_request_creator.rb +1 -0
- data/lib/dependabot/security_advisory.rb +1 -1
- data/lib/dependabot/shared_helpers.rb +16 -3
- data/lib/dependabot/simple_instrumentor.rb +19 -0
- data/lib/dependabot/source.rb +7 -7
- data/lib/dependabot/version.rb +18 -1
- data/lib/dependabot.rb +1 -0
- metadata +46 -62
- data/lib/dependabot/notifications.rb +0 -18
- data/lib/rubygems_version_patch.rb +0 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 645d08a2a5cfd122e1ec0bb4302d7c4e80bd0348e0c0e52d28dc210d196b963b
|
4
|
+
data.tar.gz: 25d81216a7b48d60b332d241e06f3a7dcc384b06ea3f5fac1dcc02949da226dc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8ef726592da7c2ff04784322801d12902ab42613e53b084687acdbfb479982e60a5303cb6e7f249e5525547a7b7681af48c3afe9df16cfda435b771e5e3f84ad
|
7
|
+
data.tar.gz: ef3a1010b2dd5736c9595754b1eb1cf1cca4cd7eecdfae551b97a2d84c71952ccad43bedafab0f9b6cea07892afbff41b766d9d8941ae10bcd7eedb434970aa3
|
@@ -192,6 +192,32 @@ module Dependabot
|
|
192
192
|
"/pullrequests?api-version=5.0", content.to_json)
|
193
193
|
end
|
194
194
|
|
195
|
+
def autocomplete_pull_request(pull_request_id, auto_complete_set_by, merge_commit_message,
|
196
|
+
delete_source_branch = true, squash_merge = true, merge_strategy = "squash",
|
197
|
+
trans_work_items = true, ignore_config_ids = [])
|
198
|
+
|
199
|
+
content = {
|
200
|
+
autoCompleteSetBy: {
|
201
|
+
id: auto_complete_set_by
|
202
|
+
},
|
203
|
+
completionOptions: {
|
204
|
+
mergeCommitMessage: merge_commit_message,
|
205
|
+
deleteSourceBranch: delete_source_branch,
|
206
|
+
squashMerge: squash_merge,
|
207
|
+
mergeStrategy: merge_strategy,
|
208
|
+
transitionWorkItems: trans_work_items,
|
209
|
+
autoCompleteIgnoreConfigIds: ignore_config_ids
|
210
|
+
}
|
211
|
+
}
|
212
|
+
|
213
|
+
response = patch(source.api_endpoint +
|
214
|
+
source.organization + "/" + source.project +
|
215
|
+
"/_apis/git/repositories/" + source.unscoped_repo +
|
216
|
+
"/pullrequests/" + pull_request_id.to_s + "?api-version=5.1", content.to_json)
|
217
|
+
|
218
|
+
JSON.parse(response.body)
|
219
|
+
end
|
220
|
+
|
195
221
|
def pull_request(pull_request_id)
|
196
222
|
response = get(source.api_endpoint +
|
197
223
|
source.organization + "/" + source.project +
|
@@ -217,6 +243,18 @@ module Dependabot
|
|
217
243
|
end
|
218
244
|
# rubocop:enable Metrics/ParameterLists
|
219
245
|
|
246
|
+
def compare(previous_tag, new_tag, type)
|
247
|
+
response = get(source.api_endpoint +
|
248
|
+
source.organization + "/" + source.project +
|
249
|
+
"/_apis/git/repositories/" + source.unscoped_repo +
|
250
|
+
"/commits?searchCriteria.itemVersion.versionType=#{type}" \
|
251
|
+
"&searchCriteria.itemVersion.version=#{previous_tag}" \
|
252
|
+
"&searchCriteria.compareVersion.versionType=#{type}" \
|
253
|
+
"&searchCriteria.compareVersion.version=#{new_tag}")
|
254
|
+
|
255
|
+
JSON.parse(response.body).fetch("value")
|
256
|
+
end
|
257
|
+
|
220
258
|
def get(url)
|
221
259
|
response = nil
|
222
260
|
|
@@ -279,6 +317,37 @@ module Dependabot
|
|
279
317
|
response
|
280
318
|
end
|
281
319
|
|
320
|
+
def patch(url, json)
|
321
|
+
response = nil
|
322
|
+
|
323
|
+
retry_connection_failures do
|
324
|
+
response = Excon.patch(
|
325
|
+
url,
|
326
|
+
body: json,
|
327
|
+
user: credentials&.fetch("username", nil),
|
328
|
+
password: credentials&.fetch("password", nil),
|
329
|
+
idempotent: true,
|
330
|
+
**SharedHelpers.excon_defaults(
|
331
|
+
headers: auth_header.merge(
|
332
|
+
{
|
333
|
+
"Content-Type" => "application/json"
|
334
|
+
}
|
335
|
+
)
|
336
|
+
)
|
337
|
+
)
|
338
|
+
|
339
|
+
raise InternalServerError if response.status == 500
|
340
|
+
raise BadGateway if response.status == 502
|
341
|
+
raise ServiceNotAvailable if response.status == 503
|
342
|
+
end
|
343
|
+
|
344
|
+
raise Unauthorized if response.status == 401
|
345
|
+
raise Forbidden if response.status == 403
|
346
|
+
raise NotFound if response.status == 404
|
347
|
+
|
348
|
+
response
|
349
|
+
end
|
350
|
+
|
282
351
|
private
|
283
352
|
|
284
353
|
def retry_connection_failures
|
@@ -171,6 +171,8 @@ module Dependabot
|
|
171
171
|
base_url = "https://api.bitbucket.org/2.0/user?fields=uuid"
|
172
172
|
response = get(base_url)
|
173
173
|
JSON.parse(response.body).fetch("uuid")
|
174
|
+
rescue Unauthorized
|
175
|
+
[nil]
|
174
176
|
end
|
175
177
|
|
176
178
|
def default_reviewers(repo)
|
@@ -205,7 +207,7 @@ module Dependabot
|
|
205
207
|
|
206
208
|
def get(url)
|
207
209
|
response = Excon.get(
|
208
|
-
url,
|
210
|
+
URI::DEFAULT_PARSER.escape(url),
|
209
211
|
user: credentials&.fetch("username", nil),
|
210
212
|
password: credentials&.fetch("password", nil),
|
211
213
|
# Setting to false to prevent Excon retries, use BitbucketWithRetries for retries.
|
@@ -89,6 +89,12 @@ module Dependabot
|
|
89
89
|
access_tokens << nil if access_tokens.empty?
|
90
90
|
access_tokens.uniq!
|
91
91
|
|
92
|
+
# Explicitly set the proxy if one is set in the environment
|
93
|
+
# as Faraday's find_proxy is very slow.
|
94
|
+
Octokit.configure do |c|
|
95
|
+
c.proxy = ENV["HTTPS_PROXY"] if ENV["HTTPS_PROXY"]
|
96
|
+
end
|
97
|
+
|
92
98
|
Octokit.middleware = Faraday::RackBuilder.new do |builder|
|
93
99
|
builder.use Faraday::Retry::Middleware, exceptions: RETRYABLE_ERRORS, max: max_retries || 3
|
94
100
|
|
@@ -40,7 +40,7 @@ module Dependabot
|
|
40
40
|
end
|
41
41
|
|
42
42
|
unless self.class.required_files_in?(fetched_files.map(&:name))
|
43
|
-
raise Dependabot::DependencyFileNotFound, self.class.required_files_message
|
43
|
+
raise Dependabot::DependencyFileNotFound.new(nil, self.class.required_files_message)
|
44
44
|
end
|
45
45
|
|
46
46
|
fetched_files
|
@@ -32,16 +32,19 @@ module Dependabot
|
|
32
32
|
end
|
33
33
|
|
34
34
|
def versions_by_type(dependency)
|
35
|
-
|
35
|
+
version = correct_version_for(dependency)
|
36
|
+
return [] unless version
|
37
|
+
|
38
|
+
semver = version.to_semver
|
36
39
|
|
37
40
|
transformed_update_types.flat_map do |t|
|
38
41
|
case t
|
39
42
|
when PATCH_VERSION_TYPE
|
40
|
-
ignore_patch(
|
43
|
+
ignore_patch(semver)
|
41
44
|
when MINOR_VERSION_TYPE
|
42
|
-
ignore_minor(
|
45
|
+
ignore_minor(semver)
|
43
46
|
when MAJOR_VERSION_TYPE
|
44
|
-
ignore_major(
|
47
|
+
ignore_major(semver)
|
45
48
|
else
|
46
49
|
[]
|
47
50
|
end
|
@@ -49,8 +52,6 @@ module Dependabot
|
|
49
52
|
end
|
50
53
|
|
51
54
|
def ignore_patch(version)
|
52
|
-
return [] unless rubygems_compatible?(version)
|
53
|
-
|
54
55
|
parts = version.split(".")
|
55
56
|
version_parts = parts.fill(0, parts.length...2)
|
56
57
|
upper_parts = version_parts.first(1) + [version_parts[1].to_i + 1]
|
@@ -61,8 +62,6 @@ module Dependabot
|
|
61
62
|
end
|
62
63
|
|
63
64
|
def ignore_minor(version)
|
64
|
-
return [] unless rubygems_compatible?(version)
|
65
|
-
|
66
65
|
parts = version.split(".")
|
67
66
|
version_parts = parts.fill(0, parts.length...2)
|
68
67
|
lower_parts = version_parts.first(1) + [version_parts[1].to_i + 1] + ["a"]
|
@@ -74,8 +73,6 @@ module Dependabot
|
|
74
73
|
end
|
75
74
|
|
76
75
|
def ignore_major(version)
|
77
|
-
return [] unless rubygems_compatible?(version)
|
78
|
-
|
79
76
|
version_parts = version.split(".")
|
80
77
|
lower_parts = [version_parts[0].to_i + 1] + ["a"]
|
81
78
|
lower_bound = ">= #{lower_parts.join('.')}"
|
@@ -83,10 +80,20 @@ module Dependabot
|
|
83
80
|
[lower_bound]
|
84
81
|
end
|
85
82
|
|
86
|
-
def
|
87
|
-
|
83
|
+
def correct_version_for(dependency)
|
84
|
+
version = dependency.version
|
85
|
+
return if version.nil? || version.empty?
|
86
|
+
|
87
|
+
version_class = version_class_for(dependency.package_manager)
|
88
|
+
return unless version_class.correct?(version)
|
89
|
+
|
90
|
+
version_class.new(version)
|
91
|
+
end
|
88
92
|
|
89
|
-
|
93
|
+
def version_class_for(package_manager)
|
94
|
+
Utils.version_class_for_package_manager(package_manager)
|
95
|
+
rescue StandardError
|
96
|
+
Dependabot::Version
|
90
97
|
end
|
91
98
|
end
|
92
99
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "
|
3
|
+
require "dependabot/version"
|
4
4
|
|
5
5
|
module Dependabot
|
6
6
|
class Dependency
|
@@ -110,6 +110,67 @@ module Dependabot
|
|
110
110
|
display_name_builder.call(name)
|
111
111
|
end
|
112
112
|
|
113
|
+
def humanized_previous_version
|
114
|
+
# If we don't have a previous version, we *may* still be able to figure
|
115
|
+
# one out if a ref was provided and has been changed (in which case the
|
116
|
+
# previous ref was essentially the version).
|
117
|
+
if previous_version.nil?
|
118
|
+
return ref_changed? ? previous_ref : nil
|
119
|
+
end
|
120
|
+
|
121
|
+
if previous_version.match?(/^[0-9a-f]{40}/)
|
122
|
+
return previous_ref if ref_changed? && previous_ref
|
123
|
+
|
124
|
+
"`#{previous_version[0..6]}`"
|
125
|
+
elsif version == previous_version &&
|
126
|
+
package_manager == "docker"
|
127
|
+
digest = docker_digest_from_reqs(previous_requirements)
|
128
|
+
"`#{digest.split(':').last[0..6]}`"
|
129
|
+
else
|
130
|
+
previous_version
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def humanized_version
|
135
|
+
return if removed?
|
136
|
+
|
137
|
+
if version.match?(/^[0-9a-f]{40}/)
|
138
|
+
return new_ref if ref_changed? && new_ref
|
139
|
+
|
140
|
+
"`#{version[0..6]}`"
|
141
|
+
elsif version == previous_version &&
|
142
|
+
package_manager == "docker"
|
143
|
+
digest = docker_digest_from_reqs(requirements)
|
144
|
+
"`#{digest.split(':').last[0..6]}`"
|
145
|
+
else
|
146
|
+
version
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def docker_digest_from_reqs(requirements)
|
151
|
+
requirements.
|
152
|
+
filter_map { |r| r.dig(:source, "digest") || r.dig(:source, :digest) }.
|
153
|
+
first
|
154
|
+
end
|
155
|
+
|
156
|
+
def previous_ref
|
157
|
+
previous_refs = previous_requirements.filter_map do |r|
|
158
|
+
r.dig(:source, "ref") || r.dig(:source, :ref)
|
159
|
+
end.uniq
|
160
|
+
return previous_refs.first if previous_refs.count == 1
|
161
|
+
end
|
162
|
+
|
163
|
+
def new_ref
|
164
|
+
new_refs = requirements.filter_map do |r|
|
165
|
+
r.dig(:source, "ref") || r.dig(:source, :ref)
|
166
|
+
end.uniq
|
167
|
+
return new_refs.first if new_refs.count == 1
|
168
|
+
end
|
169
|
+
|
170
|
+
def ref_changed?
|
171
|
+
previous_ref != new_ref
|
172
|
+
end
|
173
|
+
|
113
174
|
# Returns all detected versions of the dependency. Only ecosystems that
|
114
175
|
# support this feature will return more than the current version.
|
115
176
|
def all_versions
|
@@ -135,7 +196,7 @@ module Dependabot
|
|
135
196
|
end
|
136
197
|
|
137
198
|
def eql?(other)
|
138
|
-
self
|
199
|
+
self == other
|
139
200
|
end
|
140
201
|
|
141
202
|
private
|
data/lib/dependabot/errors.rb
CHANGED
@@ -95,11 +95,17 @@ module Dependabot
|
|
95
95
|
rescue Dependabot::SharedHelpers::HelperSubprocessFailed => e
|
96
96
|
if e.message.include?("fatal: Remote branch #{target_branch} not found in upstream origin")
|
97
97
|
raise Dependabot::BranchNotFound, target_branch
|
98
|
+
elsif e.message.include?("No space left on device")
|
99
|
+
raise Dependabot::OutOfDisk
|
98
100
|
end
|
99
101
|
|
100
102
|
raise Dependabot::RepoNotFound, source
|
101
103
|
end
|
102
104
|
|
105
|
+
def package_manager_version
|
106
|
+
nil
|
107
|
+
end
|
108
|
+
|
103
109
|
private
|
104
110
|
|
105
111
|
def fetch_file_if_present(filename, fetch_submodules: false)
|
@@ -498,7 +504,7 @@ module Dependabot
|
|
498
504
|
_fetch_file_content_from_github(path, repo, commit)
|
499
505
|
when "gitlab"
|
500
506
|
tmp = gitlab_client.get_file(repo, path, commit).content
|
501
|
-
|
507
|
+
decode_binary_string(tmp)
|
502
508
|
when "azure"
|
503
509
|
azure_client.fetch_file_contents(commit, path)
|
504
510
|
when "bitbucket"
|
@@ -534,7 +540,7 @@ module Dependabot
|
|
534
540
|
# see https://github.blog/changelog/2022-05-03-increased-file-size-limit-when-retrieving-file-contents-via-rest-api/
|
535
541
|
github_client.contents(repo, path: path, ref: commit, accept: "application/vnd.github.v3.raw")
|
536
542
|
else
|
537
|
-
|
543
|
+
decode_binary_string(tmp.content)
|
538
544
|
end
|
539
545
|
rescue Octokit::Forbidden => e
|
540
546
|
raise unless e.message.include?("too_large")
|
@@ -549,7 +555,7 @@ module Dependabot
|
|
549
555
|
tmp = github_client.blob(repo, file_details.sha)
|
550
556
|
return tmp.content if tmp.encoding == "utf-8"
|
551
557
|
|
552
|
-
|
558
|
+
decode_binary_string(tmp.content)
|
553
559
|
end
|
554
560
|
# rubocop:enable Metrics/AbcSize
|
555
561
|
|
@@ -607,7 +613,7 @@ module Dependabot
|
|
607
613
|
CMD
|
608
614
|
)
|
609
615
|
rescue SharedHelpers::HelperSubprocessFailed => e
|
610
|
-
raise unless GIT_SUBMODULE_ERROR_REGEX && e.message.downcase.include?("submodule")
|
616
|
+
raise unless e.message.match(GIT_SUBMODULE_ERROR_REGEX) && e.message.downcase.include?("submodule")
|
611
617
|
|
612
618
|
submodule_cloning_failed = true
|
613
619
|
match = e.message.match(GIT_SUBMODULE_ERROR_REGEX)
|
@@ -652,6 +658,11 @@ module Dependabot
|
|
652
658
|
# rubocop:enable Metrics/MethodLength
|
653
659
|
# rubocop:enable Metrics/PerceivedComplexity
|
654
660
|
# rubocop:enable Metrics/BlockLength
|
661
|
+
|
662
|
+
def decode_binary_string(str)
|
663
|
+
bom = (+"\xEF\xBB\xBF").force_encoding(Encoding::BINARY)
|
664
|
+
Base64.decode64(str).delete_prefix(bom).force_encoding("UTF-8").encode
|
665
|
+
end
|
655
666
|
end
|
656
667
|
end
|
657
668
|
end
|
@@ -117,19 +117,10 @@ module Dependabot
|
|
117
117
|
|
118
118
|
# Produces a new dependency by merging the attributes of `old_dep` with those of
|
119
119
|
# `new_dep`. Requirements and subdependency metadata will be combined and deduped.
|
120
|
-
# The version of the combined dependency is determined by the
|
120
|
+
# The version of the combined dependency is determined by the
|
121
|
+
# `#combined_version` method below.
|
121
122
|
def combined_dependency(old_dep, new_dep)
|
122
|
-
version =
|
123
|
-
old_dep.version || new_dep.version
|
124
|
-
elsif !version_class.correct?(new_dep.version)
|
125
|
-
old_dep.version
|
126
|
-
elsif !version_class.correct?(old_dep.version)
|
127
|
-
new_dep.version
|
128
|
-
elsif version_class.new(new_dep.version) > version_class.new(old_dep.version)
|
129
|
-
old_dep.version
|
130
|
-
else
|
131
|
-
new_dep.version
|
132
|
-
end
|
123
|
+
version = combined_version(old_dep, new_dep)
|
133
124
|
requirements = (old_dep.requirements + new_dep.requirements).uniq
|
134
125
|
subdependency_metadata = (
|
135
126
|
(old_dep.subdependency_metadata || []) +
|
@@ -145,6 +136,22 @@ module Dependabot
|
|
145
136
|
)
|
146
137
|
end
|
147
138
|
|
139
|
+
def combined_version(old_dep, new_dep)
|
140
|
+
if old_dep.version.nil? ^ new_dep.version.nil?
|
141
|
+
[old_dep, new_dep].find(&:version).version
|
142
|
+
elsif old_dep.top_level? ^ new_dep.top_level? # Prefer a direct dependency over a transitive one
|
143
|
+
[old_dep, new_dep].find(&:top_level?).version
|
144
|
+
elsif !version_class.correct?(new_dep.version)
|
145
|
+
old_dep.version
|
146
|
+
elsif !version_class.correct?(old_dep.version)
|
147
|
+
new_dep.version
|
148
|
+
elsif version_class.new(new_dep.version) > version_class.new(old_dep.version)
|
149
|
+
old_dep.version
|
150
|
+
else
|
151
|
+
new_dep.version
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
148
155
|
def version_class
|
149
156
|
@version_class ||= Utils.version_class_for_package_manager(@combined.package_manager)
|
150
157
|
end
|
@@ -106,7 +106,7 @@ module Dependabot
|
|
106
106
|
|
107
107
|
def fetch_raw_upload_pack_with_git_for(uri)
|
108
108
|
service_pack_uri = uri
|
109
|
-
service_pack_uri += ".git" unless service_pack_uri.end_with?(".git")
|
109
|
+
service_pack_uri += ".git" unless service_pack_uri.end_with?(".git") || skip_git_suffix(uri)
|
110
110
|
|
111
111
|
env = { "PATH" => ENV.fetch("PATH", nil) }
|
112
112
|
command = "git ls-remote #{service_pack_uri}"
|
@@ -158,40 +158,45 @@ module Dependabot
|
|
158
158
|
def service_pack_uri(uri)
|
159
159
|
service_pack_uri = uri_with_auth(uri)
|
160
160
|
service_pack_uri = service_pack_uri.gsub(%r{/$}, "")
|
161
|
-
service_pack_uri += ".git" unless service_pack_uri.end_with?(".git")
|
161
|
+
service_pack_uri += ".git" unless service_pack_uri.end_with?(".git") || skip_git_suffix(uri)
|
162
162
|
service_pack_uri + "/info/refs?service=git-upload-pack"
|
163
163
|
end
|
164
164
|
|
165
|
+
def skip_git_suffix(uri)
|
166
|
+
# TODO: Unlike the other providers (GitHub, GitLab, BitBucket), as of 2023-01-18 Azure DevOps does not support the
|
167
|
+
# ".git" suffix. It will return a 404.
|
168
|
+
# So skip adding ".git" if looks like an ADO URI.
|
169
|
+
# There's no access to the source object here, so have to check the URI instead.
|
170
|
+
# Even if we had the current source object, the URI may be for a dependency hosted elsewhere.
|
171
|
+
# Unfortunately as a consequence, urls pointing to Azure DevOps Server will not work.
|
172
|
+
# Only alternative is to remove the addition of ".git" suffix since the other providers
|
173
|
+
# (GitHub, GitLab, BitBucket) work with or without the suffix.
|
174
|
+
# That change has other ramifications, so it'd be better if Azure started supporting ".git"
|
175
|
+
# like all the other providers.
|
176
|
+
uri = "https://#{uri.split('git@').last.sub(%r{:/?}, '/')}" if uri.start_with?("git@")
|
177
|
+
uri = URI(uri)
|
178
|
+
hostname = uri.hostname.to_s
|
179
|
+
hostname == "dev.azure.com" || hostname.end_with?(".visualstudio.com")
|
180
|
+
end
|
181
|
+
|
182
|
+
# Add in username and password if present in credentials.
|
183
|
+
# Credentials are never present for production Dependabot.
|
165
184
|
def uri_with_auth(uri)
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
uri.sub(%r{.*?://}, "")
|
170
|
-
end
|
185
|
+
# Handle SCP-style git URIs
|
186
|
+
uri = "https://#{uri.split('git@').last.sub(%r{:/?}, '/')}" if uri.start_with?("git@")
|
187
|
+
uri = URI(uri)
|
171
188
|
cred = credentials.select { |c| c["type"] == "git_source" }.
|
172
|
-
find { |c|
|
189
|
+
find { |c| uri.host == c["host"] }
|
173
190
|
|
174
|
-
scheme =
|
191
|
+
uri.scheme = "https" if uri.scheme != "http"
|
175
192
|
|
176
|
-
if
|
177
|
-
# URI already has authentication details
|
178
|
-
"#{scheme}://#{bare_uri}"
|
179
|
-
elsif cred&.fetch("username", nil) && cred&.fetch("password", nil)
|
193
|
+
if !uri.password && cred&.fetch("username", nil) && cred&.fetch("password", nil)
|
180
194
|
# URI doesn't have authentication details, but we have credentials
|
181
|
-
|
182
|
-
"
|
183
|
-
else
|
184
|
-
# No credentials, so just return the http(s) URI
|
185
|
-
"#{scheme}://#{bare_uri}"
|
195
|
+
uri.user = URI.encode_www_form_component(cred["username"])
|
196
|
+
uri.password = URI.encode_www_form_component(cred["password"])
|
186
197
|
end
|
187
|
-
end
|
188
198
|
|
189
|
-
|
190
|
-
if uri.match?(%r{^http://})
|
191
|
-
"http"
|
192
|
-
else
|
193
|
-
"https"
|
194
|
-
end
|
199
|
+
uri.to_s
|
195
200
|
end
|
196
201
|
|
197
202
|
def sha_for_update_pack_line(line)
|
@@ -45,7 +45,7 @@ and implement the following methods:
|
|
45
45
|
|
46
46
|
| Method | Description |
|
47
47
|
|------------------------|-------------------------|
|
48
|
-
| `#look_up_source` | Private method that returns a `Dependabot::Source` object. Generally the source details are extracted from a source code URL provided by the language's dependency registry, but sometimes it's already
|
48
|
+
| `#look_up_source` | Private method that returns a `Dependabot::Source` object. Generally the source details are extracted from a source code URL provided by the language's dependency registry, but sometimes it's already available from parsing the dependency file. |
|
49
49
|
|
50
50
|
To ensure the above are implemented, you should include
|
51
51
|
`it_behaves_like "a dependency metadata finder"` in your specs for the new
|
@@ -82,11 +82,12 @@ module Dependabot
|
|
82
82
|
return unless suggested_changelog_url
|
83
83
|
|
84
84
|
# TODO: Support other providers
|
85
|
-
|
86
|
-
return unless
|
85
|
+
suggested_source = Source.from_url(suggested_changelog_url)
|
86
|
+
return unless suggested_source&.provider == "github"
|
87
87
|
|
88
|
-
opts = { path:
|
89
|
-
|
88
|
+
opts = { path: suggested_source.directory, ref: suggested_source.branch }.compact
|
89
|
+
suggested_source_client = github_client_for_source(suggested_source)
|
90
|
+
tmp_files = suggested_source_client.contents(suggested_source.repo, opts)
|
90
91
|
|
91
92
|
filename = suggested_changelog_url.split("/").last.split("#").first
|
92
93
|
@changelog_from_suggested_url =
|
@@ -161,12 +162,13 @@ module Dependabot
|
|
161
162
|
@file_text ||= {}
|
162
163
|
|
163
164
|
unless @file_text.key?(file.download_url)
|
164
|
-
|
165
|
+
file_source = Source.from_url(file.html_url)
|
165
166
|
@file_text[file.download_url] =
|
166
|
-
case provider
|
167
|
-
when "github" then fetch_github_file(file)
|
167
|
+
case file_source.provider
|
168
|
+
when "github" then fetch_github_file(file_source, file)
|
168
169
|
when "gitlab" then fetch_gitlab_file(file)
|
169
170
|
when "bitbucket" then fetch_bitbucket_file(file)
|
171
|
+
when "azure" then fetch_azure_file(file)
|
170
172
|
when "codecommit" then nil # TODO: git file from codecommit
|
171
173
|
else raise "Unsupported provider '#{provider}'"
|
172
174
|
end
|
@@ -177,9 +179,9 @@ module Dependabot
|
|
177
179
|
@file_text[file.download_url].sub(/\n*\z/, "")
|
178
180
|
end
|
179
181
|
|
180
|
-
def fetch_github_file(file)
|
182
|
+
def fetch_github_file(file_source, file)
|
181
183
|
# Hitting the download URL directly causes encoding problems
|
182
|
-
raw_content =
|
184
|
+
raw_content = github_client_for_source(file_source).get(file.url).content
|
183
185
|
Base64.decode64(raw_content).force_encoding("UTF-8").encode
|
184
186
|
end
|
185
187
|
|
@@ -196,6 +198,11 @@ module Dependabot
|
|
196
198
|
force_encoding("UTF-8").encode
|
197
199
|
end
|
198
200
|
|
201
|
+
def fetch_azure_file(file)
|
202
|
+
azure_client.get(file.download_url).body.
|
203
|
+
force_encoding("UTF-8").encode
|
204
|
+
end
|
205
|
+
|
199
206
|
def upgrade_guide
|
200
207
|
return unless source
|
201
208
|
|
@@ -220,7 +227,7 @@ module Dependabot
|
|
220
227
|
when "github" then fetch_github_file_list(ref)
|
221
228
|
when "bitbucket" then fetch_bitbucket_file_list
|
222
229
|
when "gitlab" then fetch_gitlab_file_list
|
223
|
-
when "azure" then
|
230
|
+
when "azure" then fetch_azure_file_list
|
224
231
|
when "codecommit" then [] # TODO: Fetch Files from Codecommit
|
225
232
|
else raise "Unexpected repo provider '#{source.provider}'"
|
226
233
|
end
|
@@ -292,6 +299,29 @@ module Dependabot
|
|
292
299
|
[]
|
293
300
|
end
|
294
301
|
|
302
|
+
def fetch_azure_file_list
|
303
|
+
azure_client.fetch_repo_contents.map do |entry|
|
304
|
+
type = case entry.fetch("gitObjectType")
|
305
|
+
when "blob" then "file"
|
306
|
+
when "tree" then "dir"
|
307
|
+
else entry.fetch("gitObjectType")
|
308
|
+
end
|
309
|
+
|
310
|
+
OpenStruct.new(
|
311
|
+
name: File.basename(entry.fetch("relativePath")),
|
312
|
+
type: type,
|
313
|
+
size: entry.fetch("size"),
|
314
|
+
path: entry.fetch("relativePath"),
|
315
|
+
html_url: "#{source.url}?path=/#{entry.fetch('relativePath')}",
|
316
|
+
download_url: entry.fetch("url")
|
317
|
+
)
|
318
|
+
end
|
319
|
+
rescue Dependabot::Clients::Azure::NotFound,
|
320
|
+
Dependabot::Clients::Azure::Unauthorized,
|
321
|
+
Dependabot::Clients::Azure::Forbidden
|
322
|
+
[]
|
323
|
+
end
|
324
|
+
|
295
325
|
def new_version
|
296
326
|
return @new_version if defined?(@new_version)
|
297
327
|
|
@@ -346,7 +376,19 @@ module Dependabot
|
|
346
376
|
|
347
377
|
def github_client
|
348
378
|
@github_client ||= Dependabot::Clients::GithubWithRetries.
|
349
|
-
|
379
|
+
for_source(source: source, credentials: credentials)
|
380
|
+
end
|
381
|
+
|
382
|
+
def azure_client
|
383
|
+
@azure_client ||= Dependabot::Clients::Azure.
|
384
|
+
for_source(source: source, credentials: credentials)
|
385
|
+
end
|
386
|
+
|
387
|
+
def github_client_for_source(client_source)
|
388
|
+
return github_client if client_source == source
|
389
|
+
|
390
|
+
Dependabot::Clients::GithubWithRetries.
|
391
|
+
for_source(source: client_source, credentials: credentials)
|
350
392
|
end
|
351
393
|
|
352
394
|
def bitbucket_client
|