dependabot-common 0.129.3 → 0.129.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: caa3a193af53d69a8c06fc60d972a0571418b6192dacf2ce20b2b7ddc9011b60
4
- data.tar.gz: d9f6046100711920da02ee7c5a7cf5049d67e3d0c2c614c0ad39bccb31445354
3
+ metadata.gz: afed21fb500f1de6d025f3824fa4a64eff41d0816d44106e044f4a54de984bfe
4
+ data.tar.gz: 3c8c4a17267398cc4efbdc4974a1f8dc78e71aa74f08e194029cb01438938457
5
5
  SHA512:
6
- metadata.gz: f5f0891b60e259e31374cd338c0e155d9dfee28bbe3ee252149b46a9849c5a5bda070aa91384270970e430d331a047a673116a07dc262f70df1708510216993a
7
- data.tar.gz: afcb0cc9ef39a72177eb3880815c139a4d904b860aa257b8c14d4d8427786d85c9ba11862a4581066255b1fc1c19492ea4772be620a96c9e93159f887408101b
6
+ metadata.gz: 7539dc5753d2f66e23cc7b2f5f77b8d7a01e39480b08df5362e08e5012c7249613edc0e25c2dbce80968e40034fdd64b3c4d10adb5ac190a7e870d2288786f05
7
+ data.tar.gz: 6e776353cf20627d05453b2334dbd112f7ab1bf48e959be8f88093d4a4ea74416c557161e14eafc9ef0dd8049d10c52aef7474f2c95541378a0470d34bb047dd
@@ -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
 
@@ -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
@@ -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,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Dependabot
4
- VERSION = "0.129.3"
4
+ VERSION = "0.129.4"
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.3
4
+ version: 0.129.4
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-05 00:00:00.000000000 Z
11
+ date: 2021-01-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk-codecommit
@@ -168,20 +168,6 @@ 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
@@ -396,6 +382,7 @@ files:
396
382
  - lib/dependabot/metadata_finders/base/release_finder.rb
397
383
  - lib/dependabot/pull_request_creator.rb
398
384
  - lib/dependabot/pull_request_creator/azure.rb
385
+ - lib/dependabot/pull_request_creator/bitbucket.rb
399
386
  - lib/dependabot/pull_request_creator/branch_namer.rb
400
387
  - lib/dependabot/pull_request_creator/codecommit.rb
401
388
  - lib/dependabot/pull_request_creator/commit_signer.rb