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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c084a2dd6045074bdde8be081749cf0bb32dc4fcaa99b07bf6eea049cd798dd6
4
- data.tar.gz: 3201d221483932d06cadd03304dcb8b65561bc1778d3aefca45416fc260e94cf
3
+ metadata.gz: 83263fa7e5a3d1dbd38624d9476cab98b226ef442af42cd6e9324dcb61226476
4
+ data.tar.gz: a47175b2fb55cb804e95a1f438f21de893f73b3921b319bcb296e3ff7f0397da
5
5
  SHA512:
6
- metadata.gz: 68a073b8397b7128e2f63076267e1f3efb4b7c3501674e7e657ac4ee3a6cd8e5d8f55e7cb368758045dddbb179289ec7a6a45f1eeca2d8376c9b9758d8ca8577
7
- data.tar.gz: bc1cddb30b8d543019e3434963b224f3feb58cf50abe19b9a360606db3ba4340fcb8d007716302b29a9e25a79e305590b060285e19aa139a6c186203b81ca534
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
 
@@ -183,7 +183,7 @@ module Dependabot
183
183
 
184
184
  def excon_defaults
185
185
  # Some git hosts are slow when returning a large number of tags
186
- SharedHelpers.excon_defaults.merge(read_timeout: 20)
186
+ SharedHelpers.excon_defaults(read_timeout: 20)
187
187
  end
188
188
  end
189
189
  end
@@ -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
- @branch_ref ||= azure_client_for_source.branch(branch_name)
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
- annotate_pull_request(pull_request)
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
- raise RepoDisabled, err.message if err.message.include?("disabled")
423
- raise RepoArchived, err.message if err.message.include?("archived")
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
- raise RepoNotFound, err.message
444
+ raise_custom_error err, RepoNotFound, err.message
430
445
  when Octokit::UnprocessableEntity
431
- raise err unless err.message.include?("no history in common")
446
+ if err.message.include?("no history in common")
447
+ raise_custom_error err, NoHistoryInCommon, err.message
448
+ end
432
449
 
433
- raise NoHistoryInCommon, err.message
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(dep)
316
- break_tag = source_provider_supports_html? ? "\n<br />" : "\n\n"
317
-
318
- msg = ""
319
- msg += vulnerabilities_cascade(dep)
320
- msg += release_cascade(dep)
321
- msg += changelog_cascade(dep)
322
- msg += upgrade_guide_cascade(dep)
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 commits(dependency)
536
- metadata_finder(dependency).commits
334
+ def homepage_url(dependency)
335
+ metadata_finder(dependency).homepage_url
537
336
  end
538
337
 
539
- def maintainer_changes(dependency)
540
- metadata_finder(dependency).maintainer_changes
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 homepage_url(dependency)
548
- metadata_finder(dependency).homepage_url
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.excon_defaults
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:)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Dependabot
4
- VERSION = "0.119.4"
4
+ VERSION = "0.120.2"
5
5
  end
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.119.4
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-15 00:00:00.000000000 Z
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.90.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.90.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