dependabot-common 0.237.0 → 0.239.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,12 +1,43 @@
1
- # typed: true
1
+ # typed: strong
2
2
  # frozen_string_literal: true
3
3
 
4
+ require "sorbet-runtime"
5
+
4
6
  module Dependabot
5
7
  class PullRequestCreator
6
8
  class BranchNamer
7
9
  class Base
8
- attr_reader :dependencies, :files, :target_branch, :separator, :prefix, :max_length
10
+ extend T::Sig
11
+
12
+ sig { returns(T::Array[Dependency]) }
13
+ attr_reader :dependencies
14
+
15
+ sig { returns(T::Array[DependencyFile]) }
16
+ attr_reader :files
17
+
18
+ sig { returns(T.nilable(String)) }
19
+ attr_reader :target_branch
9
20
 
21
+ sig { returns(String) }
22
+ attr_reader :separator
23
+
24
+ sig { returns(String) }
25
+ attr_reader :prefix
26
+
27
+ sig { returns(T.nilable(Integer)) }
28
+ attr_reader :max_length
29
+
30
+ sig do
31
+ params(
32
+ dependencies: T::Array[Dependency],
33
+ files: T::Array[DependencyFile],
34
+ target_branch: T.nilable(String),
35
+ separator: String,
36
+ prefix: String,
37
+ max_length: T.nilable(Integer)
38
+ )
39
+ .void
40
+ end
10
41
  def initialize(dependencies:, files:, target_branch:, separator: "/",
11
42
  prefix: "dependabot", max_length: nil)
12
43
  @dependencies = dependencies
@@ -19,6 +50,7 @@ module Dependabot
19
50
 
20
51
  private
21
52
 
53
+ sig { params(ref_name: String).returns(String) }
22
54
  def sanitize_branch_name(ref_name)
23
55
  # General git ref validation
24
56
  sanitized_name = sanitize_ref(ref_name)
@@ -27,14 +59,15 @@ module Dependabot
27
59
  sanitized_name = sanitized_name.gsub("/", separator)
28
60
 
29
61
  # Shorten the ref in case users refs have length limits
30
- if max_length && (sanitized_name.length > max_length)
31
- sha = Digest::SHA1.hexdigest(sanitized_name)[0, max_length]
32
- sanitized_name[[max_length - sha.size, 0].max..] = sha
62
+ if max_length && (sanitized_name.length > T.must(max_length))
63
+ sha = T.must(Digest::SHA1.hexdigest(sanitized_name)[0, T.must(max_length)])
64
+ sanitized_name[[T.must(max_length) - sha.size, 0].max..] = sha
33
65
  end
34
66
 
35
67
  sanitized_name
36
68
  end
37
69
 
70
+ sig { params(ref: String).returns(String) }
38
71
  def sanitize_ref(ref)
39
72
  # This isn't a complete implementation of git's ref validation, but it
40
73
  # covers most cases that crop up. Its list of allowed characters is a
@@ -8,17 +8,18 @@ module Dependabot
8
8
  class BranchNamer
9
9
  class DependencyGroupStrategy < Base
10
10
  def initialize(dependencies:, files:, target_branch:, dependency_group:,
11
- separator: "/", prefix: "dependabot", max_length: nil)
11
+ separator: "/", prefix: "dependabot", max_length: nil, includes_security_fixes:)
12
12
  super(
13
13
  dependencies: dependencies,
14
14
  files: files,
15
15
  target_branch: target_branch,
16
16
  separator: separator,
17
17
  prefix: prefix,
18
- max_length: max_length
18
+ max_length: max_length,
19
19
  )
20
20
 
21
21
  @dependency_group = dependency_group
22
+ @includes_security_fixes = includes_security_fixes
22
23
  end
23
24
 
24
25
  def new_branch_name
@@ -45,7 +46,11 @@ module Dependabot
45
46
  # Let's append a short hash digest of the dependency changes so that we can
46
47
  # meet this guarantee.
47
48
  def group_name_with_dependency_digest
48
- "#{dependency_group.name}-#{dependency_digest}"
49
+ if @includes_security_fixes
50
+ "group-security-#{package_manager}-#{dependency_digest}"
51
+ else
52
+ "#{dependency_group.name}-#{dependency_digest}"
53
+ end
49
54
  end
50
55
 
51
56
  def dependency_digest
@@ -55,11 +60,11 @@ module Dependabot
55
60
  end
56
61
 
57
62
  def package_manager
58
- dependencies.first.package_manager
63
+ T.must(dependencies.first).package_manager
59
64
  end
60
65
 
61
66
  def directory
62
- files.first.directory.tr(" ", "-")
67
+ T.must(files.first).directory.tr(" ", "-")
63
68
  end
64
69
  end
65
70
  end
@@ -38,31 +38,31 @@ module Dependabot
38
38
  [
39
39
  prefix,
40
40
  package_manager,
41
- files.first.directory.tr(" ", "-"),
41
+ T.must(files.first).directory.tr(" ", "-"),
42
42
  target_branch
43
43
  ].compact
44
44
  end
45
45
 
46
46
  def package_manager
47
- dependencies.first.package_manager
47
+ T.must(dependencies.first).package_manager
48
48
  end
49
49
 
50
50
  def updating_a_property?
51
- dependencies.first
52
- .requirements
53
- .any? { |r| r.dig(:metadata, :property_name) }
51
+ T.must(dependencies.first)
52
+ .requirements
53
+ .any? { |r| r.dig(:metadata, :property_name) }
54
54
  end
55
55
 
56
56
  def updating_a_dependency_set?
57
- dependencies.first
58
- .requirements
59
- .any? { |r| r.dig(:metadata, :dependency_set) }
57
+ T.must(dependencies.first)
58
+ .requirements
59
+ .any? { |r| r.dig(:metadata, :dependency_set) }
60
60
  end
61
61
 
62
62
  def property_name
63
- @property_name ||= dependencies.first.requirements
64
- .find { |r| r.dig(:metadata, :property_name) }
65
- &.dig(:metadata, :property_name)
63
+ @property_name ||= T.must(dependencies.first).requirements
64
+ .find { |r| r.dig(:metadata, :property_name) }
65
+ &.dig(:metadata, :property_name)
66
66
 
67
67
  raise "No property name!" unless @property_name
68
68
 
@@ -70,9 +70,9 @@ module Dependabot
70
70
  end
71
71
 
72
72
  def dependency_set
73
- @dependency_set ||= dependencies.first.requirements
74
- .find { |r| r.dig(:metadata, :dependency_set) }
75
- &.dig(:metadata, :dependency_set)
73
+ @dependency_set ||= T.must(dependencies.first).requirements
74
+ .find { |r| r.dig(:metadata, :dependency_set) }
75
+ &.dig(:metadata, :dependency_set)
76
76
 
77
77
  raise "No dependency set!" unless @dependency_set
78
78
 
@@ -82,7 +82,7 @@ module Dependabot
82
82
  def branch_version_suffix
83
83
  dep = dependencies.first
84
84
 
85
- if dep.removed?
85
+ if T.must(dep).removed?
86
86
  "-removed"
87
87
  elsif library? && ref_changed?(dep) && new_ref(dep)
88
88
  new_ref(dep)
@@ -11,10 +11,11 @@ require "dependabot/pull_request_creator/branch_namer/dependency_group_strategy"
11
11
  module Dependabot
12
12
  class PullRequestCreator
13
13
  class BranchNamer
14
- attr_reader :dependencies, :files, :target_branch, :separator, :prefix, :max_length, :dependency_group
14
+ attr_reader :dependencies, :files, :target_branch, :separator, :prefix, :max_length, :dependency_group,
15
+ :includes_security_fixes
15
16
 
16
17
  def initialize(dependencies:, files:, target_branch:, dependency_group: nil,
17
- separator: "/", prefix: "dependabot", max_length: nil)
18
+ separator: "/", prefix: "dependabot", max_length: nil, includes_security_fixes: false)
18
19
  @dependencies = dependencies
19
20
  @files = files
20
21
  @target_branch = target_branch
@@ -22,6 +23,7 @@ module Dependabot
22
23
  @separator = separator
23
24
  @prefix = prefix
24
25
  @max_length = max_length
26
+ @includes_security_fixes = includes_security_fixes
25
27
  end
26
28
 
27
29
  def new_branch_name
@@ -49,7 +51,8 @@ module Dependabot
49
51
  dependency_group: dependency_group,
50
52
  separator: separator,
51
53
  prefix: prefix,
52
- max_length: max_length
54
+ max_length: max_length,
55
+ includes_security_fixes: includes_security_fixes
53
56
  )
54
57
  end
55
58
  end
@@ -210,7 +210,7 @@ module Dependabot
210
210
 
211
211
  {
212
212
  path: file.realpath,
213
- mode: (file.mode || Dependabot::DependencyFile::Mode::FILE),
213
+ mode: file.mode || Dependabot::DependencyFile::Mode::FILE,
214
214
  type: "blob"
215
215
  }.merge(content)
216
216
  end
@@ -148,7 +148,6 @@ module Dependabot
148
148
  end
149
149
 
150
150
  def build_details_tag(summary:, body:)
151
- # Azure DevOps does not support <details> tag (https://developercommunity.visualstudio.com/content/problem/608769/add-support-for-in-markdown.html)
152
151
  # Bitbucket does not support <details> tag (https://jira.atlassian.com/browse/BCLOUD-20231)
153
152
  # CodeCommit does not support the <details> tag (no url available)
154
153
  if source_provider_supports_html?
@@ -244,7 +243,7 @@ module Dependabot
244
243
  end
245
244
 
246
245
  def source_provider_supports_html?
247
- !%w(azure bitbucket codecommit).include?(source.provider)
246
+ !%w(bitbucket codecommit).include?(source.provider)
248
247
  end
249
248
 
250
249
  def sanitize_links_and_mentions(text, unsafe: false)
@@ -85,7 +85,7 @@ module Dependabot
85
85
  msg = (msg[0..trunc_length] + tr_msg)
86
86
  end
87
87
  # if we used a custom encoding for calculating length, then we need to force back to UTF-8
88
- msg.force_encoding(Encoding::UTF_8) unless pr_message_encoding.nil?
88
+ msg = msg.encode("utf-8", "binary", invalid: :replace, undef: :replace) unless pr_message_encoding.nil?
89
89
  msg
90
90
  end
91
91
 
@@ -162,7 +162,13 @@ module Dependabot
162
162
 
163
163
  def group_pr_name
164
164
  updates = dependencies.map(&:name).uniq.count
165
- "bump the #{dependency_group.name} group#{pr_name_directory} with #{updates} update#{'s' if updates > 1}"
165
+
166
+ if source&.directories
167
+ "bump the #{dependency_group.name} across #{source.directories.count} directories " \
168
+ "with #{updates} update#{'s' if updates > 1}"
169
+ else
170
+ "bump the #{dependency_group.name} group#{pr_name_directory} with #{updates} update#{'s' if updates > 1}"
171
+ end
166
172
  end
167
173
 
168
174
  def pr_name_prefix
@@ -260,6 +266,8 @@ module Dependabot
260
266
  # rubocop:disable Metrics/PerceivedComplexity
261
267
  # rubocop:disable Metrics/AbcSize
262
268
  def version_commit_message_intro
269
+ return multi_directory_group_intro if dependency_group && source&.directories
270
+
263
271
  return group_intro if dependency_group
264
272
 
265
273
  return multidependency_property_intro if dependencies.count > 1 && updating_a_property?
@@ -346,6 +354,42 @@ module Dependabot
346
354
  msg
347
355
  end
348
356
 
357
+ def multi_directory_group_intro
358
+ msg = ""
359
+
360
+ source.directories.each do |directory|
361
+ dependencies_in_directory = dependencies.select { |dep| dep.metadata[:directory] == directory }
362
+ next unless dependencies_in_directory.any?
363
+
364
+ update_count = dependencies_in_directory.map(&:name).uniq.count
365
+
366
+ msg += "Bumps the #{dependency_group.name} " \
367
+ "with #{update_count} update#{update_count > 1 ? 's' : ''} in the #{directory} directory:"
368
+
369
+ msg += if update_count >= 5
370
+ header = %w(Package From To)
371
+ rows = dependencies_in_directory.map do |dep|
372
+ [
373
+ dependency_link(dep),
374
+ "`#{dep.humanized_previous_version}`",
375
+ "`#{dep.humanized_version}`"
376
+ ]
377
+ end
378
+ "\n\n#{table([header] + rows)}"
379
+ elsif update_count > 1
380
+ dependency_links_in_directory = dependency_links_for_directory(directory)
381
+ " #{dependency_links_in_directory[0..-2].join(', ')} and #{dependency_links_in_directory[-1]}."
382
+ else
383
+ dependency_links_in_directory = dependency_links_for_directory(directory)
384
+ " #{dependency_links_in_directory.first}."
385
+ end
386
+
387
+ msg += "\n"
388
+ end
389
+
390
+ msg
391
+ end
392
+
349
393
  def group_intro
350
394
  update_count = dependencies.map(&:name).uniq.count
351
395
 
@@ -427,6 +471,12 @@ module Dependabot
427
471
  @dependency_links = uniq_deps.map { |dep| dependency_link(dep) }
428
472
  end
429
473
 
474
+ def dependency_links_for_directory(directory)
475
+ dependencies_in_directory = dependencies.select { |dep| dep.metadata[:directory] == directory }
476
+ uniq_deps = dependencies_in_directory.each_with_object({}) { |dep, memo| memo[dep.name] ||= dep }.values
477
+ @dependency_links = uniq_deps.map { |dep| dependency_link(dep) }
478
+ end
479
+
430
480
  def dependency_link(dependency)
431
481
  if source_url(dependency)
432
482
  "[#{dependency.display_name}](#{source_url(dependency)})"
@@ -442,7 +492,7 @@ module Dependabot
442
492
  end
443
493
 
444
494
  def metadata_links
445
- return metadata_links_for_dep(dependencies.first) if dependencies.count == 1
495
+ return metadata_links_for_dep(dependencies.first) if dependencies.count == 1 && dependency_group.nil?
446
496
 
447
497
  dependencies.map do |dep|
448
498
  if dep.removed?
@@ -483,8 +533,8 @@ module Dependabot
483
533
  "| #{row.join(' | ')} |"
484
534
  end
485
535
 
486
- def metadata_cascades
487
- return metadata_cascades_for_dep(dependencies.first) if dependencies.one?
536
+ def metadata_cascades # rubocop:disable Metrics/PerceivedComplexity
537
+ return metadata_cascades_for_dep(dependencies.first) if dependencies.one? && !dependency_group
488
538
 
489
539
  dependencies.map do |dep|
490
540
  msg = if dep.removed?
@@ -266,7 +266,8 @@ module Dependabot
266
266
  dependency_group: dependency_group,
267
267
  separator: branch_name_separator,
268
268
  prefix: branch_name_prefix,
269
- max_length: branch_name_max_length
269
+ max_length: branch_name_max_length,
270
+ includes_security_fixes: includes_security_fixes?
270
271
  )
271
272
  end
272
273
 
@@ -0,0 +1,20 @@
1
+ # typed: strong
2
+ # frozen_string_literal: true
3
+
4
+ require "sorbet-runtime"
5
+
6
+ module Dependabot
7
+ class Requirement < Gem::Requirement
8
+ extend T::Sig
9
+ extend T::Helpers
10
+
11
+ abstract!
12
+
13
+ sig do
14
+ abstract
15
+ .params(requirement_string: T.nilable(String))
16
+ .returns(T::Array[Requirement])
17
+ end
18
+ def self.requirements_array(requirement_string); end
19
+ end
20
+ end
@@ -4,6 +4,8 @@
4
4
  require "tmpdir"
5
5
  require "set"
6
6
  require "sorbet-runtime"
7
+
8
+ require "dependabot/requirement"
7
9
  require "dependabot/version"
8
10
  require "dependabot/config/file"
9
11
 
@@ -33,9 +35,9 @@ module Dependabot
33
35
  @version_classes[package_manager] = version_class
34
36
  end
35
37
 
36
- @requirement_classes = T.let({}, T::Hash[String, T.class_of(Gem::Requirement)])
38
+ @requirement_classes = T.let({}, T::Hash[String, T.class_of(Dependabot::Requirement)])
37
39
 
38
- sig { params(package_manager: String).returns(T.class_of(Gem::Requirement)) }
40
+ sig { params(package_manager: String).returns(T.class_of(Dependabot::Requirement)) }
39
41
  def self.requirement_class_for_package_manager(package_manager)
40
42
  requirement_class = @requirement_classes[package_manager]
41
43
  return requirement_class if requirement_class
@@ -43,7 +45,7 @@ module Dependabot
43
45
  raise "Unregistered package_manager #{package_manager}"
44
46
  end
45
47
 
46
- sig { params(package_manager: String, requirement_class: T.class_of(Gem::Requirement)).void }
48
+ sig { params(package_manager: String, requirement_class: T.class_of(Dependabot::Requirement)).void }
47
49
  def self.register_requirement_class(package_manager, requirement_class)
48
50
  validate_package_manager!(package_manager)
49
51
 
@@ -1,4 +1,4 @@
1
- # typed: strict
1
+ # typed: strong
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "sorbet-runtime"
data/lib/dependabot.rb CHANGED
@@ -2,5 +2,5 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module Dependabot
5
- VERSION = "0.237.0"
5
+ VERSION = "0.239.0"
6
6
  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.237.0
4
+ version: 0.239.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dependabot
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-11-21 00:00:00.000000000 Z
11
+ date: 2023-12-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk-codecommit
@@ -154,6 +154,20 @@ dependencies:
154
154
  - - '='
155
155
  - !ruby/object:Gem::Version
156
156
  version: 4.19.0
157
+ - !ruby/object:Gem::Dependency
158
+ name: json
159
+ requirement: !ruby/object:Gem::Requirement
160
+ requirements:
161
+ - - "<"
162
+ - !ruby/object:Gem::Version
163
+ version: '2.7'
164
+ type: :runtime
165
+ prerelease: false
166
+ version_requirements: !ruby/object:Gem::Requirement
167
+ requirements:
168
+ - - "<"
169
+ - !ruby/object:Gem::Version
170
+ version: '2.7'
157
171
  - !ruby/object:Gem::Dependency
158
172
  name: nokogiri
159
173
  requirement: !ruby/object:Gem::Requirement
@@ -360,14 +374,14 @@ dependencies:
360
374
  requirements:
361
375
  - - "~>"
362
376
  - !ruby/object:Gem::Version
363
- version: 1.57.2
377
+ version: 1.58.0
364
378
  type: :development
365
379
  prerelease: false
366
380
  version_requirements: !ruby/object:Gem::Requirement
367
381
  requirements:
368
382
  - - "~>"
369
383
  - !ruby/object:Gem::Version
370
- version: 1.57.2
384
+ version: 1.58.0
371
385
  - !ruby/object:Gem::Dependency
372
386
  name: rubocop-performance
373
387
  requirement: !ruby/object:Gem::Requirement
@@ -491,6 +505,7 @@ files:
491
505
  - lib/dependabot/file_updaters/vendor_updater.rb
492
506
  - lib/dependabot/git_commit_checker.rb
493
507
  - lib/dependabot/git_metadata_fetcher.rb
508
+ - lib/dependabot/git_ref.rb
494
509
  - lib/dependabot/logger.rb
495
510
  - lib/dependabot/metadata_finders.rb
496
511
  - lib/dependabot/metadata_finders/README.md
@@ -522,6 +537,7 @@ files:
522
537
  - lib/dependabot/pull_request_updater/github.rb
523
538
  - lib/dependabot/pull_request_updater/gitlab.rb
524
539
  - lib/dependabot/registry_client.rb
540
+ - lib/dependabot/requirement.rb
525
541
  - lib/dependabot/security_advisory.rb
526
542
  - lib/dependabot/shared_helpers.rb
527
543
  - lib/dependabot/simple_instrumentor.rb
@@ -542,7 +558,7 @@ licenses:
542
558
  - Nonstandard
543
559
  metadata:
544
560
  bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
545
- changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.237.0
561
+ changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.239.0
546
562
  post_install_message:
547
563
  rdoc_options: []
548
564
  require_paths: