dependabot-common 0.119.2 → 0.120.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of dependabot-common might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c81b0ca1f68eb6edaf9aba683e0537cf2acc69caccaf95bb777c531c25b936a1
4
- data.tar.gz: 70e8b39a6f6f711b68e5033778c1063b3a91fe19f6f2b0377447ae2705e0603d
3
+ metadata.gz: 8a591ed018e9734955f64c0f830dd403c103706b4ffe9f9db18c5eb9c701061d
4
+ data.tar.gz: 86c1b8b7d36005ec164c35016144cf60a00027c1e95e5943fb0199ae2b4772ba
5
5
  SHA512:
6
- metadata.gz: afa8c8f3b5462009ea4b88df0d69bd87ac4c8cddb64419cd7817a1a01e302efac77774f1b093e7b4e92d143860f08f924b81504fb7f06b4149d99a258c3465fd
7
- data.tar.gz: e8177d4e247a073d3bd30393c20b724bb342d6863fad8fcc26792556b1092096c533ccdd373dd9b1423308d7925d23741ea0e89f5841c604cd99bdc6f0feb923
6
+ metadata.gz: '02211953c4f4ca35f549629a4196a18ef875cb4aa9a67e06af8f56c564cd9dcd5e2322c5c3e8fa2a57e7517c90e6a3806c93c4ecea8e2ae6d2befc04167da875'
7
+ data.tar.gz: 31b207db8ee1fe5a2b36f598b3082a044b7e01de990f06c37d3864fa591982804e1b0921243613b0754dabcf5b01cff914dac4f56beac5418e1d636f81ca6064
@@ -28,6 +28,7 @@ module Dependabot
28
28
  def initialize(source, credentials)
29
29
  @source = source
30
30
  @credentials = credentials
31
+ @auth_header = auth_header_for(credentials&.fetch("token", nil))
31
32
  end
32
33
 
33
34
  def fetch_commit(_repo, branch)
@@ -152,8 +153,9 @@ module Dependabot
152
153
  "/pushes?api-version=5.0", content.to_json)
153
154
  end
154
155
 
156
+ # rubocop:disable Metrics/ParameterLists
155
157
  def create_pull_request(pr_name, source_branch, target_branch,
156
- pr_description, labels)
158
+ pr_description, labels, work_item = nil)
157
159
  # Azure DevOps only support descriptions up to 4000 characters
158
160
  # https://developercommunity.visualstudio.com/content/problem/608770/remove-4000-character-limit-on-pull-request-descri.html
159
161
  azure_max_length = 3999
@@ -162,13 +164,15 @@ module Dependabot
162
164
  truncate_length = azure_max_length - truncated_msg.length
163
165
  pr_description = pr_description[0..truncate_length] + truncated_msg
164
166
  end
167
+ # rubocop:enable Metrics/ParameterLists
165
168
 
166
169
  content = {
167
170
  sourceRefName: "refs/heads/" + source_branch,
168
171
  targetRefName: "refs/heads/" + target_branch,
169
172
  title: pr_name,
170
173
  description: pr_description,
171
- labels: labels.map { |label| { name: label } }
174
+ labels: labels.map { |label| { name: label } },
175
+ workItemRefs: [{ id: work_item }]
172
176
  }
173
177
 
174
178
  post(source.api_endpoint +
@@ -180,8 +184,9 @@ module Dependabot
180
184
  def get(url)
181
185
  response = Excon.get(
182
186
  url,
183
- user: credentials&.fetch("username"),
184
- password: credentials&.fetch("password"),
187
+ headers: auth_header,
188
+ user: credentials&.fetch("username", nil),
189
+ password: credentials&.fetch("password", nil),
185
190
  idempotent: true,
186
191
  **SharedHelpers.excon_defaults
187
192
  )
@@ -193,12 +198,14 @@ module Dependabot
193
198
  def post(url, json)
194
199
  response = Excon.post(
195
200
  url,
196
- headers: {
197
- "Content-Type" => "application/json"
198
- },
201
+ headers: auth_header.merge(
202
+ {
203
+ "Content-Type" => "application/json"
204
+ }
205
+ ),
199
206
  body: json,
200
- user: credentials&.fetch("username"),
201
- password: credentials&.fetch("password"),
207
+ user: credentials&.fetch("username", nil),
208
+ password: credentials&.fetch("password", nil),
202
209
  idempotent: true,
203
210
  **SharedHelpers.excon_defaults
204
211
  )
@@ -209,6 +216,21 @@ module Dependabot
209
216
 
210
217
  private
211
218
 
219
+ def auth_header_for(token)
220
+ return {} unless token
221
+
222
+ if token.include?(":")
223
+ encoded_token = Base64.encode64(token).delete("\n")
224
+ { "Authorization" => "Basic #{encoded_token}" }
225
+ elsif Base64.decode64(token).ascii_only? &&
226
+ Base64.decode64(token).include?(":")
227
+ { "Authorization" => "Basic #{token.delete("\n")}" }
228
+ else
229
+ { "Authorization" => "Bearer #{token}" }
230
+ end
231
+ end
232
+
233
+ attr_reader :auth_header
212
234
  attr_reader :credentials
213
235
  attr_reader :source
214
236
  end
@@ -60,7 +60,6 @@ module Dependabot
60
60
  dependencies.find { |d| d.name&.downcase == name&.downcase }
61
61
  end
62
62
 
63
- # rubocop:disable Metrics/PerceivedComplexity
64
63
  def combined_dependency(old_dep, new_dep)
65
64
  package_manager = old_dep.package_manager
66
65
  v_cls = Utils.version_class_for_package_manager(package_manager)
@@ -89,8 +88,6 @@ module Dependabot
89
88
  subdependency_metadata: subdependency_metadata
90
89
  )
91
90
  end
92
-
93
- # rubocop:enable Metrics/PerceivedComplexity
94
91
  end
95
92
  end
96
93
  end
@@ -86,6 +86,7 @@ module Dependabot
86
86
  raise Dependabot::GitDependencyReferenceNotFound, dependency.name
87
87
  end
88
88
 
89
+ # rubocop:disable Metrics/PerceivedComplexity
89
90
  def local_tag_for_latest_version
90
91
  tags =
91
92
  local_tags.
@@ -114,6 +115,7 @@ module Dependabot
114
115
  tag_sha: tag.tag_sha
115
116
  }
116
117
  end
118
+ # rubocop:enable Metrics/PerceivedComplexity
117
119
 
118
120
  def git_repo_reachable?
119
121
  local_upload_pack
@@ -143,6 +143,7 @@ module Dependabot
143
143
  select_best_changelog(files)
144
144
  end
145
145
 
146
+ # rubocop:disable Metrics/PerceivedComplexity
146
147
  def select_best_changelog(files)
147
148
  CHANGELOG_NAMES.each do |name|
148
149
  candidates = files.select { |f| f.name =~ /#{name}/i }
@@ -163,6 +164,7 @@ module Dependabot
163
164
 
164
165
  nil
165
166
  end
167
+ # rubocop:enable Metrics/PerceivedComplexity
166
168
 
167
169
  def tag_for_new_version
168
170
  @tag_for_new_version ||=
@@ -21,7 +21,6 @@ module Dependabot
21
21
  !old_version_changelog_line.nil?
22
22
  end
23
23
 
24
- # rubocop:disable Metrics/PerceivedComplexity
25
24
  def pruned_text
26
25
  changelog_lines = changelog_text.split("\n")
27
26
 
@@ -51,7 +50,6 @@ module Dependabot
51
50
 
52
51
  changelog_lines.slice(slice_range).join("\n").sub(/\n*\z/, "")
53
52
  end
54
- # rubocop:enable Metrics/PerceivedComplexity
55
53
 
56
54
  private
57
55
 
@@ -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
 
@@ -116,7 +116,6 @@ module Dependabot
116
116
  gsub(",", "-and-")
117
117
  end
118
118
 
119
- # rubocop:disable Metrics/PerceivedComplexity
120
119
  def new_version(dependency)
121
120
  # Version looks like a git SHA and we could be updating to a specific
122
121
  # ref in which case we return that otherwise we return a shorthand sha
@@ -135,7 +134,6 @@ module Dependabot
135
134
  dependency.version
136
135
  end
137
136
  end
138
- # rubocop:enable Metrics/PerceivedComplexity
139
137
 
140
138
  def previous_ref(dependency)
141
139
  previous_refs = dependency.previous_requirements.map do |r|
@@ -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
 
@@ -51,6 +52,7 @@ module Dependabot
51
52
  @require_up_to_date_base
52
53
  end
53
54
 
55
+ # rubocop:disable Metrics/PerceivedComplexity
54
56
  def branch_exists?(name)
55
57
  git_metadata_fetcher.ref_names.include?(name)
56
58
  rescue Dependabot::GitDependenciesNotReachable => e
@@ -66,6 +68,7 @@ module Dependabot
66
68
  retrying = true
67
69
  retry
68
70
  end
71
+ # rubocop:enable Metrics/PerceivedComplexity
69
72
 
70
73
  def unmerged_pull_request_exists?
71
74
  pull_requests_for_branch.reject(&:merged).any?
@@ -109,7 +112,11 @@ module Dependabot
109
112
  pull_request = create_pull_request
110
113
  return unless pull_request
111
114
 
112
- 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
113
120
 
114
121
  pull_request
115
122
  end
@@ -415,24 +422,49 @@ module Dependabot
415
422
  end
416
423
 
417
424
  def handle_error(err)
418
- case err
425
+ cause = case err
426
+ when AnnotationError
427
+ err.cause
428
+ else
429
+ err
430
+ end
431
+
432
+ case cause
419
433
  when Octokit::Forbidden
420
- raise RepoDisabled, err.message if err.message.include?("disabled")
421
- 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
422
439
 
423
440
  raise err
424
441
  when Octokit::NotFound
425
442
  raise err if repo_exists?
426
443
 
427
- raise RepoNotFound, err.message
444
+ raise_custom_error err, RepoNotFound, err.message
428
445
  when Octokit::UnprocessableEntity
429
- 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
430
449
 
431
- raise NoHistoryInCommon, err.message
450
+ raise err
432
451
  else
433
452
  raise err
434
453
  end
435
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
436
467
  end
468
+ # rubocop:enable Metrics/ClassLength
437
469
  end
438
470
  end
@@ -113,6 +113,7 @@ module Dependabot
113
113
  end.min
114
114
  end
115
115
 
116
+ # rubocop:disable Metrics/PerceivedComplexity
116
117
  def version(dep)
117
118
  return dep.version if version_class.correct?(dep.version)
118
119
 
@@ -127,7 +128,9 @@ module Dependabot
127
128
 
128
129
  version_from_ref
129
130
  end
131
+ # rubocop:enable Metrics/PerceivedComplexity
130
132
 
133
+ # rubocop:disable Metrics/PerceivedComplexity
131
134
  def previous_version(dep)
132
135
  version_str = dep.previous_version
133
136
  return version_str if version_class.correct?(version_str)
@@ -144,6 +147,7 @@ module Dependabot
144
147
 
145
148
  version_from_ref
146
149
  end
150
+ # rubocop:enable Metrics/PerceivedComplexity
147
151
 
148
152
  def create_default_dependencies_label_if_required
149
153
  return if custom_labels
@@ -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)
@@ -567,7 +366,6 @@ module Dependabot
567
366
  )
568
367
  end
569
368
 
570
- # rubocop:disable Metrics/PerceivedComplexity
571
369
  def previous_version(dependency)
572
370
  # If we don't have a previous version, we *may* still be able to figure
573
371
  # one out if a ref was provided and has been changed (in which case the
@@ -590,7 +388,6 @@ module Dependabot
590
388
  dependency.previous_version
591
389
  end
592
390
  end
593
- # rubocop:enable Metrics/PerceivedComplexity
594
391
 
595
392
  def new_version(dependency)
596
393
  if dependency.version.match?(/^[0-9a-f]{40}$/)
@@ -658,48 +455,6 @@ module Dependabot
658
455
  raise "No new requirement!"
659
456
  end
660
457
 
661
- def link_issues(text:, dependency:)
662
- IssueLinker.
663
- new(source_url: source_url(dependency)).
664
- link_issues(text: text)
665
- end
666
-
667
- def fix_relative_links(text:, base_url:)
668
- text.gsub(/\[.*?\]\([^)]+\)/) do |link|
669
- next link if link.include?("://")
670
-
671
- relative_path = link.match(/\((.*?)\)/).captures.last
672
- base = base_url.split("://").last.gsub(%r{[^/]*$}, "")
673
- path = File.join(base, relative_path)
674
- absolute_path =
675
- base_url.sub(
676
- %r{(?<=://).*$},
677
- Pathname.new(path).cleanpath.to_s
678
- )
679
- link.gsub(relative_path, absolute_path)
680
- end
681
- end
682
-
683
- def sanitize_links_and_mentions(text, unsafe: false)
684
- return text unless source.provider == "github"
685
-
686
- LinkAndMentionSanitizer.
687
- new(github_redirection_service: github_redirection_service).
688
- sanitize_links_and_mentions(text: text, unsafe: unsafe)
689
- end
690
-
691
- def sanitize_template_tags(text)
692
- text.gsub(/\<.*?\>/) do |tag|
693
- tag_contents = tag.match(/\<(.*?)\>/).captures.first.strip
694
-
695
- # Unclosed calls to template overflow out of the blockquote block,
696
- # wrecking the rest of our PRs. Other tags don't share this problem.
697
- next "\\#{tag}" if tag_contents.start_with?("template")
698
-
699
- tag
700
- end
701
- end
702
-
703
458
  def ref_changed?(dependency)
704
459
  previous_ref(dependency) != new_ref(dependency)
705
460
  end
@@ -58,7 +58,6 @@ module Dependabot
58
58
  end
59
59
  end
60
60
 
61
- # rubocop:disable Metrics/PerceivedComplexity
62
61
  def sanitize_links(doc)
63
62
  doc.walk do |node|
64
63
  if node.type == :link && node.url.match?(GITHUB_REF_REGEX)
@@ -81,7 +80,6 @@ module Dependabot
81
80
  end
82
81
  end
83
82
  end
84
- # rubocop:enable Metrics/PerceivedComplexity
85
83
 
86
84
  def replace_github_host(text)
87
85
  text.gsub(
@@ -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
@@ -172,6 +172,7 @@ module Dependabot
172
172
  last_dependabot_commit_message&.split(/[:(]/)&.first
173
173
  end
174
174
 
175
+ # rubocop:disable Metrics/PerceivedComplexity
175
176
  def using_angular_commit_messages?
176
177
  return false if recent_commit_messages.none?
177
178
 
@@ -202,6 +203,7 @@ module Dependabot
202
203
 
203
204
  true
204
205
  end
206
+ # rubocop:enable Metrics/PerceivedComplexity
205
207
 
206
208
  def using_eslint_commit_messages?
207
209
  return false if recent_commit_messages.none?
@@ -178,6 +178,7 @@ module Dependabot
178
178
  )
179
179
  end
180
180
 
181
+ # rubocop:disable Metrics/PerceivedComplexity
181
182
  def self.configure_git_credentials(credentials)
182
183
  # Then add a file-based credential store that loads a file in this repo.
183
184
  # Under the hood this uses git credential-store, but it's invoked through
@@ -221,6 +222,7 @@ module Dependabot
221
222
  # Save the file
222
223
  File.write("git.store", git_store_content)
223
224
  end
225
+ # rubocop:enable Metrics/PerceivedComplexity
224
226
 
225
227
  def self.reset_git_repo(path)
226
228
  Dir.chdir(path) do
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Dependabot
4
- VERSION = "0.119.2"
4
+ VERSION = "0.120.0"
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.2
4
+ version: 0.120.0
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-02 00:00:00.000000000 Z
11
+ date: 2020-09-24 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.88.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.88.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