dependabot-common 0.119.4 → 0.120.2
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/lib/dependabot/clients/azure.rb +15 -10
- data/lib/dependabot/git_metadata_fetcher.rb +1 -1
- data/lib/dependabot/pull_request_creator.rb +16 -3
- data/lib/dependabot/pull_request_creator/azure.rb +6 -6
- data/lib/dependabot/pull_request_creator/github.rb +38 -8
- data/lib/dependabot/pull_request_creator/message_builder.rb +15 -258
- data/lib/dependabot/pull_request_creator/message_builder/metadata_presenter.rb +270 -0
- data/lib/dependabot/shared_helpers.rb +16 -3
- data/lib/dependabot/version.rb +1 -1
- metadata +5 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 83263fa7e5a3d1dbd38624d9476cab98b226ef442af42cd6e9324dcb61226476
|
|
4
|
+
data.tar.gz: a47175b2fb55cb804e95a1f438f21de893f73b3921b319bcb296e3ff7f0397da
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c04da188b4d2914b86db40c0640074d45010ce6f0834117b3b6b9faf6371893af47bafd643b4d905a5db2f853c21e3c6cc8c40df38659b93281299820fb6b812
|
|
7
|
+
data.tar.gz: f6e8639ddfc7ffdd50926c3f32e1087076f3e66ad915eb074663669537b37b993df346dda6fc35144e0fd02aedba423b609e5d6eb596d35ecc67cace0c2c12f7
|
|
@@ -153,8 +153,9 @@ module Dependabot
|
|
|
153
153
|
"/pushes?api-version=5.0", content.to_json)
|
|
154
154
|
end
|
|
155
155
|
|
|
156
|
+
# rubocop:disable Metrics/ParameterLists
|
|
156
157
|
def create_pull_request(pr_name, source_branch, target_branch,
|
|
157
|
-
pr_description, labels)
|
|
158
|
+
pr_description, labels, work_item = nil)
|
|
158
159
|
# Azure DevOps only support descriptions up to 4000 characters
|
|
159
160
|
# https://developercommunity.visualstudio.com/content/problem/608770/remove-4000-character-limit-on-pull-request-descri.html
|
|
160
161
|
azure_max_length = 3999
|
|
@@ -163,13 +164,15 @@ module Dependabot
|
|
|
163
164
|
truncate_length = azure_max_length - truncated_msg.length
|
|
164
165
|
pr_description = pr_description[0..truncate_length] + truncated_msg
|
|
165
166
|
end
|
|
167
|
+
# rubocop:enable Metrics/ParameterLists
|
|
166
168
|
|
|
167
169
|
content = {
|
|
168
170
|
sourceRefName: "refs/heads/" + source_branch,
|
|
169
171
|
targetRefName: "refs/heads/" + target_branch,
|
|
170
172
|
title: pr_name,
|
|
171
173
|
description: pr_description,
|
|
172
|
-
labels: labels.map { |label| { name: label } }
|
|
174
|
+
labels: labels.map { |label| { name: label } },
|
|
175
|
+
workItemRefs: [{ id: work_item }]
|
|
173
176
|
}
|
|
174
177
|
|
|
175
178
|
post(source.api_endpoint +
|
|
@@ -181,11 +184,12 @@ module Dependabot
|
|
|
181
184
|
def get(url)
|
|
182
185
|
response = Excon.get(
|
|
183
186
|
url,
|
|
184
|
-
headers: auth_header,
|
|
185
187
|
user: credentials&.fetch("username", nil),
|
|
186
188
|
password: credentials&.fetch("password", nil),
|
|
187
189
|
idempotent: true,
|
|
188
|
-
**SharedHelpers.excon_defaults
|
|
190
|
+
**SharedHelpers.excon_defaults(
|
|
191
|
+
headers: auth_header
|
|
192
|
+
)
|
|
189
193
|
)
|
|
190
194
|
raise NotFound if response.status == 404
|
|
191
195
|
|
|
@@ -195,16 +199,17 @@ module Dependabot
|
|
|
195
199
|
def post(url, json)
|
|
196
200
|
response = Excon.post(
|
|
197
201
|
url,
|
|
198
|
-
headers: auth_header.merge(
|
|
199
|
-
{
|
|
200
|
-
"Content-Type" => "application/json"
|
|
201
|
-
}
|
|
202
|
-
),
|
|
203
202
|
body: json,
|
|
204
203
|
user: credentials&.fetch("username", nil),
|
|
205
204
|
password: credentials&.fetch("password", nil),
|
|
206
205
|
idempotent: true,
|
|
207
|
-
**SharedHelpers.excon_defaults
|
|
206
|
+
**SharedHelpers.excon_defaults(
|
|
207
|
+
headers: auth_header.merge(
|
|
208
|
+
{
|
|
209
|
+
"Content-Type" => "application/json"
|
|
210
|
+
}
|
|
211
|
+
)
|
|
212
|
+
)
|
|
208
213
|
)
|
|
209
214
|
raise NotFound if response.status == 404
|
|
210
215
|
|
|
@@ -17,13 +17,23 @@ module Dependabot
|
|
|
17
17
|
class RepoDisabled < StandardError; end
|
|
18
18
|
class NoHistoryInCommon < StandardError; end
|
|
19
19
|
|
|
20
|
+
# AnnotationError is raised if a PR was created, but failed annotation
|
|
21
|
+
class AnnotationError < StandardError
|
|
22
|
+
attr_reader :cause, :pull_request
|
|
23
|
+
def initialize(cause, pull_request)
|
|
24
|
+
super(cause.message)
|
|
25
|
+
@cause = cause
|
|
26
|
+
@pull_request = pull_request
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
20
30
|
attr_reader :source, :dependencies, :files, :base_commit,
|
|
21
31
|
:credentials, :pr_message_header, :pr_message_footer,
|
|
22
32
|
:custom_labels, :author_details, :signature_key,
|
|
23
33
|
:commit_message_options, :vulnerabilities_fixed,
|
|
24
34
|
:reviewers, :assignees, :milestone, :branch_name_separator,
|
|
25
35
|
:branch_name_prefix, :github_redirection_service,
|
|
26
|
-
:custom_headers
|
|
36
|
+
:custom_headers, :provider_metadata
|
|
27
37
|
|
|
28
38
|
def initialize(source:, base_commit:, dependencies:, files:, credentials:,
|
|
29
39
|
pr_message_header: nil, pr_message_footer: nil,
|
|
@@ -33,7 +43,8 @@ module Dependabot
|
|
|
33
43
|
branch_name_separator: "/", branch_name_prefix: "dependabot",
|
|
34
44
|
label_language: false, automerge_candidate: false,
|
|
35
45
|
github_redirection_service: "github-redirect.dependabot.com",
|
|
36
|
-
custom_headers: nil, require_up_to_date_base: false
|
|
46
|
+
custom_headers: nil, require_up_to_date_base: false,
|
|
47
|
+
provider_metadata: {})
|
|
37
48
|
@dependencies = dependencies
|
|
38
49
|
@source = source
|
|
39
50
|
@base_commit = base_commit
|
|
@@ -56,6 +67,7 @@ module Dependabot
|
|
|
56
67
|
@github_redirection_service = github_redirection_service
|
|
57
68
|
@custom_headers = custom_headers
|
|
58
69
|
@require_up_to_date_base = require_up_to_date_base
|
|
70
|
+
@provider_metadata = provider_metadata
|
|
59
71
|
|
|
60
72
|
check_dependencies_have_previous_version
|
|
61
73
|
end
|
|
@@ -142,7 +154,8 @@ module Dependabot
|
|
|
142
154
|
pr_description: message_builder.pr_message,
|
|
143
155
|
pr_name: message_builder.pr_name,
|
|
144
156
|
author_details: author_details,
|
|
145
|
-
labeler: labeler
|
|
157
|
+
labeler: labeler,
|
|
158
|
+
work_item: provider_metadata&.fetch(:work_item, nil)
|
|
146
159
|
)
|
|
147
160
|
end
|
|
148
161
|
|
|
@@ -8,11 +8,11 @@ module Dependabot
|
|
|
8
8
|
class Azure
|
|
9
9
|
attr_reader :source, :branch_name, :base_commit, :credentials,
|
|
10
10
|
:files, :commit_message, :pr_description, :pr_name,
|
|
11
|
-
:author_details, :labeler
|
|
11
|
+
:author_details, :labeler, :work_item
|
|
12
12
|
|
|
13
13
|
def initialize(source:, branch_name:, base_commit:, credentials:,
|
|
14
14
|
files:, commit_message:, pr_description:, pr_name:,
|
|
15
|
-
author_details:, labeler:)
|
|
15
|
+
author_details:, labeler:, work_item: nil)
|
|
16
16
|
@source = source
|
|
17
17
|
@branch_name = branch_name
|
|
18
18
|
@base_commit = base_commit
|
|
@@ -23,6 +23,7 @@ module Dependabot
|
|
|
23
23
|
@pr_name = pr_name
|
|
24
24
|
@author_details = author_details
|
|
25
25
|
@labeler = labeler
|
|
26
|
+
@work_item = work_item
|
|
26
27
|
end
|
|
27
28
|
|
|
28
29
|
def create
|
|
@@ -46,9 +47,7 @@ module Dependabot
|
|
|
46
47
|
end
|
|
47
48
|
|
|
48
49
|
def branch_exists?
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
@branch_ref
|
|
50
|
+
azure_client_for_source.branch(branch_name)
|
|
52
51
|
rescue ::Azure::Error::NotFound
|
|
53
52
|
false
|
|
54
53
|
end
|
|
@@ -79,7 +78,8 @@ module Dependabot
|
|
|
79
78
|
branch_name,
|
|
80
79
|
source.branch || default_branch,
|
|
81
80
|
pr_description,
|
|
82
|
-
labeler.labels_for_pr
|
|
81
|
+
labeler.labels_for_pr,
|
|
82
|
+
work_item
|
|
83
83
|
)
|
|
84
84
|
end
|
|
85
85
|
|
|
@@ -7,6 +7,7 @@ require "dependabot/pull_request_creator"
|
|
|
7
7
|
require "dependabot/pull_request_creator/commit_signer"
|
|
8
8
|
module Dependabot
|
|
9
9
|
class PullRequestCreator
|
|
10
|
+
# rubocop:disable Metrics/ClassLength
|
|
10
11
|
class Github
|
|
11
12
|
attr_reader :source, :branch_name, :base_commit, :credentials,
|
|
12
13
|
:files, :pr_description, :pr_name, :commit_message,
|
|
@@ -41,7 +42,7 @@ module Dependabot
|
|
|
41
42
|
return if require_up_to_date_base? && !base_commit_is_up_to_date?
|
|
42
43
|
|
|
43
44
|
create_annotated_pull_request
|
|
44
|
-
rescue Octokit::Error => e
|
|
45
|
+
rescue AnnotationError, Octokit::Error => e
|
|
45
46
|
handle_error(e)
|
|
46
47
|
end
|
|
47
48
|
|
|
@@ -111,7 +112,11 @@ module Dependabot
|
|
|
111
112
|
pull_request = create_pull_request
|
|
112
113
|
return unless pull_request
|
|
113
114
|
|
|
114
|
-
|
|
115
|
+
begin
|
|
116
|
+
annotate_pull_request(pull_request)
|
|
117
|
+
rescue StandardError => e
|
|
118
|
+
raise AnnotationError.new(e, pull_request)
|
|
119
|
+
end
|
|
115
120
|
|
|
116
121
|
pull_request
|
|
117
122
|
end
|
|
@@ -417,24 +422,49 @@ module Dependabot
|
|
|
417
422
|
end
|
|
418
423
|
|
|
419
424
|
def handle_error(err)
|
|
420
|
-
case err
|
|
425
|
+
cause = case err
|
|
426
|
+
when AnnotationError
|
|
427
|
+
err.cause
|
|
428
|
+
else
|
|
429
|
+
err
|
|
430
|
+
end
|
|
431
|
+
|
|
432
|
+
case cause
|
|
421
433
|
when Octokit::Forbidden
|
|
422
|
-
|
|
423
|
-
|
|
434
|
+
if err.message.include?("disabled")
|
|
435
|
+
raise_custom_error err, RepoDisabled, err.message
|
|
436
|
+
elsif err.message.include?("archived")
|
|
437
|
+
raise_custom_error err, RepoArchived, err.message
|
|
438
|
+
end
|
|
424
439
|
|
|
425
440
|
raise err
|
|
426
441
|
when Octokit::NotFound
|
|
427
442
|
raise err if repo_exists?
|
|
428
443
|
|
|
429
|
-
|
|
444
|
+
raise_custom_error err, RepoNotFound, err.message
|
|
430
445
|
when Octokit::UnprocessableEntity
|
|
431
|
-
|
|
446
|
+
if err.message.include?("no history in common")
|
|
447
|
+
raise_custom_error err, NoHistoryInCommon, err.message
|
|
448
|
+
end
|
|
432
449
|
|
|
433
|
-
raise
|
|
450
|
+
raise err
|
|
434
451
|
else
|
|
435
452
|
raise err
|
|
436
453
|
end
|
|
437
454
|
end
|
|
455
|
+
|
|
456
|
+
def raise_custom_error(base_err, type, message)
|
|
457
|
+
case base_err
|
|
458
|
+
when AnnotationError
|
|
459
|
+
raise AnnotationError.new(
|
|
460
|
+
type.new(message),
|
|
461
|
+
base_err.pull_request
|
|
462
|
+
)
|
|
463
|
+
else
|
|
464
|
+
raise type, message
|
|
465
|
+
end
|
|
466
|
+
end
|
|
438
467
|
end
|
|
468
|
+
# rubocop:enable Metrics/ClassLength
|
|
439
469
|
end
|
|
440
470
|
end
|
|
@@ -10,6 +10,7 @@ require "dependabot/pull_request_creator"
|
|
|
10
10
|
module Dependabot
|
|
11
11
|
class PullRequestCreator
|
|
12
12
|
class MessageBuilder
|
|
13
|
+
require_relative "message_builder/metadata_presenter"
|
|
13
14
|
require_relative "message_builder/issue_linker"
|
|
14
15
|
require_relative "message_builder/link_and_mention_sanitizer"
|
|
15
16
|
require_relative "pr_name_prefixer"
|
|
@@ -312,240 +313,38 @@ module Dependabot
|
|
|
312
313
|
end.join
|
|
313
314
|
end
|
|
314
315
|
|
|
315
|
-
def metadata_cascades_for_dep(
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
msg += commits_cascade(dep)
|
|
324
|
-
msg += maintainer_changes_cascade(dep)
|
|
325
|
-
msg += break_tag unless msg == ""
|
|
326
|
-
"\n" + sanitize_links_and_mentions(msg, unsafe: true)
|
|
327
|
-
end
|
|
328
|
-
|
|
329
|
-
def vulnerabilities_cascade(dep)
|
|
330
|
-
fixed_vulns = vulnerabilities_fixed[dep.name]
|
|
331
|
-
return "" unless fixed_vulns&.any?
|
|
332
|
-
|
|
333
|
-
msg = ""
|
|
334
|
-
fixed_vulns.each { |v| msg += serialized_vulnerability_details(v) }
|
|
335
|
-
msg = sanitize_template_tags(msg)
|
|
336
|
-
msg = sanitize_links_and_mentions(msg)
|
|
337
|
-
|
|
338
|
-
build_details_tag(summary: "Vulnerabilities fixed", body: msg)
|
|
339
|
-
end
|
|
340
|
-
|
|
341
|
-
def release_cascade(dep)
|
|
342
|
-
return "" unless releases_text(dep) && releases_url(dep)
|
|
343
|
-
|
|
344
|
-
msg = "*Sourced from [#{dep.display_name}'s releases]"\
|
|
345
|
-
"(#{releases_url(dep)}).*\n\n"
|
|
346
|
-
msg +=
|
|
347
|
-
begin
|
|
348
|
-
release_note_lines = releases_text(dep).split("\n").first(50)
|
|
349
|
-
release_note_lines = release_note_lines.map { |line| "> #{line}\n" }
|
|
350
|
-
if release_note_lines.count == 50
|
|
351
|
-
release_note_lines << truncated_line
|
|
352
|
-
end
|
|
353
|
-
release_note_lines.join
|
|
354
|
-
end
|
|
355
|
-
msg = link_issues(text: msg, dependency: dep)
|
|
356
|
-
msg = fix_relative_links(
|
|
357
|
-
text: msg,
|
|
358
|
-
base_url: source_url(dep) + "/blob/HEAD/"
|
|
359
|
-
)
|
|
360
|
-
msg = sanitize_template_tags(msg)
|
|
361
|
-
msg = sanitize_links_and_mentions(msg)
|
|
362
|
-
|
|
363
|
-
build_details_tag(summary: "Release notes", body: msg)
|
|
364
|
-
end
|
|
365
|
-
|
|
366
|
-
def changelog_cascade(dep)
|
|
367
|
-
return "" unless changelog_url(dep) && changelog_text(dep)
|
|
368
|
-
|
|
369
|
-
msg = "*Sourced from "\
|
|
370
|
-
"[#{dep.display_name}'s changelog](#{changelog_url(dep)}).*\n\n"
|
|
371
|
-
msg +=
|
|
372
|
-
begin
|
|
373
|
-
changelog_lines = changelog_text(dep).split("\n").first(50)
|
|
374
|
-
changelog_lines = changelog_lines.map { |line| "> #{line}\n" }
|
|
375
|
-
changelog_lines << truncated_line if changelog_lines.count == 50
|
|
376
|
-
changelog_lines.join
|
|
377
|
-
end
|
|
378
|
-
msg = link_issues(text: msg, dependency: dep)
|
|
379
|
-
msg = fix_relative_links(text: msg, base_url: changelog_url(dep))
|
|
380
|
-
msg = sanitize_template_tags(msg)
|
|
381
|
-
msg = sanitize_links_and_mentions(msg)
|
|
382
|
-
|
|
383
|
-
build_details_tag(summary: "Changelog", body: msg)
|
|
384
|
-
end
|
|
385
|
-
|
|
386
|
-
def upgrade_guide_cascade(dep)
|
|
387
|
-
return "" unless upgrade_url(dep) && upgrade_text(dep)
|
|
388
|
-
|
|
389
|
-
msg = "*Sourced from "\
|
|
390
|
-
"[#{dep.display_name}'s upgrade guide]"\
|
|
391
|
-
"(#{upgrade_url(dep)}).*\n\n"
|
|
392
|
-
msg +=
|
|
393
|
-
begin
|
|
394
|
-
upgrade_lines = upgrade_text(dep).split("\n").first(50)
|
|
395
|
-
upgrade_lines = upgrade_lines.map { |line| "> #{line}\n" }
|
|
396
|
-
upgrade_lines << truncated_line if upgrade_lines.count == 50
|
|
397
|
-
upgrade_lines.join
|
|
398
|
-
end
|
|
399
|
-
msg = link_issues(text: msg, dependency: dep)
|
|
400
|
-
msg = fix_relative_links(text: msg, base_url: upgrade_url(dep))
|
|
401
|
-
msg = sanitize_template_tags(msg)
|
|
402
|
-
msg = sanitize_links_and_mentions(msg)
|
|
403
|
-
|
|
404
|
-
build_details_tag(summary: "Upgrade guide", body: msg)
|
|
405
|
-
end
|
|
406
|
-
|
|
407
|
-
def commits_cascade(dep)
|
|
408
|
-
return "" unless commits_url(dep) && commits(dep)
|
|
409
|
-
|
|
410
|
-
msg = ""
|
|
411
|
-
|
|
412
|
-
commits(dep).reverse.first(10).each do |commit|
|
|
413
|
-
title = commit[:message].strip.split("\n").first
|
|
414
|
-
title = title.slice(0..76) + "..." if title && title.length > 80
|
|
415
|
-
title = title&.gsub(/(?<=[^\w.-])([_*`~])/, '\\1')
|
|
416
|
-
sha = commit[:sha][0, 7]
|
|
417
|
-
msg += "- [`#{sha}`](#{commit[:html_url]}) #{title}\n"
|
|
418
|
-
end
|
|
419
|
-
|
|
420
|
-
msg = msg.gsub(/\<.*?\>/) { |tag| "\\#{tag}" }
|
|
421
|
-
|
|
422
|
-
msg +=
|
|
423
|
-
if commits(dep).count > 10
|
|
424
|
-
"- Additional commits viewable in "\
|
|
425
|
-
"[compare view](#{commits_url(dep)})\n"
|
|
426
|
-
else
|
|
427
|
-
"- See full diff in [compare view](#{commits_url(dep)})\n"
|
|
428
|
-
end
|
|
429
|
-
msg = link_issues(text: msg, dependency: dep)
|
|
430
|
-
msg = sanitize_links_and_mentions(msg)
|
|
431
|
-
|
|
432
|
-
build_details_tag(summary: "Commits", body: msg)
|
|
433
|
-
end
|
|
434
|
-
|
|
435
|
-
def maintainer_changes_cascade(dep)
|
|
436
|
-
return "" unless maintainer_changes(dep)
|
|
437
|
-
|
|
438
|
-
build_details_tag(
|
|
439
|
-
summary: "Maintainer changes",
|
|
440
|
-
body: sanitize_links_and_mentions(maintainer_changes(dep)) + "\n"
|
|
441
|
-
)
|
|
442
|
-
end
|
|
443
|
-
|
|
444
|
-
def build_details_tag(summary:, body:)
|
|
445
|
-
# Azure DevOps does not support <details> tag (https://developercommunity.visualstudio.com/content/problem/608769/add-support-for-in-markdown.html)
|
|
446
|
-
# CodeCommit does not support the <details> tag (no url available)
|
|
447
|
-
if source_provider_supports_html?
|
|
448
|
-
msg = "<details>\n<summary>#{summary}</summary>\n\n"
|
|
449
|
-
msg += body
|
|
450
|
-
msg + "</details>\n"
|
|
451
|
-
else
|
|
452
|
-
"\n\##{summary}\n\n#{body}"
|
|
453
|
-
end
|
|
454
|
-
end
|
|
455
|
-
|
|
456
|
-
def source_provider_supports_html?
|
|
457
|
-
!%w(azure codecommit).include?(source.provider)
|
|
458
|
-
end
|
|
459
|
-
|
|
460
|
-
def serialized_vulnerability_details(details)
|
|
461
|
-
msg = vulnerability_source_line(details)
|
|
462
|
-
|
|
463
|
-
if details["title"]
|
|
464
|
-
msg += "> **#{details['title'].lines.map(&:strip).join(' ')}**\n"
|
|
465
|
-
end
|
|
466
|
-
|
|
467
|
-
if (description = details["description"])
|
|
468
|
-
description.strip.lines.first(20).each { |line| msg += "> #{line}" }
|
|
469
|
-
msg += truncated_line if description.strip.lines.count > 20
|
|
470
|
-
end
|
|
471
|
-
|
|
472
|
-
msg += "\n" unless msg.end_with?("\n")
|
|
473
|
-
msg += "> \n"
|
|
474
|
-
msg += vulnerability_version_range_lines(details)
|
|
475
|
-
msg + "\n"
|
|
476
|
-
end
|
|
477
|
-
|
|
478
|
-
def vulnerability_source_line(details)
|
|
479
|
-
if details["source_url"] && details["source_name"]
|
|
480
|
-
"*Sourced from [#{details['source_name']}]"\
|
|
481
|
-
"(#{details['source_url']}).*\n\n"
|
|
482
|
-
elsif details["source_name"]
|
|
483
|
-
"*Sourced from #{details['source_name']}.*\n\n"
|
|
484
|
-
else
|
|
485
|
-
""
|
|
486
|
-
end
|
|
487
|
-
end
|
|
488
|
-
|
|
489
|
-
def vulnerability_version_range_lines(details)
|
|
490
|
-
msg = ""
|
|
491
|
-
%w(patched_versions unaffected_versions affected_versions).each do |tp|
|
|
492
|
-
type = tp.split("_").first.capitalize
|
|
493
|
-
next unless details[tp]
|
|
494
|
-
|
|
495
|
-
versions_string = details[tp].any? ? details[tp].join("; ") : "none"
|
|
496
|
-
versions_string = versions_string.gsub(/(?<!\\)~/, '\~')
|
|
497
|
-
msg += "> #{type} versions: #{versions_string}\n"
|
|
498
|
-
end
|
|
499
|
-
msg
|
|
500
|
-
end
|
|
501
|
-
|
|
502
|
-
def truncated_line
|
|
503
|
-
# Tables can spill out of truncated details, so we close them
|
|
504
|
-
"></tr></table> ... (truncated)\n"
|
|
505
|
-
end
|
|
506
|
-
|
|
507
|
-
def releases_url(dependency)
|
|
508
|
-
metadata_finder(dependency).releases_url
|
|
509
|
-
end
|
|
510
|
-
|
|
511
|
-
def releases_text(dependency)
|
|
512
|
-
metadata_finder(dependency).releases_text
|
|
316
|
+
def metadata_cascades_for_dep(dependency)
|
|
317
|
+
MetadataPresenter.new(
|
|
318
|
+
dependency: dependency,
|
|
319
|
+
source: source,
|
|
320
|
+
metadata_finder: metadata_finder(dependency),
|
|
321
|
+
vulnerabilities_fixed: vulnerabilities_fixed[dependency.name],
|
|
322
|
+
github_redirection_service: github_redirection_service
|
|
323
|
+
).to_s
|
|
513
324
|
end
|
|
514
325
|
|
|
515
326
|
def changelog_url(dependency)
|
|
516
327
|
metadata_finder(dependency).changelog_url
|
|
517
328
|
end
|
|
518
329
|
|
|
519
|
-
def changelog_text(dependency)
|
|
520
|
-
metadata_finder(dependency).changelog_text
|
|
521
|
-
end
|
|
522
|
-
|
|
523
|
-
def upgrade_url(dependency)
|
|
524
|
-
metadata_finder(dependency).upgrade_guide_url
|
|
525
|
-
end
|
|
526
|
-
|
|
527
|
-
def upgrade_text(dependency)
|
|
528
|
-
metadata_finder(dependency).upgrade_guide_text
|
|
529
|
-
end
|
|
530
|
-
|
|
531
330
|
def commits_url(dependency)
|
|
532
331
|
metadata_finder(dependency).commits_url
|
|
533
332
|
end
|
|
534
333
|
|
|
535
|
-
def
|
|
536
|
-
metadata_finder(dependency).
|
|
334
|
+
def homepage_url(dependency)
|
|
335
|
+
metadata_finder(dependency).homepage_url
|
|
537
336
|
end
|
|
538
337
|
|
|
539
|
-
def
|
|
540
|
-
metadata_finder(dependency).
|
|
338
|
+
def releases_url(dependency)
|
|
339
|
+
metadata_finder(dependency).releases_url
|
|
541
340
|
end
|
|
542
341
|
|
|
543
342
|
def source_url(dependency)
|
|
544
343
|
metadata_finder(dependency).source_url
|
|
545
344
|
end
|
|
546
345
|
|
|
547
|
-
def
|
|
548
|
-
metadata_finder(dependency).
|
|
346
|
+
def upgrade_url(dependency)
|
|
347
|
+
metadata_finder(dependency).upgrade_guide_url
|
|
549
348
|
end
|
|
550
349
|
|
|
551
350
|
def metadata_finder(dependency)
|
|
@@ -656,48 +455,6 @@ module Dependabot
|
|
|
656
455
|
raise "No new requirement!"
|
|
657
456
|
end
|
|
658
457
|
|
|
659
|
-
def link_issues(text:, dependency:)
|
|
660
|
-
IssueLinker.
|
|
661
|
-
new(source_url: source_url(dependency)).
|
|
662
|
-
link_issues(text: text)
|
|
663
|
-
end
|
|
664
|
-
|
|
665
|
-
def fix_relative_links(text:, base_url:)
|
|
666
|
-
text.gsub(/\[.*?\]\([^)]+\)/) do |link|
|
|
667
|
-
next link if link.include?("://")
|
|
668
|
-
|
|
669
|
-
relative_path = link.match(/\((.*?)\)/).captures.last
|
|
670
|
-
base = base_url.split("://").last.gsub(%r{[^/]*$}, "")
|
|
671
|
-
path = File.join(base, relative_path)
|
|
672
|
-
absolute_path =
|
|
673
|
-
base_url.sub(
|
|
674
|
-
%r{(?<=://).*$},
|
|
675
|
-
Pathname.new(path).cleanpath.to_s
|
|
676
|
-
)
|
|
677
|
-
link.gsub(relative_path, absolute_path)
|
|
678
|
-
end
|
|
679
|
-
end
|
|
680
|
-
|
|
681
|
-
def sanitize_links_and_mentions(text, unsafe: false)
|
|
682
|
-
return text unless source.provider == "github"
|
|
683
|
-
|
|
684
|
-
LinkAndMentionSanitizer.
|
|
685
|
-
new(github_redirection_service: github_redirection_service).
|
|
686
|
-
sanitize_links_and_mentions(text: text, unsafe: unsafe)
|
|
687
|
-
end
|
|
688
|
-
|
|
689
|
-
def sanitize_template_tags(text)
|
|
690
|
-
text.gsub(/\<.*?\>/) do |tag|
|
|
691
|
-
tag_contents = tag.match(/\<(.*?)\>/).captures.first.strip
|
|
692
|
-
|
|
693
|
-
# Unclosed calls to template overflow out of the blockquote block,
|
|
694
|
-
# wrecking the rest of our PRs. Other tags don't share this problem.
|
|
695
|
-
next "\\#{tag}" if tag_contents.start_with?("template")
|
|
696
|
-
|
|
697
|
-
tag
|
|
698
|
-
end
|
|
699
|
-
end
|
|
700
|
-
|
|
701
458
|
def ref_changed?(dependency)
|
|
702
459
|
previous_ref(dependency) != new_ref(dependency)
|
|
703
460
|
end
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "dependabot/pull_request_creator/message_builder"
|
|
4
|
+
|
|
5
|
+
module Dependabot
|
|
6
|
+
class PullRequestCreator
|
|
7
|
+
class MessageBuilder
|
|
8
|
+
class MetadataPresenter
|
|
9
|
+
extend Forwardable
|
|
10
|
+
|
|
11
|
+
attr_reader :dependency, :source, :metadata_finder,
|
|
12
|
+
:vulnerabilities_fixed, :github_redirection_service
|
|
13
|
+
|
|
14
|
+
def_delegators :metadata_finder,
|
|
15
|
+
:changelog_url,
|
|
16
|
+
:changelog_text,
|
|
17
|
+
:commits_url,
|
|
18
|
+
:commits,
|
|
19
|
+
:maintainer_changes,
|
|
20
|
+
:releases_url,
|
|
21
|
+
:releases_text,
|
|
22
|
+
:source_url,
|
|
23
|
+
:upgrade_guide_url,
|
|
24
|
+
:upgrade_guide_text
|
|
25
|
+
|
|
26
|
+
def initialize(dependency:, source:, metadata_finder:,
|
|
27
|
+
vulnerabilities_fixed:, github_redirection_service:)
|
|
28
|
+
@dependency = dependency
|
|
29
|
+
@source = source
|
|
30
|
+
@metadata_finder = metadata_finder
|
|
31
|
+
@vulnerabilities_fixed = vulnerabilities_fixed
|
|
32
|
+
@github_redirection_service = github_redirection_service
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def to_s
|
|
36
|
+
msg = ""
|
|
37
|
+
msg += vulnerabilities_cascade
|
|
38
|
+
msg += release_cascade
|
|
39
|
+
msg += changelog_cascade
|
|
40
|
+
msg += upgrade_guide_cascade
|
|
41
|
+
msg += commits_cascade
|
|
42
|
+
msg += maintainer_changes_cascade
|
|
43
|
+
msg += break_tag unless msg == ""
|
|
44
|
+
"\n" + sanitize_links_and_mentions(msg, unsafe: true)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
private
|
|
48
|
+
|
|
49
|
+
def vulnerabilities_cascade
|
|
50
|
+
return "" unless vulnerabilities_fixed&.any?
|
|
51
|
+
|
|
52
|
+
msg = ""
|
|
53
|
+
vulnerabilities_fixed.each do |v|
|
|
54
|
+
msg += serialized_vulnerability_details(v)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
msg = sanitize_template_tags(msg)
|
|
58
|
+
msg = sanitize_links_and_mentions(msg)
|
|
59
|
+
|
|
60
|
+
build_details_tag(summary: "Vulnerabilities fixed", body: msg)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def release_cascade
|
|
64
|
+
return "" unless releases_text && releases_url
|
|
65
|
+
|
|
66
|
+
msg = "*Sourced from [#{dependency.display_name}'s releases]"\
|
|
67
|
+
"(#{releases_url}).*\n\n"
|
|
68
|
+
msg += quote_and_truncate(releases_text)
|
|
69
|
+
msg = link_issues(text: msg)
|
|
70
|
+
msg = fix_relative_links(
|
|
71
|
+
text: msg,
|
|
72
|
+
base_url: source_url + "/blob/HEAD/"
|
|
73
|
+
)
|
|
74
|
+
msg = sanitize_template_tags(msg)
|
|
75
|
+
msg = sanitize_links_and_mentions(msg)
|
|
76
|
+
|
|
77
|
+
build_details_tag(summary: "Release notes", body: msg)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def changelog_cascade
|
|
81
|
+
return "" unless changelog_url && changelog_text
|
|
82
|
+
|
|
83
|
+
msg = "*Sourced from "\
|
|
84
|
+
"[#{dependency.display_name}'s changelog]"\
|
|
85
|
+
"(#{changelog_url}).*\n\n"
|
|
86
|
+
msg += quote_and_truncate(changelog_text)
|
|
87
|
+
msg = link_issues(text: msg)
|
|
88
|
+
msg = fix_relative_links(text: msg, base_url: changelog_url)
|
|
89
|
+
msg = sanitize_template_tags(msg)
|
|
90
|
+
msg = sanitize_links_and_mentions(msg)
|
|
91
|
+
|
|
92
|
+
build_details_tag(summary: "Changelog", body: msg)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def upgrade_guide_cascade
|
|
96
|
+
return "" unless upgrade_guide_url && upgrade_guide_text
|
|
97
|
+
|
|
98
|
+
msg = "*Sourced from "\
|
|
99
|
+
"[#{dependency.display_name}'s upgrade guide]"\
|
|
100
|
+
"(#{upgrade_guide_url}).*\n\n"
|
|
101
|
+
msg += quote_and_truncate(upgrade_guide_text)
|
|
102
|
+
msg = link_issues(text: msg)
|
|
103
|
+
msg = fix_relative_links(text: msg, base_url: upgrade_guide_url)
|
|
104
|
+
msg = sanitize_template_tags(msg)
|
|
105
|
+
msg = sanitize_links_and_mentions(msg)
|
|
106
|
+
|
|
107
|
+
build_details_tag(summary: "Upgrade guide", body: msg)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def commits_cascade
|
|
111
|
+
return "" unless commits_url && commits
|
|
112
|
+
|
|
113
|
+
msg = ""
|
|
114
|
+
|
|
115
|
+
commits.reverse.first(10).each do |commit|
|
|
116
|
+
title = commit[:message].strip.split("\n").first
|
|
117
|
+
title = title.slice(0..76) + "..." if title && title.length > 80
|
|
118
|
+
title = title&.gsub(/(?<=[^\w.-])([_*`~])/, '\\1')
|
|
119
|
+
sha = commit[:sha][0, 7]
|
|
120
|
+
msg += "- [`#{sha}`](#{commit[:html_url]}) #{title}\n"
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
msg = msg.gsub(/\<.*?\>/) { |tag| "\\#{tag}" }
|
|
124
|
+
|
|
125
|
+
msg +=
|
|
126
|
+
if commits.count > 10
|
|
127
|
+
"- Additional commits viewable in "\
|
|
128
|
+
"[compare view](#{commits_url})\n"
|
|
129
|
+
else
|
|
130
|
+
"- See full diff in [compare view](#{commits_url})\n"
|
|
131
|
+
end
|
|
132
|
+
msg = link_issues(text: msg)
|
|
133
|
+
msg = sanitize_links_and_mentions(msg)
|
|
134
|
+
|
|
135
|
+
build_details_tag(summary: "Commits", body: msg)
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def maintainer_changes_cascade
|
|
139
|
+
return "" unless maintainer_changes
|
|
140
|
+
|
|
141
|
+
build_details_tag(
|
|
142
|
+
summary: "Maintainer changes",
|
|
143
|
+
body: sanitize_links_and_mentions(maintainer_changes) + "\n"
|
|
144
|
+
)
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def build_details_tag(summary:, body:)
|
|
148
|
+
# Azure DevOps does not support <details> tag (https://developercommunity.visualstudio.com/content/problem/608769/add-support-for-in-markdown.html)
|
|
149
|
+
# CodeCommit does not support the <details> tag (no url available)
|
|
150
|
+
if source_provider_supports_html?
|
|
151
|
+
msg = "<details>\n<summary>#{summary}</summary>\n\n"
|
|
152
|
+
msg += body
|
|
153
|
+
msg + "</details>\n"
|
|
154
|
+
else
|
|
155
|
+
"\n\##{summary}\n\n#{body}"
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def serialized_vulnerability_details(details)
|
|
160
|
+
msg = vulnerability_source_line(details)
|
|
161
|
+
|
|
162
|
+
if details["title"]
|
|
163
|
+
msg += "> **#{details['title'].lines.map(&:strip).join(' ')}**\n"
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
if (description = details["description"])
|
|
167
|
+
description.strip.lines.first(20).each { |line| msg += "> #{line}" }
|
|
168
|
+
msg += truncated_line if description.strip.lines.count > 20
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
msg += "\n" unless msg.end_with?("\n")
|
|
172
|
+
msg += "> \n"
|
|
173
|
+
msg += vulnerability_version_range_lines(details)
|
|
174
|
+
msg + "\n"
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def vulnerability_source_line(details)
|
|
178
|
+
if details["source_url"] && details["source_name"]
|
|
179
|
+
"*Sourced from [#{details['source_name']}]"\
|
|
180
|
+
"(#{details['source_url']}).*\n\n"
|
|
181
|
+
elsif details["source_name"]
|
|
182
|
+
"*Sourced from #{details['source_name']}.*\n\n"
|
|
183
|
+
else
|
|
184
|
+
""
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
def vulnerability_version_range_lines(details)
|
|
189
|
+
msg = ""
|
|
190
|
+
%w(
|
|
191
|
+
patched_versions
|
|
192
|
+
unaffected_versions
|
|
193
|
+
affected_versions
|
|
194
|
+
).each do |tp|
|
|
195
|
+
type = tp.split("_").first.capitalize
|
|
196
|
+
next unless details[tp]
|
|
197
|
+
|
|
198
|
+
versions_string = details[tp].any? ? details[tp].join("; ") : "none"
|
|
199
|
+
versions_string = versions_string.gsub(/(?<!\\)~/, '\~')
|
|
200
|
+
msg += "> #{type} versions: #{versions_string}\n"
|
|
201
|
+
end
|
|
202
|
+
msg
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
def link_issues(text:)
|
|
206
|
+
IssueLinker.
|
|
207
|
+
new(source_url: source_url).
|
|
208
|
+
link_issues(text: text)
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
def fix_relative_links(text:, base_url:)
|
|
212
|
+
text.gsub(/\[.*?\]\([^)]+\)/) do |link|
|
|
213
|
+
next link if link.include?("://")
|
|
214
|
+
|
|
215
|
+
relative_path = link.match(/\((.*?)\)/).captures.last
|
|
216
|
+
base = base_url.split("://").last.gsub(%r{[^/]*$}, "")
|
|
217
|
+
path = File.join(base, relative_path)
|
|
218
|
+
absolute_path =
|
|
219
|
+
base_url.sub(
|
|
220
|
+
%r{(?<=://).*$},
|
|
221
|
+
Pathname.new(path).cleanpath.to_s
|
|
222
|
+
)
|
|
223
|
+
link.gsub(relative_path, absolute_path)
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
def quote_and_truncate(text, limit: 50)
|
|
228
|
+
lines = text.split("\n")
|
|
229
|
+
lines.first(limit).tap do |limited_lines|
|
|
230
|
+
limited_lines.map! { |line| "> #{line}\n" }
|
|
231
|
+
limited_lines << truncated_line if lines.count > limit
|
|
232
|
+
end.join
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
def truncated_line
|
|
236
|
+
# Tables can spill out of truncated details, so we close them
|
|
237
|
+
"></tr></table> \n ... (truncated)\n"
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
def break_tag
|
|
241
|
+
source_provider_supports_html? ? "\n<br />" : "\n\n"
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
def source_provider_supports_html?
|
|
245
|
+
!%w(azure codecommit).include?(source.provider)
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
def sanitize_links_and_mentions(text, unsafe: false)
|
|
249
|
+
return text unless source.provider == "github"
|
|
250
|
+
|
|
251
|
+
LinkAndMentionSanitizer.
|
|
252
|
+
new(github_redirection_service: github_redirection_service).
|
|
253
|
+
sanitize_links_and_mentions(text: text, unsafe: unsafe)
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
def sanitize_template_tags(text)
|
|
257
|
+
text.gsub(/\<.*?\>/) do |tag|
|
|
258
|
+
tag_contents = tag.match(/\<(.*?)\>/).captures.first.strip
|
|
259
|
+
|
|
260
|
+
# Unclosed calls to template overflow out of the blockquote block,
|
|
261
|
+
# wrecking the rest of our PRs. Other tags don't share this problem.
|
|
262
|
+
next "\\#{tag}" if tag_contents.start_with?("template")
|
|
263
|
+
|
|
264
|
+
tag
|
|
265
|
+
end
|
|
266
|
+
end
|
|
267
|
+
end
|
|
268
|
+
end
|
|
269
|
+
end
|
|
270
|
+
end
|
|
@@ -13,6 +13,10 @@ module Dependabot
|
|
|
13
13
|
BUMP_TMP_FILE_PREFIX = "dependabot_"
|
|
14
14
|
BUMP_TMP_DIR_PATH = "tmp"
|
|
15
15
|
GIT_CONFIG_GLOBAL_PATH = File.expand_path("~/.gitconfig")
|
|
16
|
+
USER_AGENT = "dependabot-core/#{Dependabot::VERSION} "\
|
|
17
|
+
"#{Excon::USER_AGENT} ruby/#{RUBY_VERSION} "\
|
|
18
|
+
"(#{RUBY_PLATFORM}) "\
|
|
19
|
+
"(+https://github.com/dependabot/dependabot-core)"
|
|
16
20
|
|
|
17
21
|
class ChildProcessFailed < StandardError
|
|
18
22
|
attr_reader :error_class, :error_message, :error_backtrace
|
|
@@ -138,14 +142,23 @@ module Dependabot
|
|
|
138
142
|
[Excon::Middleware::RedirectFollower]
|
|
139
143
|
end
|
|
140
144
|
|
|
141
|
-
def self.
|
|
145
|
+
def self.excon_headers(headers = nil)
|
|
146
|
+
headers ||= {}
|
|
147
|
+
{
|
|
148
|
+
"User-Agent" => USER_AGENT
|
|
149
|
+
}.merge(headers)
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def self.excon_defaults(options = nil)
|
|
153
|
+
options ||= {}
|
|
142
154
|
{
|
|
143
155
|
connect_timeout: 5,
|
|
144
156
|
write_timeout: 5,
|
|
145
157
|
read_timeout: 20,
|
|
146
158
|
omit_default_port: true,
|
|
147
|
-
middlewares: excon_middleware
|
|
148
|
-
|
|
159
|
+
middlewares: excon_middleware,
|
|
160
|
+
headers: excon_headers(options[:headers])
|
|
161
|
+
}.merge(options)
|
|
149
162
|
end
|
|
150
163
|
|
|
151
164
|
def self.with_git_configured(credentials:)
|
data/lib/dependabot/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: dependabot-common
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.120.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Dependabot
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2020-09-
|
|
11
|
+
date: 2020-09-25 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: aws-sdk-codecommit
|
|
@@ -292,14 +292,14 @@ dependencies:
|
|
|
292
292
|
requirements:
|
|
293
293
|
- - "~>"
|
|
294
294
|
- !ruby/object:Gem::Version
|
|
295
|
-
version: 0.
|
|
295
|
+
version: 0.91.0
|
|
296
296
|
type: :development
|
|
297
297
|
prerelease: false
|
|
298
298
|
version_requirements: !ruby/object:Gem::Requirement
|
|
299
299
|
requirements:
|
|
300
300
|
- - "~>"
|
|
301
301
|
- !ruby/object:Gem::Version
|
|
302
|
-
version: 0.
|
|
302
|
+
version: 0.91.0
|
|
303
303
|
- !ruby/object:Gem::Dependency
|
|
304
304
|
name: vcr
|
|
305
305
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -376,6 +376,7 @@ files:
|
|
|
376
376
|
- lib/dependabot/pull_request_creator/message_builder.rb
|
|
377
377
|
- lib/dependabot/pull_request_creator/message_builder/issue_linker.rb
|
|
378
378
|
- lib/dependabot/pull_request_creator/message_builder/link_and_mention_sanitizer.rb
|
|
379
|
+
- lib/dependabot/pull_request_creator/message_builder/metadata_presenter.rb
|
|
379
380
|
- lib/dependabot/pull_request_creator/pr_name_prefixer.rb
|
|
380
381
|
- lib/dependabot/pull_request_updater.rb
|
|
381
382
|
- lib/dependabot/pull_request_updater/github.rb
|