dependabot-common 0.212.0 → 0.214.0

Sign up to get free protection for your applications and to get access to all the features.
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