pronto 0.10.0 → 0.11.0

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: c46191096dc80dd16c7d74cb071776e3d527c58030b205f13ef7cdd814bc2a75
4
- data.tar.gz: c0e30815ad2b8e4cc4dc5b0e3f020347346a2e27463855951399b270b136015b
3
+ metadata.gz: 46470dd7ac5341cc9bebbf13127f62c06d5d5a19cf55578a40439265761d59b3
4
+ data.tar.gz: a6a51d6593f9c4e521c8adf4a7fca559c3342931e7b207659e620d8d3585678a
5
5
  SHA512:
6
- metadata.gz: 005ccdcd8d549c490828c473658708c273f982fca0923897444cb84d02e2757b539d1acdf2accbe87220e08a55d5d2b3168780090c996e0449416cde798eaf92
7
- data.tar.gz: 4b3b8aefc717056f27840f5ad1693f6d053e4988c4d892b281dadb55ac6dbbe9824dd97bccc609caab3d2e772e60802bb45c0021772ef64fb19883219bd4f62e
6
+ metadata.gz: e500bc433123227725e318c285995986ba6cf4a5281cbcb2be92aaac130515a788be5fabdd957d9d95e2f58fb95708bed6db193ab340c123760d8210471f4995
7
+ data.tar.gz: 1342570798515c8efdfcc17eaf383c308c8875031dd61cb4eef5821513c8e3a748b411b7112d5c210dabda11afc0831fc5767f08729dcad8d452e9c1215c60c1
@@ -0,0 +1,3 @@
1
+ # Order is important. The last matching pattern takes the most precedence.
2
+ # Default owners for everything in the repo.
3
+ * @prontolabs/core
@@ -2,6 +2,35 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 0.11.0
6
+
7
+ ### New features
8
+
9
+ * [#304](https://github.com/prontolabs/pronto/pull/304) add option to limit comments per PR review
10
+ * [#333](https://github.com/prontolabs/pronto/pull/333) add github_combined_status formatter
11
+ * [#334](https://github.com/prontolabs/pronto/pull/334) add configurable review_type for GitHub (with REQUEST_CHANGES as default)
12
+ * [#351](https://github.com/prontolabs/pronto/pull/351) add gitLab_mr formatter
13
+ * [#369](https://github.com/prontolabs/pronto/pull/369) make Pronto::Git::Patch#new_file_path public
14
+ * update to the BitBucket 2.0 API (_as the 1.0 API was deprecated_) via [#347](https://github.com/prontolabs/pronto/pull/347), [#348](https://github.com/prontolabs/pronto/pull/348), [#352](https://github.com/prontolabs/pronto/pull/352) and [#354](https://github.com/prontolabs/pronto/pull/354)
15
+
16
+ ### Bugs fixed
17
+
18
+ * [#344](https://github.com/prontolabs/pronto/pull/344) treat Gemfile and .gemspecs as Ruby
19
+ * [#380](https://github.com/prontolabs/pronto/pull/380) fix compatibility with rugged >= 0.99
20
+ * [#387](https://github.com/prontolabs/pronto/pull/387) fix running pronto inside git submodules
21
+
22
+ ### Changes
23
+
24
+ * [#370](https://github.com/prontolabs/pronto/pull/370) allow thor 1.x gem versions
25
+ * [#379](https://github.com/prontolabs/pronto/pull/379) allow rugged 1.0.x gem versions
26
+ * [#386](https://github.com/prontolabs/pronto/pull/386) add ruby 2.7 to CI
27
+ * [#390](https://github.com/prontolabs/pronto/pull/390) fix issue with generating Sorbet RBI
28
+ * [#396](https://github.com/prontolabs/pronto/pull/396) add support for Ruby 3.0
29
+ * document/improve GitHub Actions integration in README.md via [#360](https://github.com/prontolabs/pronto/pull/360), [#378](https://github.com/prontolabs/pronto/pull/378) and [#389](https://github.com/prontolabs/pronto/pull/389)
30
+ * add links to additional pronto runners in README.md
31
+
32
+ ## 0.10.0
33
+
5
34
  ### New features
6
35
 
7
36
  * [#301](https://github.com/prontolabs/pronto/pull/301): add ability to auto approve Bitbucket pull requests.
data/README.md CHANGED
@@ -110,18 +110,40 @@ If you want comments to appear on pull request diff, instead of commit:
110
110
  $ PRONTO_GITHUB_ACCESS_TOKEN=token pronto run -f github_pr -c origin/master
111
111
  ```
112
112
 
113
- If you want review to appear on pull request diff, instead of comments:
113
+ If you want review to appear on pull request diff, instead of separate comments:
114
114
 
115
115
  ```sh
116
116
  $ PRONTO_GITHUB_ACCESS_TOKEN=token pronto run -f github_pr_review -c origin/master
117
117
  ```
118
118
 
119
+ All the **N** pending comments will be now separated into **X** number of PR reviews.
120
+ The number of the PR reviews will be controlled by an additional environment variable or with the help of a config setting.
121
+ This way, by a single pronto run, all the comments will be published to the PR, but divided into small reviews
122
+ in order to avoid the rate limit of the providers.
123
+
124
+ ```
125
+ X = N / {PRONTO_WARNINGS_PER_REVIEW || warnings_per_review || 30})
126
+ ```
127
+
128
+ Note: In case no environment variable or config setting is specified in `.pronto.yml`,
129
+ a default value of `30` will be used.
130
+
131
+ ```sh
132
+ $ PRONTO_WARNINGS_PER_REVIEW=30 PRONTO_GITHUB_ACCESS_TOKEN=token pronto run -f github_pr_review -c origin/master
133
+ ```
134
+
119
135
  Use `GithubStatusFormatter` to submit [commit status](https://github.com/blog/1227-commit-status-api):
120
136
 
121
137
  ```sh
122
138
  $ PRONTO_GITHUB_ACCESS_TOKEN=token pronto run -f github_status -c origin/master
123
139
  ```
124
140
 
141
+ If you want to show a one single status for all runners, instead of status per runner:
142
+
143
+ ```sh
144
+ $ PRONTO_GITHUB_ACCESS_TOKEN=token pronto run -f github_combined_status -c origin/master
145
+ ```
146
+
125
147
  It's possible to combine multiple formatters.
126
148
  To get both pull request comments and commit status summary use:
127
149
 
@@ -140,6 +162,39 @@ formatters = [formatter, status_formatter]
140
162
  Pronto.run('origin/master', '.', formatters)
141
163
  ```
142
164
 
165
+ #### GitHub Actions Integration
166
+
167
+ You can also run Pronto as a GitHub action.
168
+
169
+ Here's an example `.github/workflows/pronto.yml` workflow file using the `github_status` and `github_pr` formatters and running on each GitHub PR, with `pronto-rubocop` as the runner:
170
+
171
+
172
+ ```yml
173
+ name: Pronto
174
+ on: [pull_request]
175
+
176
+ jobs:
177
+ pronto:
178
+
179
+ runs-on: ubuntu-latest
180
+
181
+ steps:
182
+ - name: Checkout code
183
+ uses: actions/checkout@v2
184
+ - run: |
185
+ git fetch --no-tags --prune --depth=10 origin +refs/heads/*:refs/remotes/origin/*
186
+ - name: Setup Ruby
187
+ uses: ruby/setup-ruby@v1
188
+ - name: Setup pronto
189
+ run: gem install pronto pronto-rubocop
190
+ - name: Run Pronto
191
+ run: pronto run -f github_status github_pr -c origin/${{ github.base_ref }}
192
+ env:
193
+ PRONTO_PULL_REQUEST_ID: ${{ github.event.pull_request.number }}
194
+ PRONTO_GITHUB_ACCESS_TOKEN: "${{ github.token }}"
195
+ ```
196
+ check Wiki on [GitHub Actions Integration](https://github.com/prontolabs/pronto/wiki/GitHub-Actions-Integration) for more info.
197
+
143
198
  ### GitLab Integration
144
199
 
145
200
  You can run Pronto as a step of your CI builds and get the results as comments
@@ -159,6 +214,29 @@ Then just run it:
159
214
  $ PRONTO_GITLAB_API_PRIVATE_TOKEN=token pronto run -f gitlab -c origin/master
160
215
  ```
161
216
 
217
+ **note: this requires at least Gitlab 11.6+**
218
+
219
+ Merge request integration:
220
+
221
+ ```sh
222
+ $ PRONTO_GITLAB_API_PRIVATE_TOKEN=token PRONTO_PULL_REQUEST_ID=id pronto run -f gitlab_mr -c origin/master
223
+ ```
224
+
225
+ On GitLabCI make make sure to run Pronto in a [merge request pipeline](https://docs.gitlab.com/ce/ci/merge_request_pipelines/):
226
+
227
+ ```yml
228
+ lint:
229
+ image: ruby
230
+ variables:
231
+ PRONTO_GITLAB_API_ENDPOINT: "https://gitlab.com/api/v4"
232
+ PRONTO_GITLAB_API_PRIVATE_TOKEN: token
233
+ only:
234
+ - merge_requests
235
+ script:
236
+ - bundle install
237
+ - bundle exec pronto run -f gitlab_mr -c origin/$CI_MERGE_REQUEST_TARGET_BRANCH_NAME
238
+ ```
239
+
162
240
  ### Bitbucket Integration
163
241
 
164
242
  You can run Pronto as a step of your CI builds and get the results as comments
@@ -210,6 +288,7 @@ bitbucket:
210
288
  password: pass
211
289
  web_endpoint: https://bitbucket.org/
212
290
  max_warnings: 150
291
+ warnings_per_review: 30
213
292
  verbose: false
214
293
  ```
215
294
 
@@ -260,13 +339,17 @@ The following values are available only to the text formatter:
260
339
  Pronto can run various tools and libraries, as long as there's a runner for it.
261
340
  Currently available:
262
341
 
342
+ * [pronto-bigfiles](https://github.com/apiology/pronto-bigfiles)
263
343
  * [pronto-blacklist](https://github.com/pbstriker38/pronto-blacklist)
264
344
  * [pronto-brakeman](https://github.com/prontolabs/pronto-brakeman)
345
+ * [pronto-bundler_audit](https://github.com/pdobb/pronto-bundler_audit)
346
+ * [pronto-checkstyle](https://github.com/seikichi/pronto-checkstyle)
265
347
  * [pronto-coffeelint](https://github.com/siebertm/pronto-coffeelint)
266
348
  * [pronto-clang_format](https://github.com/micjabbour/pronto-clang_format)
267
349
  * [pronto-clang_tidy](https://github.com/micjabbour/pronto-clang_tidy)
268
350
  * [pronto-clippy](https://github.com/hauleth/pronto-clippy)
269
351
  * [pronto-credo](https://github.com/carakan/pronto-credo)
352
+ * [pronto-dialyxir](https://github.com/Apelsinka223/pronto-dialyxir)
270
353
  * [pronto-dialyzer](https://github.com/iurifq/pronto-dialyzer)
271
354
  * [pronto-dirty_words](https://github.com/kevinjalbert/pronto-dirty_words)
272
355
  * [pronto-dogma](https://github.com/iurifq/pronto-dogma)
@@ -274,11 +357,15 @@ Currently available:
274
357
  * [pronto-eslint](https://github.com/prontolabs/pronto-eslint) (uses [eslintrb](https://github.com/zendesk/eslintrb))
275
358
  * [pronto-eslint_npm](https://github.com/doits/pronto-eslint_npm) (uses eslint installed from npm)
276
359
  * [pronto-fasterer](https://github.com/prontolabs/pronto-fasterer)
360
+ * [pronto-findbugs](https://github.com/seikichi/pronto-findbugs)
277
361
  * [pronto-flake8](https://github.com/scoremedia/pronto-flake8)
278
362
  * [pronto-flay](https://github.com/prontolabs/pronto-flay)
279
363
  * [pronto-flow](https://github.com/kevinjalbert/pronto-flow)
280
364
  * [pronto-foodcritic](https://github.com/prontolabs/pronto-foodcritic)
365
+ * [pronto-goodcheck](https://github.com/aergonaut/pronto-goodcheck)
281
366
  * [pronto-haml](https://github.com/prontolabs/pronto-haml)
367
+ * [pronto-hlint](https://github.com/fretlink/pronto-hlint/) (uses Haskell code suggestions [hlint](https://github.com/ndmitchell/hlint))
368
+ * [pronto-infer](https://github.com/seikichi/pronto-infer)
282
369
  * [pronto-inspec](https://github.com/stiller-leser/pronto-inspec)
283
370
  * [pronto-jscs](https://github.com/spajus/pronto-jscs)
284
371
  * [pronto-jshint](https://github.com/prontolabs/pronto-jshint)
@@ -289,7 +376,9 @@ Currently available:
289
376
  * [pronto-phpmd](https://github.com/EllisV/pronto-phpmd)
290
377
  * [pronto-phpstan](https://github.com/Powerhamster/pronto-phpstan)
291
378
  * [pronto-poper](https://github.com/prontolabs/pronto-poper)
379
+ * [pronto-punchlist](https://github.com/apiology/pronto-punchlist)
292
380
  * [pronto-rails_best_practices](https://github.com/prontolabs/pronto-rails_best_practices)
381
+ * [pronto-rails_data_schema](https://github.com/mbajur/pronto-rails_data_schema)
293
382
  * [pronto-rails_schema](https://github.com/raimondasv/pronto-rails_schema)
294
383
  * [pronto-reek](https://github.com/prontolabs/pronto-reek)
295
384
  * [pronto-rubocop](https://github.com/prontolabs/pronto-rubocop)
@@ -297,15 +386,17 @@ Currently available:
297
386
  * [pronto-shellcheck](https://github.com/pclalv/pronto-shellcheck)
298
387
  * [pronto-slim](https://github.com/nysthee/pronto-slim)
299
388
  * [pronto-slim_lint](https://github.com/ibrahima/pronto-slim_lint)
389
+ * [pronto-sorbet](https://github.com/teamsimplepay/pronto-sorbet)
300
390
  * [pronto-spell](https://github.com/prontolabs/pronto-spell)
391
+ * [pronto-standardrb](https://github.com/julianrubisch/pronto-standardrb)
301
392
  * [pronto-stylelint](https://github.com/kevinjalbert/pronto-stylelint)
302
393
  * [pronto-swiftlint](https://github.com/ajanauskas/pronto-swiftlint)
303
394
  * [pronto-tailor](https://github.com/ajanauskas/pronto-tailor)
304
395
  * [pronto-textlint](https://github.com/seikichi/pronto-textlint)
305
396
  * [pronto-tslint_npm](https://github.com/eprislac/pronto-tslint_npm)
306
397
  * [pronto-yamllint](https://github.com/pauliusm/pronto-yamllint)
307
- * [pronto-goodcheck](https://github.com/aergonaut/pronto-goodcheck)
308
398
  * [pronto-undercover](https://github.com/grodowski/pronto-undercover)
399
+ * [pronto-xmllint](https://github.com/pauliusm/pronto-xmllint)
309
400
 
310
401
  ## Articles
311
402
 
@@ -42,9 +42,11 @@ require 'pronto/formatter/commit_formatter'
42
42
  require 'pronto/formatter/pull_request_formatter'
43
43
  require 'pronto/formatter/github_formatter'
44
44
  require 'pronto/formatter/github_status_formatter'
45
+ require 'pronto/formatter/github_combined_status_formatter'
45
46
  require 'pronto/formatter/github_pull_request_formatter'
46
47
  require 'pronto/formatter/github_pull_request_review_formatter'
47
48
  require 'pronto/formatter/gitlab_formatter'
49
+ require 'pronto/formatter/gitlab_merge_request_review_formatter'
48
50
  require 'pronto/formatter/bitbucket_formatter'
49
51
  require 'pronto/formatter/bitbucket_pull_request_formatter'
50
52
  require 'pronto/formatter/bitbucket_server_pull_request_formatter'
@@ -1,28 +1,39 @@
1
1
  class BitbucketClient
2
2
  include HTTParty
3
- base_uri 'https://api.bitbucket.org/1.0/repositories'
3
+ base_uri 'https://api.bitbucket.org/2.0/repositories'
4
4
 
5
5
  def initialize(username, password)
6
6
  self.class.basic_auth(username, password)
7
7
  end
8
8
 
9
9
  def commit_comments(slug, sha)
10
- response = get("/#{slug}/changesets/#{sha}/comments")
11
- openstruct(response)
10
+ response = get("/#{slug}/commit/#{sha}/comments?pagelen=100")
11
+ result = parse_comments(openstruct(response))
12
+ while (response['next'])
13
+ response = get response['next']
14
+ result.concat(parse_comments(openstruct(response)))
15
+ end
16
+ result
12
17
  end
13
18
 
14
19
  def create_commit_comment(slug, sha, body, path, position)
15
- post("/#{slug}/changesets/#{sha}/comments", body, path, position)
20
+ post("/#{slug}/commit/#{sha}/comments", body, path, position)
16
21
  end
17
22
 
18
23
  def pull_comments(slug, pull_id)
19
- response = get("/#{slug}/pullrequests/#{pull_id}/comments")
20
- openstruct(response)
24
+ response = get("/#{slug}/pullrequests/#{pull_id}/comments?pagelen=100")
25
+ parse_comments(openstruct(response))
26
+ result = parse_comments(openstruct(response))
27
+ while (response['next'])
28
+ response = get response['next']
29
+ result.concat(parse_comments(openstruct(response)))
30
+ end
31
+ result
21
32
  end
22
33
 
23
34
  def pull_requests(slug)
24
- response = get("#{pull_request_api(slug)}/pullrequests?state=OPEN")
25
- openstruct(response['values'])
35
+ response = get("/#{slug}/pullrequests?state=OPEN")
36
+ openstruct(response)
26
37
  end
27
38
 
28
39
  def create_pull_comment(slug, pull_id, body, path, position)
@@ -30,29 +41,46 @@ class BitbucketClient
30
41
  end
31
42
 
32
43
  def approve_pull_request(slug, pull_id)
33
- self.class.post("#{pull_request_api(slug)}/pullrequests/#{pull_id}/approve")
44
+ self.class.post("/#{slug}/pullrequests/#{pull_id}/approve")
34
45
  end
35
46
 
36
47
  def unapprove_pull_request(slug, pull_id)
37
- self.class.delete("#{pull_request_api(slug)}/pullrequests/#{pull_id}/approve")
48
+ self.class.delete("/#{slug}/pullrequests/#{pull_id}/approve")
38
49
  end
39
50
 
40
51
  private
41
52
 
42
- def pull_request_api(slug)
43
- "https://api.bitbucket.org/2.0/repositories/#{slug}"
44
- end
45
-
46
53
  def openstruct(response)
47
- response.map { |r| OpenStruct.new(r) }
54
+ if response['values']
55
+ response['values'].map { |r| OpenStruct.new(r) }
56
+ else
57
+ p response
58
+ raise 'BitBucket response invalid'
59
+ end
48
60
  end
49
61
 
62
+ def parse_comments(values)
63
+ values.each do |value|
64
+ value.content = value.content['raw']
65
+ value.line_to = value.inline ? value.inline['to'] : 0
66
+ value.filename = value.inline ? value.inline['path'] : ''
67
+ end
68
+ values
69
+ end
70
+
50
71
  def post(url, body, path, position)
51
72
  options = {
52
73
  body: {
53
- content: body,
54
- line_to: position,
55
- filename: path
74
+ content: {
75
+ raw: body
76
+ },
77
+ inline: {
78
+ to: position,
79
+ path: path
80
+ }
81
+ }.to_json,
82
+ headers: {
83
+ 'Content-Type': 'application/json'
56
84
  }
57
85
  }
58
86
  self.class.post(url, options)
@@ -18,6 +18,18 @@ module Pronto
18
18
  consolidated
19
19
  end
20
20
 
21
+ def github_review_type
22
+ review_type =
23
+ ENV['PRONTO_GITHUB_REVIEW_TYPE'] ||
24
+ @config_hash.fetch('github_review_type', false)
25
+
26
+ if review_type == 'request_changes'
27
+ 'REQUEST_CHANGES'
28
+ else
29
+ 'COMMENT'
30
+ end
31
+ end
32
+
21
33
  def excluded_files(runner)
22
34
  files =
23
35
  if runner == 'all'
@@ -39,6 +51,10 @@ module Pronto
39
51
  URI.parse(bitbucket_web_endpoint).host
40
52
  end
41
53
 
54
+ def warnings_per_review
55
+ ENV['PRONTO_WARNINGS_PER_REVIEW'] && Integer(ENV['PRONTO_WARNINGS_PER_REVIEW']) || @config_hash['warnings_per_review']
56
+ end
57
+
42
58
  def max_warnings
43
59
  ENV['PRONTO_MAX_WARNINGS'] && Integer(ENV['PRONTO_MAX_WARNINGS']) || @config_hash['max_warnings']
44
60
  end
@@ -1,6 +1,7 @@
1
1
  module Pronto
2
2
  class ConfigFile
3
3
  DEFAULT_MESSAGE_FORMAT = '%{msg}'.freeze
4
+ DEFAULT_WARNINGS_PER_REVIEW = 30
4
5
 
5
6
  EMPTY = {
6
7
  'all' => {
@@ -11,7 +12,8 @@ module Pronto
11
12
  'slug' => nil,
12
13
  'access_token' => nil,
13
14
  'api_endpoint' => 'https://api.github.com/',
14
- 'web_endpoint' => 'https://github.com/'
15
+ 'web_endpoint' => 'https://github.com/',
16
+ 'review_type' => 'request_changes'
15
17
  },
16
18
  'gitlab' => {
17
19
  'slug' => nil,
@@ -32,6 +34,7 @@ module Pronto
32
34
  'runners' => [],
33
35
  'formatters' => [],
34
36
  'max_warnings' => nil,
37
+ 'warnings_per_review' => DEFAULT_WARNINGS_PER_REVIEW,
35
38
  'verbose' => false,
36
39
  'format' => DEFAULT_MESSAGE_FORMAT
37
40
  }.freeze
@@ -7,7 +7,7 @@ module Pronto
7
7
  @output = ''
8
8
  end
9
9
 
10
- def format(messages, _, _)
10
+ def format(messages, _repo, _patches)
11
11
  open_xml
12
12
  process_messages(messages)
13
13
  close_xml
@@ -13,9 +13,11 @@ module Pronto
13
13
  FORMATTERS = {
14
14
  'github' => GithubFormatter,
15
15
  'github_status' => GithubStatusFormatter,
16
+ 'github_combined_status' => GithubCombinedStatusFormatter,
16
17
  'github_pr' => GithubPullRequestFormatter,
17
18
  'github_pr_review' => GithubPullRequestReviewFormatter,
18
19
  'gitlab' => GitlabFormatter,
20
+ 'gitlab_mr' => GitlabMergeRequestReviewFormatter,
19
21
  'bitbucket' => BitbucketFormatter,
20
22
  'bitbucket_pr' => BitbucketPullRequestFormatter,
21
23
  'bitbucket_server_pr' => BitbucketServerPullRequestFormatter,
@@ -0,0 +1,24 @@
1
+ require_relative 'github_status_formatter/status_builder'
2
+
3
+ module Pronto
4
+ module Formatter
5
+ class GithubCombinedStatusFormatter
6
+ def format(messages, repo, _)
7
+ client = Github.new(repo)
8
+ head = repo.head_commit_sha
9
+
10
+ create_status(client, head, messages.uniq || [])
11
+ end
12
+
13
+ private
14
+
15
+ def create_status(client, sha, messages)
16
+ builder = GithubStatusFormatter::StatusBuilder.new(nil, messages)
17
+ status = Status.new(sha, builder.state,
18
+ 'pronto', builder.description)
19
+
20
+ client.create_commit_status(status)
21
+ end
22
+ end
23
+ end
24
+ end
@@ -10,7 +10,7 @@ module Pronto
10
10
  end
11
11
 
12
12
  def submit_comments(client, comments)
13
- client.create_pull_request_review(comments)
13
+ client.publish_pull_request_comments(comments)
14
14
  rescue Octokit::UnprocessableEntity, HTTParty::Error => e
15
15
  $stderr.puts "Failed to post: #{e.message}"
16
16
  end
@@ -0,0 +1,29 @@
1
+ module Pronto
2
+ module Formatter
3
+ class GitlabMergeRequestReviewFormatter < PullRequestFormatter
4
+ def client_module
5
+ Gitlab
6
+ end
7
+
8
+ def pretty_name
9
+ 'Gitlab'
10
+ end
11
+
12
+ def existing_comments(_, client, repo)
13
+ sha = repo.head_commit_sha
14
+ comments = client.pull_comments(sha)
15
+ grouped_comments(comments)
16
+ end
17
+
18
+ def submit_comments(client, comments)
19
+ client.create_pull_request_review(comments)
20
+ rescue => e
21
+ $stderr.puts "Failed to post: #{e.message}"
22
+ end
23
+
24
+ def line_number(message, _)
25
+ message.line.line.new_lineno if message.line
26
+ end
27
+ end
28
+ end
29
+ end
@@ -3,7 +3,7 @@ require 'json'
3
3
  module Pronto
4
4
  module Formatter
5
5
  class JsonFormatter < Base
6
- def format(messages, _, _)
6
+ def format(messages, _repo, _patches)
7
7
  messages.map do |message|
8
8
  lineno = message.line.new_lineno if message.line
9
9
 
@@ -1,7 +1,7 @@
1
1
  module Pronto
2
2
  module Formatter
3
3
  class NullFormatter < Base
4
- def format(_, _, _); end
4
+ def format(_messages, _repo, _patches); end
5
5
  end
6
6
  end
7
7
  end
@@ -3,7 +3,7 @@ require 'pronto/formatter/text_message_decorator'
3
3
  module Pronto
4
4
  module Formatter
5
5
  class TextFormatter < Base
6
- def format(messages, _, _)
6
+ def format(messages, _repo, _patches)
7
7
  messages.map do |message|
8
8
  message_format = config.message_format(self.class.name)
9
9
  message_data = TextMessageDecorator.new(message).to_h
@@ -37,8 +37,6 @@ module Pronto
37
37
  repo.path.join(new_file_path)
38
38
  end
39
39
 
40
- private
41
-
42
40
  def new_file_path
43
41
  delta.new_file[:path]
44
42
  end
@@ -38,7 +38,7 @@ module Pronto
38
38
 
39
39
  def commits_until(sha)
40
40
  result = []
41
- @repo.walk(head, Rugged::SORT_TOPO).take_while do |commit|
41
+ @repo.walk(head_commit_sha, Rugged::SORT_TOPO).take_while do |commit|
42
42
  result << commit.oid
43
43
  !commit.oid.start_with?(sha)
44
44
  end
@@ -46,7 +46,7 @@ module Pronto
46
46
  end
47
47
 
48
48
  def path
49
- Pathname.new(@repo.path).parent
49
+ Pathname.new(@repo.workdir).cleanpath
50
50
  end
51
51
 
52
52
  def blame(path, lineno)
@@ -45,17 +45,12 @@ module Pronto
45
45
  end
46
46
  end
47
47
 
48
- def create_pull_request_review(comments)
49
- return if comments.empty?
50
-
51
- options = {
52
- event: 'COMMENT',
53
- accept: 'application/vnd.github.v3.diff+json', # https://developer.github.com/v3/pulls/reviews/#create-a-pull-request-review
54
- comments: comments.map do |c|
55
- { path: c.path, position: c.position, body: c.body }
56
- end
57
- }
58
- client.create_pull_request_review(slug, pull_id, options)
48
+ def publish_pull_request_comments(comments)
49
+ comments_left = comments.clone
50
+ while comments_left.any?
51
+ comments_to_publish = comments_left.slice!(0, warnings_per_review)
52
+ create_pull_request_review(comments_to_publish)
53
+ end
59
54
  end
60
55
 
61
56
  def create_commit_status(status)
@@ -68,6 +63,21 @@ module Pronto
68
63
 
69
64
  private
70
65
 
66
+ def create_pull_request_review(comments)
67
+ options = {
68
+ event: @config.github_review_type,
69
+ accept: 'application/vnd.github.v3.diff+json', # https://developer.github.com/v3/pulls/reviews/#create-a-pull-request-review
70
+ comments: comments.map do |comment|
71
+ {
72
+ path: comment.path,
73
+ position: comment.position,
74
+ body: comment.body
75
+ }
76
+ end
77
+ }
78
+ client.create_pull_request_review(slug, pull_id, options)
79
+ end
80
+
71
81
  def slug
72
82
  return @config.github_slug if @config.github_slug
73
83
  @slug ||= begin
@@ -103,5 +113,9 @@ module Pronto
103
113
  @github_pull.pull_by_commit(@repo.head_commit_sha)
104
114
  end
105
115
  end
116
+
117
+ def warnings_per_review
118
+ @warnings_per_review ||= @config.warnings_per_review
119
+ end
106
120
  end
107
121
  end
@@ -2,12 +2,49 @@ module Pronto
2
2
  class Gitlab < Client
3
3
  def commit_comments(sha)
4
4
  @comment_cache[sha.to_s] ||= begin
5
- client.commit_comments(slug, sha, per_page: 500).map do |comment|
5
+ client.commit_comments(slug, sha).auto_paginate.map do |comment|
6
6
  Comment.new(sha, comment.note, comment.path, comment.line)
7
7
  end
8
8
  end
9
9
  end
10
10
 
11
+ def pull_comments(sha)
12
+ @comment_cache["#{slug}/#{pull_id}"] ||= begin
13
+ arr = []
14
+ client.merge_request_discussions(slug, pull_id).auto_paginate.each do |comment|
15
+ comment.notes.each do |note|
16
+ next unless note['position']
17
+
18
+ arr << Comment.new(
19
+ sha,
20
+ note['body'],
21
+ note['position']['new_path'],
22
+ note['position']['new_line']
23
+ )
24
+ end
25
+ end
26
+ arr
27
+ end
28
+ end
29
+
30
+ def create_pull_request_review(comments)
31
+ return if comments.empty?
32
+
33
+ comments.each do |comment|
34
+ options = {
35
+ body: comment.body,
36
+ position: position_sha.dup.merge(
37
+ new_path: comment.path,
38
+ position_type: 'text',
39
+ new_line: comment.position,
40
+ old_line: nil,
41
+ )
42
+ }
43
+
44
+ client.create_merge_request_discussion(slug, pull_id, options)
45
+ end
46
+ end
47
+
11
48
  def create_commit_comment(comment)
12
49
  @config.logger.log("Creating commit comment on #{comment.sha}")
13
50
  client.create_commit_comment(slug, comment.sha, comment.body,
@@ -17,6 +54,15 @@ module Pronto
17
54
 
18
55
  private
19
56
 
57
+ def position_sha
58
+ # Better to get those informations from Gitlab API directly than trying to look for them here.
59
+ # (FYI you can't use `pull` method because index api does not contains those informations)
60
+ @position_sha ||= begin
61
+ data = client.merge_request(slug, pull_id)
62
+ data.diff_refs.to_h
63
+ end
64
+ end
65
+
20
66
  def slug
21
67
  return @config.gitlab_slug if @config.gitlab_slug
22
68
  @slug ||= begin
@@ -27,6 +73,17 @@ module Pronto
27
73
  end
28
74
  end
29
75
 
76
+ def pull_id
77
+ env_pull_id || raise(Pronto::Error, "Unable to determine merge request id. Specify either `PRONTO_PULL_REQUEST_ID` or `CI_MERGE_REQUEST_IID`.")
78
+ end
79
+
80
+ def env_pull_id
81
+ pull_request = super
82
+
83
+ pull_request ||= ENV['CI_MERGE_REQUEST_IID']
84
+ pull_request.to_i if pull_request
85
+ end
86
+
30
87
  def slug_regex(url)
31
88
  if url =~ %r{^ssh:\/\/}
32
89
  %r{.*#{host}(:[0-9]+)?(:|\/)(?<slug>.*).git}
@@ -28,7 +28,10 @@ module Pronto
28
28
  end
29
29
 
30
30
  def ruby_file?(path)
31
- rb_file?(path) || rake_file?(path) || ruby_executable?(path)
31
+ rb_file?(path) ||
32
+ rake_file?(path) ||
33
+ gem_file?(path) ||
34
+ ruby_executable?(path)
32
35
  end
33
36
 
34
37
  def repo_path
@@ -45,6 +48,10 @@ module Pronto
45
48
  File.extname(path) == '.rake'
46
49
  end
47
50
 
51
+ def gem_file?(path)
52
+ File.basename(path) == 'Gemfile' || File.extname(path) == '.gemspec'
53
+ end
54
+
48
55
  def ruby_executable?(path)
49
56
  return false if File.directory?(path)
50
57
  line = File.open(path, &:readline)
@@ -1,6 +1,6 @@
1
1
  module Pronto
2
2
  module Version
3
- STRING = '0.10.0'.freeze
3
+ STRING = '0.11.0'.freeze
4
4
 
5
5
  MSG = '%s (running on %s %s %s)'.freeze
6
6
 
@@ -40,14 +40,15 @@ Gem::Specification.new do |s|
40
40
  s.require_paths = ['lib']
41
41
  s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
42
42
 
43
- s.add_runtime_dependency('gitlab', '~> 4.0', '>= 4.0.0')
43
+ s.add_runtime_dependency('gitlab', '~> 4.4', '>= 4.4.0')
44
44
  s.add_runtime_dependency('httparty', '>= 0.13.7')
45
45
  s.add_runtime_dependency('octokit', '~> 4.7', '>= 4.7.0')
46
46
  s.add_runtime_dependency('rainbow', '>= 2.2', '< 4.0')
47
- s.add_runtime_dependency('rugged', '~> 0.24', '>= 0.23.0')
48
- s.add_runtime_dependency('thor', '~> 0.20.0')
47
+ s.add_runtime_dependency('rexml', '~> 3.2')
48
+ s.add_runtime_dependency('rugged', '>= 0.23.0', '< 1.1.0')
49
+ s.add_runtime_dependency('thor', '>= 0.20.3', '< 2.0')
49
50
  s.add_development_dependency('bundler', '>= 1.15')
50
- s.add_development_dependency('pronto-rubocop', '~> 0.9.0')
51
+ s.add_development_dependency('pronto-rubocop', '~> 0.10.0')
51
52
  s.add_development_dependency('rake', '~> 12.0')
52
53
  s.add_development_dependency('rspec', '~> 3.4')
53
54
  s.add_development_dependency('rspec-its', '~> 1.2')
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pronto
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.0
4
+ version: 0.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mindaugas Mozūras
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-02-03 00:00:00.000000000 Z
11
+ date: 2021-01-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: gitlab
@@ -16,20 +16,20 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 4.0.0
19
+ version: 4.4.0
20
20
  - - "~>"
21
21
  - !ruby/object:Gem::Version
22
- version: '4.0'
22
+ version: '4.4'
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
26
26
  requirements:
27
27
  - - ">="
28
28
  - !ruby/object:Gem::Version
29
- version: 4.0.0
29
+ version: 4.4.0
30
30
  - - "~>"
31
31
  - !ruby/object:Gem::Version
32
- version: '4.0'
32
+ version: '4.4'
33
33
  - !ruby/object:Gem::Dependency
34
34
  name: httparty
35
35
  requirement: !ruby/object:Gem::Requirement
@@ -84,6 +84,20 @@ dependencies:
84
84
  - - "<"
85
85
  - !ruby/object:Gem::Version
86
86
  version: '4.0'
87
+ - !ruby/object:Gem::Dependency
88
+ name: rexml
89
+ requirement: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - "~>"
92
+ - !ruby/object:Gem::Version
93
+ version: '3.2'
94
+ type: :runtime
95
+ prerelease: false
96
+ version_requirements: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - "~>"
99
+ - !ruby/object:Gem::Version
100
+ version: '3.2'
87
101
  - !ruby/object:Gem::Dependency
88
102
  name: rugged
89
103
  requirement: !ruby/object:Gem::Requirement
@@ -91,9 +105,9 @@ dependencies:
91
105
  - - ">="
92
106
  - !ruby/object:Gem::Version
93
107
  version: 0.23.0
94
- - - "~>"
108
+ - - "<"
95
109
  - !ruby/object:Gem::Version
96
- version: '0.24'
110
+ version: 1.1.0
97
111
  type: :runtime
98
112
  prerelease: false
99
113
  version_requirements: !ruby/object:Gem::Requirement
@@ -101,23 +115,29 @@ dependencies:
101
115
  - - ">="
102
116
  - !ruby/object:Gem::Version
103
117
  version: 0.23.0
104
- - - "~>"
118
+ - - "<"
105
119
  - !ruby/object:Gem::Version
106
- version: '0.24'
120
+ version: 1.1.0
107
121
  - !ruby/object:Gem::Dependency
108
122
  name: thor
109
123
  requirement: !ruby/object:Gem::Requirement
110
124
  requirements:
111
- - - "~>"
125
+ - - ">="
112
126
  - !ruby/object:Gem::Version
113
- version: 0.20.0
127
+ version: 0.20.3
128
+ - - "<"
129
+ - !ruby/object:Gem::Version
130
+ version: '2.0'
114
131
  type: :runtime
115
132
  prerelease: false
116
133
  version_requirements: !ruby/object:Gem::Requirement
117
134
  requirements:
118
- - - "~>"
135
+ - - ">="
136
+ - !ruby/object:Gem::Version
137
+ version: 0.20.3
138
+ - - "<"
119
139
  - !ruby/object:Gem::Version
120
- version: 0.20.0
140
+ version: '2.0'
121
141
  - !ruby/object:Gem::Dependency
122
142
  name: bundler
123
143
  requirement: !ruby/object:Gem::Requirement
@@ -138,14 +158,14 @@ dependencies:
138
158
  requirements:
139
159
  - - "~>"
140
160
  - !ruby/object:Gem::Version
141
- version: 0.9.0
161
+ version: 0.10.0
142
162
  type: :development
143
163
  prerelease: false
144
164
  version_requirements: !ruby/object:Gem::Requirement
145
165
  requirements:
146
166
  - - "~>"
147
167
  - !ruby/object:Gem::Version
148
- version: 0.9.0
168
+ version: 0.10.0
149
169
  - !ruby/object:Gem::Dependency
150
170
  name: rake
151
171
  requirement: !ruby/object:Gem::Requirement
@@ -243,6 +263,7 @@ extra_rdoc_files:
243
263
  - LICENSE
244
264
  - README.md
245
265
  files:
266
+ - ".github/CODEOWNERS"
246
267
  - CHANGELOG.md
247
268
  - CONTRIBUTING.md
248
269
  - LICENSE
@@ -268,6 +289,7 @@ files:
268
289
  - lib/pronto/formatter/commit_formatter.rb
269
290
  - lib/pronto/formatter/formatter.rb
270
291
  - lib/pronto/formatter/git_formatter.rb
292
+ - lib/pronto/formatter/github_combined_status_formatter.rb
271
293
  - lib/pronto/formatter/github_formatter.rb
272
294
  - lib/pronto/formatter/github_pull_request_formatter.rb
273
295
  - lib/pronto/formatter/github_pull_request_review_formatter.rb
@@ -275,6 +297,7 @@ files:
275
297
  - lib/pronto/formatter/github_status_formatter/sentence.rb
276
298
  - lib/pronto/formatter/github_status_formatter/status_builder.rb
277
299
  - lib/pronto/formatter/gitlab_formatter.rb
300
+ - lib/pronto/formatter/gitlab_merge_request_review_formatter.rb
278
301
  - lib/pronto/formatter/json_formatter.rb
279
302
  - lib/pronto/formatter/null_formatter.rb
280
303
  - lib/pronto/formatter/pull_request_formatter.rb
@@ -316,7 +339,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
316
339
  - !ruby/object:Gem::Version
317
340
  version: '0'
318
341
  requirements: []
319
- rubygems_version: 3.0.1
342
+ rubygems_version: 3.0.3
320
343
  signing_key:
321
344
  specification_version: 4
322
345
  summary: Pronto runs analysis by checking only the introduced changes