dependabot-common 0.119.2 → 0.120.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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