dependabot-common 0.212.0 → 0.214.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.
Files changed (30) hide show
  1. checksums.yaml +4 -4
  2. data/lib/dependabot/clients/azure.rb +10 -1
  3. data/lib/dependabot/clients/bitbucket.rb +49 -14
  4. data/lib/dependabot/clients/github_with_retries.rb +15 -19
  5. data/lib/dependabot/config/file.rb +1 -1
  6. data/lib/dependabot/dependency.rb +27 -2
  7. data/lib/dependabot/dependency_file.rb +11 -3
  8. data/lib/dependabot/errors.rb +3 -3
  9. data/lib/dependabot/experiments.rb +19 -0
  10. data/lib/dependabot/file_fetchers/base.rb +164 -80
  11. data/lib/dependabot/file_parsers/base/dependency_set.rb +106 -41
  12. data/lib/dependabot/git_commit_checker.rb +138 -91
  13. data/lib/dependabot/git_metadata_fetcher.rb +22 -18
  14. data/lib/dependabot/pull_request_creator/azure.rb +6 -2
  15. data/lib/dependabot/pull_request_creator/branch_namer.rb +15 -4
  16. data/lib/dependabot/pull_request_creator/github.rb +1 -1
  17. data/lib/dependabot/pull_request_creator/labeler.rb +6 -6
  18. data/lib/dependabot/pull_request_creator/message_builder/issue_linker.rb +5 -5
  19. data/lib/dependabot/pull_request_creator/message_builder/link_and_mention_sanitizer.rb +33 -5
  20. data/lib/dependabot/pull_request_creator/message_builder/metadata_presenter.rb +1 -3
  21. data/lib/dependabot/pull_request_creator/message_builder.rb +78 -6
  22. data/lib/dependabot/pull_request_creator/pr_name_prefixer.rb +3 -2
  23. data/lib/dependabot/pull_request_creator.rb +8 -3
  24. data/lib/dependabot/pull_request_updater/azure.rb +1 -1
  25. data/lib/dependabot/pull_request_updater/github.rb +15 -12
  26. data/lib/dependabot/pull_request_updater.rb +2 -1
  27. data/lib/dependabot/source.rb +9 -9
  28. data/lib/dependabot/update_checkers/base.rb +13 -6
  29. data/lib/dependabot/version.rb +1 -1
  30. metadata +36 -57
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5242196cd22b0092cbdaaf08f6d5ce3f4249d1eeccedada949822b0b14657e9c
4
- data.tar.gz: f47437aa525423bdbb507dfa5b0978863e41f3010682ed1c6f321d2ac67efea9
3
+ metadata.gz: 1fab7bc375e03e37b65e94e3e05e7c9ad945d982295b6c9a030083ed038dbaf3
4
+ data.tar.gz: 9924a1980357d1833988bd19a8119a05162a28cc20cbdf157626744ef93be0ba
5
5
  SHA512:
6
- metadata.gz: cad3f4c8848f45b07d7769bdf4a1b351e3cca4f921bb449cee629ddffc3c579df3b1dfc9343ecfdabd1192d1f1e207e82f8af0c8ee0f142af5856e5bee769d0e
7
- data.tar.gz: c564e966eba317b8b5e61bf4d82df255248ee4932711d85854e38e843ce0f26d0dc22a649cb7e2f475e01f2b0fd61dce160a46a5ecdc0cbe61d560fd5b004587
6
+ metadata.gz: 88069b0acbe42180a064046ab55cba565da0f9a3e00d40582a3fb406aee9e3b357cf8e3bdf34dc84da959c931c1519a87e02022e994baf947193f7d6fb949be8
7
+ data.tar.gz: 785cddd10adbed3413e7fdfcbfcc9b5fa00fde7a55f6e171db0c62f4e4a9f17000dc06d7e4c75d312fda6c7801e9fa6428642ea2b3473dc1b4d7f14e0a660bff
@@ -172,7 +172,8 @@ module Dependabot
172
172
 
173
173
  # rubocop:disable Metrics/ParameterLists
174
174
  def create_pull_request(pr_name, source_branch, target_branch,
175
- pr_description, labels, work_item = nil)
175
+ pr_description, labels,
176
+ reviewers = nil, assignees = nil, work_item = nil)
176
177
  pr_description = truncate_pr_description(pr_description)
177
178
 
178
179
  content = {
@@ -181,6 +182,7 @@ module Dependabot
181
182
  title: pr_name,
182
183
  description: pr_description,
183
184
  labels: labels.map { |label| { name: label } },
185
+ reviewers: pr_reviewers(reviewers, assignees),
184
186
  workItemRefs: [{ id: work_item }]
185
187
  }
186
188
 
@@ -324,6 +326,13 @@ module Dependabot
324
326
  message&.include?("TF401289")
325
327
  end
326
328
 
329
+ def pr_reviewers(reviewers, assignees)
330
+ return [] unless reviewers || assignees
331
+
332
+ pr_reviewers = reviewers&.map { |r_id| { id: r_id, isRequired: true } } || []
333
+ pr_reviewers + (assignees&.map { |r_id| { id: r_id, isRequired: false } } || [])
334
+ end
335
+
327
336
  attr_reader :auth_header
328
337
  attr_reader :credentials
329
338
  attr_reader :source
@@ -12,6 +12,8 @@ module Dependabot
12
12
 
13
13
  class Forbidden < StandardError; end
14
14
 
15
+ class TimedOut < StandardError; end
16
+
15
17
  #######################
16
18
  # Constructor methods #
17
19
  #######################
@@ -79,19 +81,24 @@ module Dependabot
79
81
  JSON.parse(response.body)
80
82
  end
81
83
 
82
- def pull_requests(repo, source_branch, target_branch)
83
- pr_path = "#{repo}/pullrequests"
84
- # Get pull requests with any status
85
- pr_path += "?status=OPEN&status=MERGED&status=DECLINED&status=SUPERSEDED"
84
+ def pull_requests(repo, source_branch, target_branch, status = %w(OPEN MERGED DECLINED SUPERSEDED))
85
+ pr_path = "#{repo}/pullrequests?"
86
+ # Get pull requests with given status
87
+ status.each { |n| pr_path += "status=#{n}&" }
86
88
  next_page_url = base_url + pr_path
87
89
  pull_requests = paginate({ "next" => next_page_url })
88
90
 
89
91
  pull_requests unless source_branch && target_branch
90
92
 
91
93
  pull_requests.select do |pr|
92
- pr_source_branch = pr.fetch("source").fetch("branch").fetch("name")
94
+ if source_branch.nil?
95
+ source_branch_matches = true
96
+ else
97
+ pr_source_branch = pr.fetch("source").fetch("branch").fetch("name")
98
+ source_branch_matches = pr_source_branch == source_branch
99
+ end
93
100
  pr_target_branch = pr.fetch("destination").fetch("branch").fetch("name")
94
- pr_source_branch == source_branch && pr_target_branch == target_branch
101
+ source_branch_matches && pr_target_branch == target_branch
95
102
  end
96
103
  end
97
104
 
@@ -106,8 +113,7 @@ module Dependabot
106
113
  }
107
114
 
108
115
  files.each do |file|
109
- absolute_path = file.name.start_with?("/") ? file.name : "/" + file.name
110
- parameters[absolute_path] = file.content
116
+ parameters[file.path] = file.content
111
117
  end
112
118
 
113
119
  body = encode_form_parameters(parameters)
@@ -144,7 +150,31 @@ module Dependabot
144
150
  end
145
151
  # rubocop:enable Metrics/ParameterLists
146
152
 
153
+ def decline_pull_request(repo, pr_id, comment = nil)
154
+ # https://developer.atlassian.com/cloud/bitbucket/rest/api-group-pullrequests/
155
+ decline_path = "#{repo}/pullrequests/#{pr_id}/decline"
156
+ post(base_url + decline_path, "")
157
+
158
+ comment = "Dependabot declined the pull request." if comment.nil?
159
+
160
+ content = {
161
+ content: {
162
+ raw: comment
163
+ }
164
+ }
165
+
166
+ comment_path = "#{repo}/pullrequests/#{pr_id}/comments"
167
+ post(base_url + comment_path, content.to_json)
168
+ end
169
+
170
+ def current_user
171
+ base_url = "https://api.bitbucket.org/2.0/user?fields=uuid"
172
+ response = get(base_url)
173
+ JSON.parse(response.body).fetch("uuid")
174
+ end
175
+
147
176
  def default_reviewers(repo)
177
+ current_uuid = current_user
148
178
  path = "#{repo}/default-reviewers?pagelen=100&fields=values.uuid,next"
149
179
  reviewers_url = base_url + path
150
180
 
@@ -153,7 +183,7 @@ module Dependabot
153
183
  reviewer_data = []
154
184
 
155
185
  default_reviewers.each do |reviewer|
156
- reviewer_data.append({ uuid: reviewer.fetch("uuid") })
186
+ reviewer_data.append({ uuid: reviewer.fetch("uuid") }) unless current_uuid == reviewer.fetch("uuid")
157
187
  end
158
188
 
159
189
  reviewer_data
@@ -198,6 +228,14 @@ module Dependabot
198
228
  end
199
229
 
200
230
  def post(url, body, content_type = "application/json")
231
+ headers = auth_header
232
+
233
+ headers = if body.empty?
234
+ headers.merge({ "Accept" => "application/json" })
235
+ else
236
+ headers.merge({ "Content-Type" => content_type })
237
+ end
238
+
201
239
  response = Excon.post(
202
240
  url,
203
241
  body: body,
@@ -205,16 +243,13 @@ module Dependabot
205
243
  password: credentials&.fetch("password", nil),
206
244
  idempotent: false,
207
245
  **SharedHelpers.excon_defaults(
208
- headers: auth_header.merge(
209
- {
210
- "Content-Type" => content_type
211
- }
212
- )
246
+ headers: headers
213
247
  )
214
248
  )
215
249
  raise Unauthorized if response.status == 401
216
250
  raise Forbidden if response.status == 403
217
251
  raise NotFound if response.status == 404
252
+ raise TimedOut if response.status == 555
218
253
 
219
254
  response
220
255
  end
@@ -84,7 +84,16 @@ module Dependabot
84
84
  access_tokens << nil if access_tokens.empty?
85
85
  access_tokens.uniq!
86
86
 
87
- @max_retries = max_retries || 3
87
+ Octokit.middleware = Faraday::RackBuilder.new do |builder|
88
+ builder.use Faraday::Retry::Middleware, exceptions: RETRYABLE_ERRORS, max: max_retries || 3
89
+
90
+ Octokit::Default::MIDDLEWARE.handlers.each do |handler|
91
+ next if handler.klass == Faraday::Retry::Middleware
92
+
93
+ builder.use handler.klass
94
+ end
95
+ end
96
+
88
97
  @clients = access_tokens.map do |token|
89
98
  Octokit::Client.new(args.merge(access_token: token))
90
99
  end
@@ -95,13 +104,11 @@ module Dependabot
95
104
  client = untried_clients.pop
96
105
 
97
106
  begin
98
- retry_connection_failures do
99
- if client.respond_to?(method_name)
100
- mutatable_args = args.map(&:dup)
101
- client.public_send(method_name, *mutatable_args, &block)
102
- else
103
- super
104
- end
107
+ if client.respond_to?(method_name)
108
+ mutatable_args = args.map(&:dup)
109
+ client.public_send(method_name, *mutatable_args, &block)
110
+ else
111
+ super
105
112
  end
106
113
  rescue Octokit::NotFound, Octokit::Unauthorized, Octokit::Forbidden
107
114
  raise unless (client = untried_clients.pop)
@@ -113,17 +120,6 @@ module Dependabot
113
120
  def respond_to_missing?(method_name, include_private = false)
114
121
  @clients.first.respond_to?(method_name) || super
115
122
  end
116
-
117
- def retry_connection_failures
118
- retry_attempt = 0
119
-
120
- begin
121
- yield
122
- rescue *RETRYABLE_ERRORS
123
- retry_attempt += 1
124
- retry_attempt <= @max_retries ? retry : raise
125
- end
126
- end
127
123
  end
128
124
  end
129
125
  end
@@ -71,7 +71,7 @@ module Dependabot
71
71
  commit_message = cfg&.dig(:"commit-message") || {}
72
72
  Dependabot::Config::UpdateConfig::CommitMessageOptions.new(
73
73
  prefix: commit_message[:prefix],
74
- prefix_development: commit_message[:"prefix-development"],
74
+ prefix_development: commit_message[:"prefix-development"] || commit_message[:prefix],
75
75
  include: commit_message[:include]
76
76
  )
77
77
  end
@@ -37,11 +37,11 @@ module Dependabot
37
37
 
38
38
  attr_reader :name, :version, :requirements, :package_manager,
39
39
  :previous_version, :previous_requirements,
40
- :subdependency_metadata
40
+ :subdependency_metadata, :metadata
41
41
 
42
42
  def initialize(name:, requirements:, package_manager:, version: nil,
43
43
  previous_version: nil, previous_requirements: nil,
44
- subdependency_metadata: [], removed: false)
44
+ subdependency_metadata: [], removed: false, metadata: {})
45
45
  @name = name
46
46
  @version = version
47
47
  @requirements = requirements.map { |req| symbolize_keys(req) }
@@ -54,6 +54,7 @@ module Dependabot
54
54
  map { |h| symbolize_keys(h) }
55
55
  end
56
56
  @removed = removed
57
+ @metadata = symbolize_keys(metadata || {})
57
58
 
58
59
  check_values
59
60
  end
@@ -66,6 +67,10 @@ module Dependabot
66
67
  @removed
67
68
  end
68
69
 
70
+ def numeric_version
71
+ @numeric_version ||= version_class.new(version) if version && version_class.correct?(version)
72
+ end
73
+
69
74
  def to_h
70
75
  {
71
76
  "name" => name,
@@ -105,6 +110,22 @@ module Dependabot
105
110
  display_name_builder.call(name)
106
111
  end
107
112
 
113
+ # Returns all detected versions of the dependency. Only ecosystems that
114
+ # support this feature will return more than the current version.
115
+ def all_versions
116
+ all_versions = metadata[:all_versions]
117
+ return [version].compact unless all_versions
118
+
119
+ all_versions.filter_map(&:version)
120
+ end
121
+
122
+ # This dependency is being indirectly updated by an update to another
123
+ # dependency. We don't need to try and update it ourselves but want to
124
+ # surface it to the user in the PR.
125
+ def informational_only?
126
+ metadata[:information_only]
127
+ end
128
+
108
129
  def ==(other)
109
130
  other.instance_of?(self.class) && to_h == other.to_h
110
131
  end
@@ -119,6 +140,10 @@ module Dependabot
119
140
 
120
141
  private
121
142
 
143
+ def version_class
144
+ Utils.version_class_for_package_manager(package_manager)
145
+ end
146
+
122
147
  def check_values
123
148
  raise ArgumentError, "blank strings must not be provided as versions" if [version, previous_version].any?("")
124
149
 
@@ -5,7 +5,7 @@ require "pathname"
5
5
  module Dependabot
6
6
  class DependencyFile
7
7
  attr_accessor :name, :content, :directory, :type, :support_file,
8
- :symlink_target, :content_encoding, :operation
8
+ :symlink_target, :content_encoding, :operation, :mode
9
9
 
10
10
  class ContentEncoding
11
11
  UTF_8 = "utf-8"
@@ -20,7 +20,8 @@ module Dependabot
20
20
 
21
21
  def initialize(name:, content:, directory: "/", type: "file",
22
22
  support_file: false, symlink_target: nil,
23
- content_encoding: ContentEncoding::UTF_8, deleted: false, operation: Operation::UPDATE)
23
+ content_encoding: ContentEncoding::UTF_8, deleted: false,
24
+ operation: Operation::UPDATE, mode: nil)
24
25
  @name = name
25
26
  @content = content
26
27
  @directory = clean_directory(directory)
@@ -40,6 +41,12 @@ module Dependabot
40
41
  # support_file flag instead)
41
42
  @type = type
42
43
 
44
+ begin
45
+ @mode = File.stat((symlink_target || path).sub(%r{^/}, "")).mode.to_s(8)
46
+ rescue StandardError
47
+ @mode = mode
48
+ end
49
+
43
50
  return unless (type == "symlink") ^ symlink_target
44
51
 
45
52
  raise "Symlinks must specify a target!" unless symlink_target
@@ -55,7 +62,8 @@ module Dependabot
55
62
  "support_file" => support_file,
56
63
  "content_encoding" => content_encoding,
57
64
  "deleted" => deleted,
58
- "operation" => operation
65
+ "operation" => operation,
66
+ "mode" => mode
59
67
  }
60
68
 
61
69
  details["symlink_target"] = symlink_target if symlink_target
@@ -4,9 +4,9 @@ require "dependabot/utils"
4
4
 
5
5
  module Dependabot
6
6
  class DependabotError < StandardError
7
- BASIC_AUTH_REGEX = %r{://(?<auth>[^:]*:[^@%\s]+(@|%40))}.freeze
7
+ BASIC_AUTH_REGEX = %r{://(?<auth>[^:]*:[^@%\s]+(@|%40))}
8
8
  # Remove any path segment from fury.io sources
9
- FURY_IO_PATH_REGEX = %r{fury\.io/(?<path>.+)}.freeze
9
+ FURY_IO_PATH_REGEX = %r{fury\.io/(?<path>.+)}
10
10
 
11
11
  def initialize(message = nil)
12
12
  super(sanitize_message(message))
@@ -18,7 +18,7 @@ module Dependabot
18
18
  return message unless message.is_a?(String)
19
19
 
20
20
  path_regex =
21
- Regexp.escape(Utils::BUMP_TMP_DIR_PATH) + "\/" +
21
+ Regexp.escape(Utils::BUMP_TMP_DIR_PATH) + "\\/" +
22
22
  Regexp.escape(Utils::BUMP_TMP_FILE_PREFIX) + "[a-zA-Z0-9-]*"
23
23
 
24
24
  message = message.gsub(/#{path_regex}/, "dependabot_tmp_dir").strip
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dependabot
4
+ module Experiments
5
+ @experiments = {}
6
+
7
+ def self.reset!
8
+ @experiments = {}
9
+ end
10
+
11
+ def self.register(name, value)
12
+ @experiments[name.to_sym] = value
13
+ end
14
+
15
+ def self.enabled?(name)
16
+ !!@experiments[name.to_sym]
17
+ end
18
+ end
19
+ end