dependabot-common 0.129.2 → 0.130.1

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: c7174415aef0e15737217d314a45c2630aacae829ef4e513534ad6f4a4a20e0e
4
- data.tar.gz: 0f995c8ec75f07917de8829386a070a2d1ac3dab21162299b2b0cb3fa83190b7
3
+ metadata.gz: 1824c73ccafb3e95ab20e310365a7d2242b7c11d9ca4baf8d78a85754c7874fc
4
+ data.tar.gz: d024003cc13c297a07a528f404fe9b32d731302a543e827ec1c25abdff93209a
5
5
  SHA512:
6
- metadata.gz: 41418972531aedf8379e330be0fc3439ecf7ec7f9d247740be77f9dd2d4a7d6da7c63769fd615bcd378f4e13075a41fab52069557e7cd6f6227ed05058f33f2e
7
- data.tar.gz: 81b2df6efb3465fd42563ea28fa728a170d0bac9b68f7bd0cf13cfe4783d04dbab2bed462e59f7c3cd0fbc4114fc085b57f43bf2fcaf32e66669d1f0a599708b
6
+ metadata.gz: b0e6f725691d7c40f0c5e93ae28ccb765b03e0d39191d73cd66e9c94d166634ba04420a2ce4b5efb68de7f2188081a1a5ae72819384a1a86dc27eb6b9cb29bef
7
+ data.tar.gz: 2334d9e4713a924b67af19f699054b79f8bc36d4854228f0eaafa82047133850fe28cc9a20dd64fa758983d726e180c0c71ab53cda2bdd3208cc11aca7b435ce
@@ -12,6 +12,19 @@ module Dependabot
12
12
 
13
13
  class Forbidden < StandardError; end
14
14
 
15
+ #######################
16
+ # Constructor methods #
17
+ #######################
18
+
19
+ def self.for_source(source:, credentials:)
20
+ credential =
21
+ credentials.
22
+ select { |cred| cred["type"] == "git_source" }.
23
+ find { |cred| cred["host"] == source.hostname }
24
+
25
+ new(credentials: credential)
26
+ end
27
+
15
28
  ##########
16
29
  # Client #
17
30
  ##########
@@ -53,6 +66,81 @@ module Dependabot
53
66
  response.body
54
67
  end
55
68
 
69
+ def commits(repo, branch_name = nil)
70
+ commits_path = "#{repo}/commits/#{branch_name}?pagelen=100"
71
+ next_page_url = base_url + commits_path
72
+ paginate({ "next" => next_page_url })
73
+ end
74
+
75
+ def branch(repo, branch_name)
76
+ branch_path = "#{repo}/refs/branches/#{branch_name}"
77
+ response = get(base_url + branch_path)
78
+
79
+ JSON.parse(response.body)
80
+ end
81
+
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"
86
+ next_page_url = base_url + pr_path
87
+ pull_requests = paginate({ "next" => next_page_url })
88
+
89
+ pull_requests unless source_branch && target_branch
90
+
91
+ pull_requests.select do |pr|
92
+ pr_source_branch = pr.fetch("source").fetch("branch").fetch("name")
93
+ pr_target_branch = pr.fetch("destination").fetch("branch").fetch("name")
94
+ pr_source_branch == source_branch && pr_target_branch == target_branch
95
+ end
96
+ end
97
+
98
+ # rubocop:disable Metrics/ParameterLists
99
+ def create_commit(repo, branch_name, base_commit, commit_message, files,
100
+ author_details)
101
+ parameters = {
102
+ message: commit_message, # TODO: Format markup in commit message
103
+ author: "#{author_details.fetch(:name)} <#{author_details.fetch(:email)}>",
104
+ parents: base_commit,
105
+ branch: branch_name
106
+ }
107
+
108
+ files.each do |file|
109
+ absolute_path = file.name.start_with?("/") ? file.name : "/" + file.name
110
+ parameters[absolute_path] = file.content
111
+ end
112
+
113
+ body = encode_form_parameters(parameters)
114
+
115
+ commit_path = "#{repo}/src"
116
+ post(base_url + commit_path, body, "application/x-www-form-urlencoded")
117
+ end
118
+ # rubocop:enable Metrics/ParameterLists
119
+
120
+ # rubocop:disable Metrics/ParameterLists
121
+ def create_pull_request(repo, pr_name, source_branch, target_branch,
122
+ pr_description, _labels, _work_item = nil)
123
+ content = {
124
+ title: pr_name,
125
+ source: {
126
+ branch: {
127
+ name: source_branch
128
+ }
129
+ },
130
+ destination: {
131
+ branch: {
132
+ name: target_branch
133
+ }
134
+ },
135
+ description: pr_description,
136
+ close_source_branch: true
137
+ }
138
+
139
+ pr_path = "#{repo}/pullrequests"
140
+ post(base_url + pr_path, content.to_json)
141
+ end
142
+ # rubocop:enable Metrics/ParameterLists
143
+
56
144
  def tags(repo)
57
145
  path = "#{repo}/refs/tags?pagelen=100"
58
146
  response = get(base_url + path)
@@ -90,6 +178,28 @@ module Dependabot
90
178
  response
91
179
  end
92
180
 
181
+ def post(url, body, content_type = "application/json")
182
+ response = Excon.post(
183
+ url,
184
+ body: body,
185
+ user: credentials&.fetch("username", nil),
186
+ password: credentials&.fetch("password", nil),
187
+ idempotent: false,
188
+ **SharedHelpers.excon_defaults(
189
+ headers: auth_header.merge(
190
+ {
191
+ "Content-Type" => content_type
192
+ }
193
+ )
194
+ )
195
+ )
196
+ raise Unauthorized if response.status == 401
197
+ raise Forbidden if response.status == 403
198
+ raise NotFound if response.status == 404
199
+
200
+ response
201
+ end
202
+
93
203
  private
94
204
 
95
205
  def auth_header_for(token)
@@ -98,6 +208,37 @@ module Dependabot
98
208
  { "Authorization" => "Bearer #{token}" }
99
209
  end
100
210
 
211
+ def encode_form_parameters(parameters)
212
+ parameters.map do |key, value|
213
+ URI.encode_www_form_component(key.to_s) + "=" + URI.encode_www_form_component(value.to_s)
214
+ end.join("&")
215
+ end
216
+
217
+ # Takes a hash with optional `values` and `next` fields
218
+ # Returns an enumerator.
219
+ #
220
+ # Can be used a few ways:
221
+ # With GET:
222
+ # paginate ({"next" => url})
223
+ # or
224
+ # paginate(JSON.parse(get(url).body))
225
+ #
226
+ # With POST (for endpoints that provide POST methods for long query parameters)
227
+ # response = post(url, body)
228
+ # first_page = JSON.parse(repsonse.body)
229
+ # paginate(first_page)
230
+ def paginate(page)
231
+ Enumerator.new do |yielder|
232
+ loop do
233
+ page.fetch("values", []).each { |value| yielder << value }
234
+ break unless page.key?("next")
235
+
236
+ next_page_url = page.fetch("next")
237
+ page = JSON.parse(get(next_page_url).body)
238
+ end
239
+ end
240
+ end
241
+
101
242
  attr_reader :auth_header
102
243
  attr_reader :credentials
103
244
 
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "logger"
4
+
5
+ module Dependabot
6
+ def self.logger
7
+ @logger ||= Logger.new(nil)
8
+ end
9
+
10
+ def self.logger=(logger)
11
+ @logger = logger
12
+ end
13
+ end
@@ -5,6 +5,7 @@ require "dependabot/metadata_finders"
5
5
  module Dependabot
6
6
  class PullRequestCreator
7
7
  require "dependabot/pull_request_creator/azure"
8
+ require "dependabot/pull_request_creator/bitbucket"
8
9
  require "dependabot/pull_request_creator/codecommit"
9
10
  require "dependabot/pull_request_creator/github"
10
11
  require "dependabot/pull_request_creator/gitlab"
@@ -88,6 +89,7 @@ module Dependabot
88
89
  when "github" then github_creator.create
89
90
  when "gitlab" then gitlab_creator.create
90
91
  when "azure" then azure_creator.create
92
+ when "bitbucket" then bitbucket_creator.create
91
93
  when "codecommit" then codecommit_creator.create
92
94
  else raise "Unsupported provider #{source.provider}"
93
95
  end
@@ -162,6 +164,22 @@ module Dependabot
162
164
  )
163
165
  end
164
166
 
167
+ def bitbucket_creator
168
+ Bitbucket.new(
169
+ source: source,
170
+ branch_name: branch_namer.new_branch_name,
171
+ base_commit: base_commit,
172
+ credentials: credentials,
173
+ files: files,
174
+ commit_message: message_builder.commit_message,
175
+ pr_description: message_builder.pr_message,
176
+ pr_name: message_builder.pr_name,
177
+ author_details: author_details,
178
+ labeler: labeler,
179
+ work_item: provider_metadata&.fetch(:work_item, nil)
180
+ )
181
+ end
182
+
165
183
  def codecommit_creator
166
184
  Codecommit.new(
167
185
  source: source,
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dependabot/clients/bitbucket"
4
+ require "dependabot/pull_request_creator"
5
+
6
+ module Dependabot
7
+ class PullRequestCreator
8
+ class Bitbucket
9
+ attr_reader :source, :branch_name, :base_commit, :credentials,
10
+ :files, :commit_message, :pr_description, :pr_name,
11
+ :author_details, :labeler, :work_item
12
+
13
+ def initialize(source:, branch_name:, base_commit:, credentials:,
14
+ files:, commit_message:, pr_description:, pr_name:,
15
+ author_details:, labeler: nil, work_item: nil)
16
+ @source = source
17
+ @branch_name = branch_name
18
+ @base_commit = base_commit
19
+ @credentials = credentials
20
+ @files = files
21
+ @commit_message = commit_message
22
+ @pr_description = pr_description
23
+ @pr_name = pr_name
24
+ @author_details = author_details
25
+ @labeler = labeler
26
+ @work_item = work_item
27
+ end
28
+
29
+ def create
30
+ return if branch_exists? && pull_request_exists?
31
+
32
+ # FIXME: Copied from Azure, but not verified whether this is true
33
+ # For Bitbucket we create or update a branch in the same request as creating
34
+ # a commit (so we don't need create or update branch logic here)
35
+ create_commit
36
+
37
+ create_pull_request
38
+ end
39
+
40
+ private
41
+
42
+ def bitbucket_client_for_source
43
+ @bitbucket_client_for_source ||=
44
+ Dependabot::Clients::Bitbucket.for_source(
45
+ source: source,
46
+ credentials: credentials
47
+ )
48
+ end
49
+
50
+ def branch_exists?
51
+ bitbucket_client_for_source.branch(source.repo, branch_name)
52
+ rescue Clients::Bitbucket::NotFound
53
+ false
54
+ end
55
+
56
+ def pull_request_exists?
57
+ bitbucket_client_for_source.pull_requests(
58
+ source.repo,
59
+ branch_name,
60
+ source.branch || default_branch
61
+ ).any?
62
+ end
63
+
64
+ def create_commit
65
+ author = author_details&.slice(:name, :email)
66
+ author = nil unless author&.any?
67
+
68
+ bitbucket_client_for_source.create_commit(
69
+ source.repo,
70
+ branch_name,
71
+ base_commit,
72
+ commit_message,
73
+ files,
74
+ author
75
+ )
76
+ end
77
+
78
+ def create_pull_request
79
+ bitbucket_client_for_source.create_pull_request(
80
+ source.repo,
81
+ pr_name,
82
+ branch_name,
83
+ source.branch || default_branch,
84
+ pr_description,
85
+ labeler&.labels_for_pr,
86
+ work_item
87
+ )
88
+ end
89
+
90
+ def default_branch
91
+ @default_branch ||=
92
+ bitbucket_client_for_source.fetch_default_branch(source.repo)
93
+ end
94
+ end
95
+ end
96
+ end
@@ -45,9 +45,13 @@ module Dependabot
45
45
 
46
46
  def sanitize_mentions(doc)
47
47
  doc.walk do |node|
48
- if !parent_node_link?(node) && node.type == :text &&
48
+ if node.type == :text &&
49
49
  node.string_content.match?(MENTION_REGEX)
50
- nodes = build_mention_nodes(node.string_content)
50
+ nodes = if !parent_node_link?(node)
51
+ build_mention_nodes(node.string_content)
52
+ else
53
+ build_mention_link_text_nodes(node.string_content)
54
+ end
51
55
 
52
56
  nodes.each do |n|
53
57
  node.insert_before(n)
@@ -113,12 +117,18 @@ module Dependabot
113
117
  nodes
114
118
  end
115
119
 
120
+ def build_mention_link_text_nodes(text)
121
+ code_node = CommonMarker::Node.new(:code)
122
+ code_node.string_content = text
123
+ [code_node]
124
+ end
125
+
116
126
  def create_link_node(url, text)
117
127
  link_node = CommonMarker::Node.new(:link)
118
- text_node = CommonMarker::Node.new(:text)
128
+ code_node = CommonMarker::Node.new(:code)
119
129
  link_node.url = url
120
- text_node.string_content = text
121
- link_node.append_child(text_node)
130
+ code_node.string_content = text
131
+ link_node.append_child(code_node)
122
132
  link_node
123
133
  end
124
134
 
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "dependabot/clients/azure"
4
+ require "dependabot/clients/bitbucket"
4
5
  require "dependabot/clients/codecommit"
5
6
  require "dependabot/clients/github_with_retries"
6
7
  require "dependabot/clients/gitlab_with_retries"
@@ -264,6 +265,7 @@ module Dependabot
264
265
  when "github" then recent_github_commit_messages
265
266
  when "gitlab" then recent_gitlab_commit_messages
266
267
  when "azure" then recent_azure_commit_messages
268
+ when "bitbucket" then recent_bitbucket_commit_messages
267
269
  when "codecommit" then recent_codecommit_commit_messages
268
270
  else raise "Unsupported provider: #{source.provider}"
269
271
  end
@@ -307,6 +309,18 @@ module Dependabot
307
309
  map(&:strip)
308
310
  end
309
311
 
312
+ def recent_bitbucket_commit_messages
313
+ @recent_bitbucket_commit_messages ||=
314
+ bitbucket_client_for_source.commits(source.repo)
315
+
316
+ @recent_bitbucket_commit_messages.
317
+ reject { |c| bitbucket_commit_author_email(c) == dependabot_email }.
318
+ map { |c| c.fetch("message", nil) }.
319
+ compact.
320
+ reject { |m| m.start_with?("Merge") }.
321
+ map(&:strip)
322
+ end
323
+
310
324
  def recent_codecommit_commit_messages
311
325
  @recent_codecommit_commit_messages ||=
312
326
  codecommit_client_for_source.commits
@@ -324,6 +338,7 @@ module Dependabot
324
338
  when "github" then last_github_dependabot_commit_message
325
339
  when "gitlab" then last_gitlab_dependabot_commit_message
326
340
  when "azure" then last_azure_dependabot_commit_message
341
+ when "bitbucket" then last_bitbucket_dependabot_commit_message
327
342
  when "codecommit" then last_codecommit_dependabot_commit_message
328
343
  else raise "Unsupported provider: #{source.provider}"
329
344
  end
@@ -365,6 +380,16 @@ module Dependabot
365
380
  strip
366
381
  end
367
382
 
383
+ def last_bitbucket_dependabot_commit_message
384
+ @recent_bitbucket_commit_messages ||=
385
+ bitbucket_client_for_source.commits(source.repo)
386
+
387
+ @recent_bitbucket_commit_messages.
388
+ find { |c| bitbucket_commit_author_email(c) == dependabot_email }&.
389
+ fetch("message", nil)&.
390
+ strip
391
+ end
392
+
368
393
  def last_codecommit_dependabot_commit_message
369
394
  @recent_codecommit_commit_messages ||=
370
395
  codecommit_client_for_source.commits(source.repo)
@@ -379,6 +404,11 @@ module Dependabot
379
404
  commit.fetch("author").fetch("email", "")
380
405
  end
381
406
 
407
+ def bitbucket_commit_author_email(commit)
408
+ matches = commit.fetch("author").fetch("raw").match(/<(.*)>/)
409
+ matches ? matches[1] : ""
410
+ end
411
+
382
412
  def github_client_for_source
383
413
  @github_client_for_source ||=
384
414
  Dependabot::Clients::GithubWithRetries.for_source(
@@ -403,6 +433,14 @@ module Dependabot
403
433
  )
404
434
  end
405
435
 
436
+ def bitbucket_client_for_source
437
+ @bitbucket_client_for_source ||=
438
+ Dependabot::Clients::Bitbucket.for_source(
439
+ source: source,
440
+ credentials: credentials
441
+ )
442
+ end
443
+
406
444
  def codecommit_client_for_source
407
445
  @codecommit_client_for_source ||=
408
446
  Dependabot::Clients::CodeCommit.for_source(
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "set"
4
+
3
5
  # TODO: in due course, these "registries" should live in a wrapper gem, not
4
6
  # dependabot-core.
5
7
  module Dependabot
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Dependabot
4
- VERSION = "0.129.2"
4
+ VERSION = "0.130.1"
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.129.2
4
+ version: 0.130.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dependabot
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-01-04 00:00:00.000000000 Z
11
+ date: 2021-01-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk-codecommit
@@ -168,34 +168,26 @@ dependencies:
168
168
  - - "~>"
169
169
  - !ruby/object:Gem::Version
170
170
  version: '2.0'
171
- - !ruby/object:Gem::Dependency
172
- name: parseconfig
173
- requirement: !ruby/object:Gem::Requirement
174
- requirements:
175
- - - "~>"
176
- - !ruby/object:Gem::Version
177
- version: '1.0'
178
- type: :runtime
179
- prerelease: false
180
- version_requirements: !ruby/object:Gem::Requirement
181
- requirements:
182
- - - "~>"
183
- - !ruby/object:Gem::Version
184
- version: '1.0'
185
171
  - !ruby/object:Gem::Dependency
186
172
  name: parser
187
173
  requirement: !ruby/object:Gem::Requirement
188
174
  requirements:
189
- - - "~>"
175
+ - - ">="
190
176
  - !ruby/object:Gem::Version
191
177
  version: '2.5'
178
+ - - "<"
179
+ - !ruby/object:Gem::Version
180
+ version: '4.0'
192
181
  type: :runtime
193
182
  prerelease: false
194
183
  version_requirements: !ruby/object:Gem::Requirement
195
184
  requirements:
196
- - - "~>"
185
+ - - ">="
197
186
  - !ruby/object:Gem::Version
198
187
  version: '2.5'
188
+ - - "<"
189
+ - !ruby/object:Gem::Version
190
+ version: '4.0'
199
191
  - !ruby/object:Gem::Dependency
200
192
  name: toml-rb
201
193
  requirement: !ruby/object:Gem::Requirement
@@ -292,14 +284,14 @@ dependencies:
292
284
  requirements:
293
285
  - - "~>"
294
286
  - !ruby/object:Gem::Version
295
- version: 1.7.0
287
+ version: 1.8.0
296
288
  type: :development
297
289
  prerelease: false
298
290
  version_requirements: !ruby/object:Gem::Requirement
299
291
  requirements:
300
292
  - - "~>"
301
293
  - !ruby/object:Gem::Version
302
- version: 1.7.0
294
+ version: 1.8.0
303
295
  - !ruby/object:Gem::Dependency
304
296
  name: simplecov
305
297
  requirement: !ruby/object:Gem::Requirement
@@ -387,6 +379,7 @@ files:
387
379
  - lib/dependabot/file_updaters/vendor_updater.rb
388
380
  - lib/dependabot/git_commit_checker.rb
389
381
  - lib/dependabot/git_metadata_fetcher.rb
382
+ - lib/dependabot/logger.rb
390
383
  - lib/dependabot/metadata_finders.rb
391
384
  - lib/dependabot/metadata_finders/README.md
392
385
  - lib/dependabot/metadata_finders/base.rb
@@ -396,6 +389,7 @@ files:
396
389
  - lib/dependabot/metadata_finders/base/release_finder.rb
397
390
  - lib/dependabot/pull_request_creator.rb
398
391
  - lib/dependabot/pull_request_creator/azure.rb
392
+ - lib/dependabot/pull_request_creator/bitbucket.rb
399
393
  - lib/dependabot/pull_request_creator/branch_namer.rb
400
394
  - lib/dependabot/pull_request_creator/codecommit.rb
401
395
  - lib/dependabot/pull_request_creator/commit_signer.rb
@@ -438,7 +432,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
438
432
  - !ruby/object:Gem::Version
439
433
  version: 2.7.3
440
434
  requirements: []
441
- rubygems_version: 3.1.4
435
+ rubygems_version: 3.2.3
442
436
  signing_key:
443
437
  specification_version: 4
444
438
  summary: Shared code used between Dependabot package managers