danger 8.4.5 → 9.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE +1 -1
- data/bin/danger +1 -1
- data/lib/danger/ci_source/appcircle.rb +83 -0
- data/lib/danger/ci_source/appveyor.rb +1 -0
- data/lib/danger/ci_source/azure_pipelines.rb +20 -5
- data/lib/danger/ci_source/bamboo.rb +1 -1
- data/lib/danger/ci_source/bitbucket_pipelines.rb +1 -2
- data/lib/danger/ci_source/bitrise.rb +10 -10
- data/lib/danger/ci_source/buildkite.rb +1 -1
- data/lib/danger/ci_source/circle.rb +1 -1
- data/lib/danger/ci_source/circle_api.rb +2 -2
- data/lib/danger/ci_source/code_build.rb +20 -6
- data/lib/danger/ci_source/codefresh.rb +1 -1
- data/lib/danger/ci_source/concourse.rb +4 -5
- data/lib/danger/ci_source/custom_ci_with_github.rb +45 -0
- data/lib/danger/ci_source/dotci.rb +4 -6
- data/lib/danger/ci_source/github_actions.rb +6 -6
- data/lib/danger/ci_source/gitlab_ci.rb +4 -4
- data/lib/danger/ci_source/jenkins.rb +22 -23
- data/lib/danger/ci_source/local_git_repo.rb +7 -1
- data/lib/danger/ci_source/local_only_git_repo.rb +1 -0
- data/lib/danger/ci_source/support/find_repo_info_from_url.rb +11 -10
- data/lib/danger/ci_source/support/pull_request_finder.rb +15 -7
- data/lib/danger/ci_source/teamcity.rb +1 -1
- data/lib/danger/ci_source/xcode_cloud.rb +7 -7
- data/lib/danger/commands/init.rb +1 -1
- data/lib/danger/commands/local.rb +3 -3
- data/lib/danger/commands/local_helpers/http_cache.rb +2 -0
- data/lib/danger/commands/local_helpers/local_setup.rb +2 -0
- data/lib/danger/commands/local_helpers/pry_setup.rb +1 -0
- data/lib/danger/commands/plugins/plugin_json.rb +1 -3
- data/lib/danger/commands/plugins/plugin_lint.rb +0 -2
- data/lib/danger/commands/plugins/plugin_readme.rb +2 -5
- data/lib/danger/commands/pr.rb +2 -1
- data/lib/danger/commands/runner.rb +1 -1
- data/lib/danger/commands/staging.rb +7 -7
- data/lib/danger/commands/systems.rb +4 -6
- data/lib/danger/comment_generators/gitlab_inline.md.erb +1 -1
- data/lib/danger/comment_generators/vsts_inline.md.erb +17 -0
- data/lib/danger/core_ext/file_list.rb +2 -2
- data/lib/danger/danger_core/dangerfile.rb +16 -16
- data/lib/danger/danger_core/environment_manager.rb +2 -1
- data/lib/danger/danger_core/executor.rb +10 -11
- data/lib/danger/danger_core/message_aggregator.rb +1 -0
- data/lib/danger/danger_core/messages/base.rb +1 -0
- data/lib/danger/danger_core/messages/markdown.rb +3 -4
- data/lib/danger/danger_core/messages/violation.rb +1 -2
- data/lib/danger/danger_core/plugins/dangerfile_bitbucket_cloud_plugin.rb +1 -3
- data/lib/danger/danger_core/plugins/dangerfile_bitbucket_server_plugin.rb +4 -4
- data/lib/danger/danger_core/plugins/dangerfile_danger_plugin.rb +9 -3
- data/lib/danger/danger_core/plugins/dangerfile_git_plugin.rb +4 -3
- data/lib/danger/danger_core/plugins/dangerfile_github_plugin.rb +2 -0
- data/lib/danger/danger_core/plugins/dangerfile_gitlab_plugin.rb +3 -1
- data/lib/danger/danger_core/plugins/dangerfile_local_only_plugin.rb +4 -3
- data/lib/danger/danger_core/plugins/dangerfile_messaging_plugin.rb +3 -1
- data/lib/danger/danger_core/plugins/dangerfile_vsts_plugin.rb +3 -3
- data/lib/danger/danger_core/standard_error.rb +2 -3
- data/lib/danger/helpers/comments_helper.rb +8 -7
- data/lib/danger/helpers/comments_parsing_helper.rb +3 -2
- data/lib/danger/helpers/emoji_mapper.rb +1 -1
- data/lib/danger/plugin_support/plugin.rb +0 -1
- data/lib/danger/plugin_support/plugin_linter.rb +1 -0
- data/lib/danger/request_sources/bitbucket_cloud.rb +17 -14
- data/lib/danger/request_sources/bitbucket_cloud_api.rb +2 -4
- data/lib/danger/request_sources/bitbucket_server.rb +47 -10
- data/lib/danger/request_sources/bitbucket_server_api.rb +14 -10
- data/lib/danger/request_sources/code_insights_api.rb +7 -11
- data/lib/danger/request_sources/github/github.rb +15 -14
- data/lib/danger/request_sources/github/github_review.rb +3 -2
- data/lib/danger/request_sources/github/github_review_resolver.rb +0 -2
- data/lib/danger/request_sources/github/github_review_unsupported.rb +0 -2
- data/lib/danger/request_sources/gitlab.rb +46 -58
- data/lib/danger/request_sources/local_only.rb +0 -2
- data/lib/danger/request_sources/request_source.rb +4 -4
- data/lib/danger/request_sources/support/get_ignored_violation.rb +1 -1
- data/lib/danger/request_sources/vsts.rb +175 -14
- data/lib/danger/request_sources/vsts_api.rb +39 -4
- data/lib/danger/scm_source/git_repo.rb +2 -1
- data/lib/danger/version.rb +1 -1
- data/lib/danger.rb +1 -0
- metadata +42 -40
- data/lib/danger/ci_source/vsts.rb +0 -73
@@ -1,5 +1,3 @@
|
|
1
|
-
# coding: utf-8
|
2
|
-
|
3
1
|
# rubocop:disable Metrics/ClassLength
|
4
2
|
|
5
3
|
require "octokit"
|
@@ -65,6 +63,7 @@ module Danger
|
|
65
63
|
|
66
64
|
def client
|
67
65
|
raise "No API token given, please provide one using `DANGER_GITHUB_API_TOKEN` or `DANGER_GITHUB_BEARER_TOKEN`" if !valid_access_token? && !valid_bearer_token? && !support_tokenless_auth
|
66
|
+
|
68
67
|
@client ||= begin
|
69
68
|
Octokit.configure do |config|
|
70
69
|
config.connection_options[:ssl] = { verify: verify_ssl }
|
@@ -83,6 +82,7 @@ module Danger
|
|
83
82
|
|
84
83
|
def review
|
85
84
|
return @review unless @review.nil?
|
85
|
+
|
86
86
|
begin
|
87
87
|
@review = client.pull_request_reviews(ci_source.repo_slug, ci_source.pull_request_id)
|
88
88
|
.map { |review_json| Danger::RequestSources::GitHubSource::Review.new(client, ci_source, review_json) }
|
@@ -133,10 +133,8 @@ module Danger
|
|
133
133
|
end
|
134
134
|
|
135
135
|
def issue_comments
|
136
|
-
@comments ||=
|
137
|
-
|
138
|
-
.map { |comment| Comment.from_github(comment) }
|
139
|
-
end
|
136
|
+
@comments ||= client.issue_comments(ci_source.repo_slug, ci_source.pull_request_id)
|
137
|
+
.map { |comment| Comment.from_github(comment) }
|
140
138
|
end
|
141
139
|
|
142
140
|
# Sending data to GitHub
|
@@ -224,7 +222,7 @@ module Danger
|
|
224
222
|
context: "danger/#{danger_id}",
|
225
223
|
target_url: details_url
|
226
224
|
})
|
227
|
-
rescue
|
225
|
+
rescue StandardError
|
228
226
|
# This usually means the user has no commit access to this repo
|
229
227
|
# That's always the case for open source projects where you can only
|
230
228
|
# use a read-only GitHub account
|
@@ -248,6 +246,7 @@ module Danger
|
|
248
246
|
issue_comments.each do |comment|
|
249
247
|
next unless comment.generated_by_danger?(danger_id)
|
250
248
|
next if comment.id == except
|
249
|
+
|
251
250
|
client.delete_comment(ci_source.repo_slug, comment.id)
|
252
251
|
end
|
253
252
|
end
|
@@ -456,9 +455,9 @@ module Danger
|
|
456
455
|
|
457
456
|
# @return [String] The organisation name, is nil if it can't be detected
|
458
457
|
def organisation
|
459
|
-
matched = self.issue_json["repository_url"].match(%r{repos
|
458
|
+
matched = self.issue_json["repository_url"].match(%r{repos/(.*)/})
|
460
459
|
return matched[1] if matched && matched[1]
|
461
|
-
rescue
|
460
|
+
rescue StandardError
|
462
461
|
nil
|
463
462
|
end
|
464
463
|
|
@@ -473,17 +472,18 @@ module Danger
|
|
473
472
|
end
|
474
473
|
|
475
474
|
# @return [String] A URL to the specific file, ready to be downloaded
|
476
|
-
def file_url(organisation: nil, repository: nil, branch: nil, path: nil)
|
475
|
+
def file_url(organisation: nil, repository: nil, ref: nil, branch: nil, path: nil)
|
477
476
|
organisation ||= self.organisation
|
477
|
+
ref ||= branch
|
478
478
|
|
479
479
|
begin
|
480
|
-
# Retrieve the download URL (default
|
481
|
-
contents = client.contents("#{organisation}/#{repository}", path: path, ref:
|
480
|
+
# Retrieve the download URL (default ref on nil param)
|
481
|
+
contents = client.contents("#{organisation}/#{repository}", path: path, ref: ref)
|
482
482
|
@download_url = contents["download_url"]
|
483
483
|
rescue Octokit::ClientError
|
484
484
|
# Fallback to github.com
|
485
|
-
|
486
|
-
@download_url = "https://raw.githubusercontent.com/#{organisation}/#{repository}/#{
|
485
|
+
ref ||= "master"
|
486
|
+
@download_url = "https://raw.githubusercontent.com/#{organisation}/#{repository}/#{ref}/#{path}"
|
487
487
|
end
|
488
488
|
end
|
489
489
|
|
@@ -512,6 +512,7 @@ module Danger
|
|
512
512
|
next 1 unless b.file && b.line
|
513
513
|
|
514
514
|
next a.line <=> b.line if a.file == b.file
|
515
|
+
|
515
516
|
next a.file <=> b.file
|
516
517
|
end
|
517
518
|
|
@@ -1,5 +1,3 @@
|
|
1
|
-
# coding: utf-8
|
2
|
-
|
3
1
|
require "octokit"
|
4
2
|
require "danger/ci_source/ci_source"
|
5
3
|
require "danger/request_sources/github/github_review_resolver"
|
@@ -35,16 +33,19 @@ module Danger
|
|
35
33
|
|
36
34
|
def id
|
37
35
|
return nil unless self.review_json
|
36
|
+
|
38
37
|
self.review_json["id"]
|
39
38
|
end
|
40
39
|
|
41
40
|
def body
|
42
41
|
return "" unless self.review_json
|
42
|
+
|
43
43
|
self.review_json["body"]
|
44
44
|
end
|
45
45
|
|
46
46
|
def status
|
47
47
|
return STATUS_PENDING if self.review_json.nil?
|
48
|
+
|
48
49
|
return self.review_json["state"]
|
49
50
|
end
|
50
51
|
|
@@ -1,4 +1,3 @@
|
|
1
|
-
# coding: utf-8
|
2
1
|
require "uri"
|
3
2
|
require "danger/helpers/comments_helper"
|
4
3
|
require "danger/helpers/comment"
|
@@ -72,20 +71,18 @@ module Danger
|
|
72
71
|
def mr_comments
|
73
72
|
# @raw_comments contains what we got back from the server.
|
74
73
|
# @comments contains Comment objects (that have less information)
|
75
|
-
@comments ||=
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
end
|
88
|
-
end
|
74
|
+
@comments ||= if supports_inline_comments
|
75
|
+
@raw_comments = mr_discussions
|
76
|
+
.auto_paginate
|
77
|
+
.flat_map { |discussion| discussion.notes.map { |note| note.to_h.merge({ "discussion_id" => discussion.id }) } }
|
78
|
+
@raw_comments
|
79
|
+
.map { |comment| Comment.from_gitlab(comment) }
|
80
|
+
else
|
81
|
+
@raw_comments = client.merge_request_comments(ci_source.repo_slug, ci_source.pull_request_id, per_page: 100)
|
82
|
+
.auto_paginate
|
83
|
+
@raw_comments
|
84
|
+
.map { |comment| Comment.from_gitlab(comment) }
|
85
|
+
end
|
89
86
|
end
|
90
87
|
|
91
88
|
def mr_discussions
|
@@ -96,10 +93,10 @@ module Danger
|
|
96
93
|
@mr_diff ||= begin
|
97
94
|
diffs = mr_changes.changes.map do |change|
|
98
95
|
diff = change["diff"]
|
99
|
-
if diff.start_with?(
|
96
|
+
if diff.start_with?("--- a/")
|
100
97
|
diff
|
101
98
|
else
|
102
|
-
"--- a/#{change[
|
99
|
+
"--- a/#{change['old_path']}\n+++ b/#{change['new_path']}\n#{diff}"
|
103
100
|
end
|
104
101
|
end
|
105
102
|
diffs.join("\n")
|
@@ -107,24 +104,18 @@ module Danger
|
|
107
104
|
end
|
108
105
|
|
109
106
|
def mr_changed_paths
|
110
|
-
@mr_changed_paths ||=
|
111
|
-
|
112
|
-
.changes.map { |change| change["new_path"] }
|
113
|
-
end
|
107
|
+
@mr_changed_paths ||= mr_changes
|
108
|
+
.changes.map { |change| change["new_path"] }
|
114
109
|
|
115
110
|
@mr_changed_paths
|
116
111
|
end
|
117
112
|
|
118
113
|
def mr_changes
|
119
|
-
@mr_changes ||=
|
120
|
-
client.merge_request_changes(ci_source.repo_slug, ci_source.pull_request_id)
|
121
|
-
end
|
114
|
+
@mr_changes ||= client.merge_request_changes(ci_source.repo_slug, ci_source.pull_request_id)
|
122
115
|
end
|
123
116
|
|
124
117
|
def mr_closes_issues
|
125
|
-
@mr_closes_issues ||=
|
126
|
-
client.merge_request_closes_issues(ci_source.repo_slug, ci_source.pull_request_id)
|
127
|
-
end
|
118
|
+
@mr_closes_issues ||= client.merge_request_closes_issues(ci_source.repo_slug, ci_source.pull_request_id)
|
128
119
|
end
|
129
120
|
|
130
121
|
def setup_danger_branches
|
@@ -154,16 +145,14 @@ module Danger
|
|
154
145
|
end
|
155
146
|
|
156
147
|
def supports_inline_comments
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
current_version = Gem::Version.new(client.version.version)
|
148
|
+
# If we can't check GitLab's version, we assume we don't support inline comments
|
149
|
+
@supports_inline_comments ||= if Gem.loaded_specs["gitlab"].version < FIRST_GITLAB_GEM_WITH_VERSION_CHECK
|
150
|
+
false
|
151
|
+
else
|
152
|
+
current_version = Gem::Version.new(client.version.version)
|
163
153
|
|
164
|
-
|
165
|
-
|
166
|
-
end
|
154
|
+
current_version >= FIRST_VERSION_WITH_INLINE_COMMENTS
|
155
|
+
end
|
167
156
|
end
|
168
157
|
|
169
158
|
def update_pull_request!(warnings: [], errors: [], messages: [], markdowns: [], danger_id: "danger", new_comment: false, remove_previous_comments: false)
|
@@ -253,11 +242,11 @@ module Danger
|
|
253
242
|
delete_old_comments!(danger_id: danger_id)
|
254
243
|
else
|
255
244
|
body = generate_comment(warnings: warnings,
|
256
|
-
|
245
|
+
errors: errors,
|
257
246
|
messages: messages,
|
258
|
-
|
259
|
-
|
260
|
-
|
247
|
+
markdowns: markdowns,
|
248
|
+
previous_violations: previous_violations,
|
249
|
+
danger_id: danger_id,
|
261
250
|
template: "gitlab")
|
262
251
|
|
263
252
|
if editable_comments.empty? or should_create_new_comment
|
@@ -278,11 +267,10 @@ module Danger
|
|
278
267
|
|
279
268
|
def delete_old_comments!(except: nil, danger_id: "danger")
|
280
269
|
@raw_comments.each do |raw_comment|
|
281
|
-
|
282
270
|
comment = Comment.from_gitlab(raw_comment)
|
283
271
|
next unless comment.generated_by_danger?(danger_id)
|
284
272
|
next if comment.id == except
|
285
|
-
next unless raw_comment.
|
273
|
+
next unless raw_comment.kind_of?(Hash) && raw_comment["position"].nil?
|
286
274
|
|
287
275
|
begin
|
288
276
|
client.delete_merge_request_comment(
|
@@ -290,7 +278,7 @@ module Danger
|
|
290
278
|
ci_source.pull_request_id,
|
291
279
|
comment.id
|
292
280
|
)
|
293
|
-
rescue
|
281
|
+
rescue StandardError
|
294
282
|
end
|
295
283
|
end
|
296
284
|
end
|
@@ -298,7 +286,7 @@ module Danger
|
|
298
286
|
def markdown_link_to_message(message, _)
|
299
287
|
"#{message.file}#L#{message.line}: "
|
300
288
|
end
|
301
|
-
|
289
|
+
|
302
290
|
# @return [String] The organisation name, is nil if it can't be detected
|
303
291
|
def organisation
|
304
292
|
nil # TODO: Implement this
|
@@ -315,12 +303,12 @@ module Danger
|
|
315
303
|
end
|
316
304
|
|
317
305
|
# @return [String] A URL to the specific file, ready to be downloaded
|
318
|
-
def file_url(organisation: nil, repository: nil, branch: nil, path: nil)
|
319
|
-
|
306
|
+
def file_url(organisation: nil, repository: nil, ref: nil, branch: nil, path: nil)
|
307
|
+
ref ||= (branch || "master")
|
320
308
|
# According to GitLab Repositories API docs path and id(slug) should be encoded.
|
321
309
|
path = URI.encode_www_form_component(path)
|
322
310
|
repository = URI.encode_www_form_component(repository)
|
323
|
-
"#{endpoint}/projects/#{repository}/repository/files/#{path}/raw?ref=#{
|
311
|
+
"#{endpoint}/projects/#{repository}/repository/files/#{path}/raw?ref=#{ref}&private_token=#{@token}"
|
324
312
|
end
|
325
313
|
|
326
314
|
def regular_violations_group(warnings: [], errors: [], messages: [], markdowns: [])
|
@@ -338,6 +326,7 @@ module Danger
|
|
338
326
|
next 1 unless b.file && b.line
|
339
327
|
|
340
328
|
next a.line <=> b.line if a.file == b.file
|
329
|
+
|
341
330
|
next a.file <=> b.file
|
342
331
|
end
|
343
332
|
|
@@ -359,7 +348,7 @@ module Danger
|
|
359
348
|
def submit_inline_comments!(warnings: [], errors: [], messages: [], markdowns: [], previous_violations: [], danger_id: "danger")
|
360
349
|
comments = mr_discussions
|
361
350
|
.auto_paginate
|
362
|
-
.flat_map { |discussion| discussion.notes.map { |note| note.to_h.merge({"discussion_id" => discussion.id}) } }
|
351
|
+
.flat_map { |discussion| discussion.notes.map { |note| note.to_h.merge({ "discussion_id" => discussion.id }) } }
|
363
352
|
.select { |comment| Comment.from_gitlab(comment).inline? }
|
364
353
|
|
365
354
|
danger_comments = comments.select { |comment| Comment.from_gitlab(comment).generated_by_danger?(danger_id) }
|
@@ -401,7 +390,7 @@ module Danger
|
|
401
390
|
}
|
402
391
|
end
|
403
392
|
|
404
|
-
def submit_inline_comments_for_kind!(kind, messages,
|
393
|
+
def submit_inline_comments_for_kind!(kind, messages, _diff_lines, danger_comments, previous_violations, danger_id: "danger")
|
405
394
|
previous_violations ||= []
|
406
395
|
is_markdown_content = kind == :markdown
|
407
396
|
emoji = { warning: "warning", error: "no_entry_sign", message: "book" }[kind]
|
@@ -440,7 +429,7 @@ module Danger
|
|
440
429
|
params = {
|
441
430
|
body: body,
|
442
431
|
position: {
|
443
|
-
position_type:
|
432
|
+
position_type: "text",
|
444
433
|
new_path: m.file,
|
445
434
|
new_line: m.line,
|
446
435
|
old_path: old_position[:path],
|
@@ -550,20 +539,19 @@ module Danger
|
|
550
539
|
line_number = 0
|
551
540
|
diff.each_line do |line|
|
552
541
|
if line.match range_header_regexp
|
553
|
-
line = line.split(
|
554
|
-
line = line.split(
|
555
|
-
range_string = line.split(
|
542
|
+
line = line.split("+").last
|
543
|
+
line = line.split(" ").first
|
544
|
+
range_string = line.split(",")
|
556
545
|
line_number = range_string[0].to_i - 1
|
557
|
-
elsif line.start_with?(
|
546
|
+
elsif line.start_with?("+")
|
558
547
|
addition_lines.push(line_number)
|
559
|
-
elsif line.start_with?(
|
560
|
-
line_number
|
548
|
+
elsif line.start_with?("-")
|
549
|
+
line_number -= 1
|
561
550
|
end
|
562
|
-
line_number
|
551
|
+
line_number += 1
|
563
552
|
end
|
564
553
|
addition_lines
|
565
554
|
end
|
566
|
-
|
567
555
|
end
|
568
556
|
end
|
569
557
|
end
|
@@ -85,12 +85,12 @@ module Danger
|
|
85
85
|
raise "Subclass and overwrite organisation"
|
86
86
|
end
|
87
87
|
|
88
|
-
def file_url(_organisation: nil, _repository: nil, _branch:
|
88
|
+
def file_url(_organisation: nil, _repository: nil, _ref: nil, _branch: nil, _path: nil)
|
89
89
|
raise "Subclass and overwrite file_url"
|
90
90
|
end
|
91
|
-
|
92
|
-
def update_build_status(
|
93
|
-
|
91
|
+
|
92
|
+
def update_build_status(_status)
|
93
|
+
raise "Subclass and overwrite update_build_status"
|
94
94
|
end
|
95
95
|
end
|
96
96
|
end
|
@@ -1,5 +1,3 @@
|
|
1
|
-
# coding: utf-8
|
2
|
-
|
3
1
|
require "danger/helpers/comments_helper"
|
4
2
|
require "danger/request_sources/vsts_api"
|
5
3
|
|
@@ -25,14 +23,13 @@ module Danger
|
|
25
23
|
def initialize(ci_source, environment)
|
26
24
|
self.ci_source = ci_source
|
27
25
|
|
28
|
-
@
|
26
|
+
@is_vsts_ci = environment.key? "DANGER_VSTS_HOST"
|
29
27
|
|
30
|
-
|
31
|
-
@api = VSTSAPI.new(project, slug, ci_source.pull_request_id, environment)
|
28
|
+
@api = VSTSAPI.new(ci_source.repo_slug, ci_source.pull_request_id, environment)
|
32
29
|
end
|
33
30
|
|
34
31
|
def validates_as_ci?
|
35
|
-
@
|
32
|
+
@is_vsts_ci
|
36
33
|
end
|
37
34
|
|
38
35
|
def validates_as_api_source?
|
@@ -43,6 +40,10 @@ module Danger
|
|
43
40
|
@scm ||= GitRepo.new
|
44
41
|
end
|
45
42
|
|
43
|
+
def client
|
44
|
+
@api
|
45
|
+
end
|
46
|
+
|
46
47
|
def host
|
47
48
|
@host ||= @api.host
|
48
49
|
end
|
@@ -76,15 +77,36 @@ module Danger
|
|
76
77
|
return
|
77
78
|
end
|
78
79
|
|
79
|
-
|
80
|
+
regular_violations = regular_violations_group(
|
81
|
+
warnings: warnings,
|
82
|
+
errors: errors,
|
83
|
+
messages: messages,
|
84
|
+
markdowns: markdowns
|
85
|
+
)
|
86
|
+
|
87
|
+
inline_violations = inline_violations_group(
|
88
|
+
warnings: warnings,
|
89
|
+
errors: errors,
|
90
|
+
messages: messages,
|
91
|
+
markdowns: markdowns
|
92
|
+
)
|
93
|
+
|
94
|
+
rest_inline_violations = submit_inline_comments!(**{
|
95
|
+
danger_id: danger_id,
|
96
|
+
previous_violations: {}
|
97
|
+
}.merge(inline_violations))
|
98
|
+
|
99
|
+
main_violations = merge_violations(
|
100
|
+
regular_violations, rest_inline_violations
|
101
|
+
)
|
102
|
+
|
103
|
+
comment = generate_description(warnings: main_violations[:warnings], errors: main_violations[:errors])
|
80
104
|
comment += "\n\n"
|
81
|
-
comment += generate_comment(
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
danger_id: danger_id,
|
87
|
-
template: "vsts")
|
105
|
+
comment += generate_comment(**{
|
106
|
+
previous_violations: {},
|
107
|
+
danger_id: danger_id,
|
108
|
+
template: "vsts"
|
109
|
+
}.merge(main_violations))
|
88
110
|
if new_comment || remove_previous_comments
|
89
111
|
post_new_comment(comment)
|
90
112
|
else
|
@@ -105,6 +127,9 @@ module Danger
|
|
105
127
|
comment_content = comment[:content].nil? ? "" : comment[:content]
|
106
128
|
# Skip the comment if it wasn't posted by danger
|
107
129
|
next unless comment_content.include?("generated_by_#{danger_id}")
|
130
|
+
# Skip the comment if it's an inline comment
|
131
|
+
next unless c[:threadContext].nil?
|
132
|
+
|
108
133
|
# Updated the danger posted comment
|
109
134
|
@api.update_comment(thread_id, comment_id, new_comment)
|
110
135
|
comment_updated = true
|
@@ -112,6 +137,142 @@ module Danger
|
|
112
137
|
# If no comment was updated, post a new one
|
113
138
|
post_new_comment(new_comment) unless comment_updated
|
114
139
|
end
|
140
|
+
|
141
|
+
def submit_inline_comments!(warnings: [], errors: [], messages: [], markdowns: [], previous_violations: [], danger_id: "danger")
|
142
|
+
# Avoid doing any fetchs if there's no inline comments
|
143
|
+
return {} if (warnings + errors + messages + markdowns).select(&:inline?).empty?
|
144
|
+
|
145
|
+
pr_threads = @api.fetch_last_comments
|
146
|
+
danger_threads = pr_threads.select do |thread|
|
147
|
+
comment = thread[:comments].first
|
148
|
+
comment_content = comment[:content].nil? ? "" : comment[:content]
|
149
|
+
|
150
|
+
next comment_content.include?("generated_by_#{danger_id}")
|
151
|
+
end
|
152
|
+
non_danger_threads = pr_threads - danger_threads
|
153
|
+
|
154
|
+
warnings = submit_inline_comments_for_kind!(:warning, warnings, danger_threads, previous_violations["warning"], danger_id: danger_id)
|
155
|
+
errors = submit_inline_comments_for_kind!(:error, errors, danger_threads, previous_violations["error"], danger_id: danger_id)
|
156
|
+
messages = submit_inline_comments_for_kind!(:message, messages, danger_threads, previous_violations["message"], danger_id: danger_id)
|
157
|
+
markdowns = submit_inline_comments_for_kind!(:markdown, markdowns, danger_threads, [], danger_id: danger_id)
|
158
|
+
|
159
|
+
# submit removes from the array all comments that are still in force
|
160
|
+
# so we strike out all remaining ones
|
161
|
+
danger_threads.each do |thread|
|
162
|
+
violation = violations_from_table(thread[:comments].first[:content]).first
|
163
|
+
if !violation.nil? && violation.sticky
|
164
|
+
body = generate_inline_comment_body("white_check_mark", violation, danger_id: danger_id, resolved: true, template: "github")
|
165
|
+
@api.update_comment(thread[:id], thread[:comments].first[:id], body)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
{
|
170
|
+
warnings: warnings,
|
171
|
+
errors: errors,
|
172
|
+
messages: messages,
|
173
|
+
markdowns: markdowns
|
174
|
+
}
|
175
|
+
end
|
176
|
+
|
177
|
+
def messages_are_equivalent(m1, m2)
|
178
|
+
blob_regexp = %r{blob/[0-9a-z]+/}
|
179
|
+
m1.file == m2.file && m1.line == m2.line &&
|
180
|
+
m1.message.sub(blob_regexp, "") == m2.message.sub(blob_regexp, "")
|
181
|
+
end
|
182
|
+
|
183
|
+
def submit_inline_comments_for_kind!(kind, messages, danger_threads, previous_violations, danger_id: "danger")
|
184
|
+
previous_violations ||= []
|
185
|
+
is_markdown_content = kind == :markdown
|
186
|
+
emoji = { warning: "warning", error: "no_entry_sign", message: "book" }[kind]
|
187
|
+
|
188
|
+
messages.reject do |m|
|
189
|
+
next false unless m.file && m.line
|
190
|
+
|
191
|
+
# Once we know we're gonna submit it, we format it
|
192
|
+
if is_markdown_content
|
193
|
+
body = generate_inline_markdown_body(m, danger_id: danger_id, template: "vsts")
|
194
|
+
else
|
195
|
+
# Hide the inline link behind a span
|
196
|
+
m.message = m.message.gsub("\n", "<br />")
|
197
|
+
m = process_markdown(m, true)
|
198
|
+
body = generate_inline_comment_body(emoji, m, danger_id: danger_id, template: "vsts")
|
199
|
+
# A comment might be in previous_violations because only now it's part of the unified diff
|
200
|
+
# We remove from the array since it won't have a place in the table anymore
|
201
|
+
previous_violations.reject! { |v| messages_are_equivalent(v, m) }
|
202
|
+
end
|
203
|
+
|
204
|
+
matching_threads = danger_threads.select do |comment_data|
|
205
|
+
if comment_data.key?(:threadContext) && !comment_data[:threadContext].nil? &&
|
206
|
+
comment_data[:threadContext][:filePath] == m.file &&
|
207
|
+
comment_data[:threadContext].key?(:rightFileStart) &&
|
208
|
+
comment_data[:threadContext][:rightFileStart][:line] == m.line
|
209
|
+
# Parse it to avoid problems with strikethrough
|
210
|
+
violation = violations_from_table(comment_data[:comments].first[:content]).first
|
211
|
+
if violation
|
212
|
+
messages_are_equivalent(violation, m)
|
213
|
+
else
|
214
|
+
blob_regexp = %r{blob/[0-9a-z]+/}
|
215
|
+
comment_data[:comments].first[:content].sub(blob_regexp, "") == body.sub(blob_regexp, "")
|
216
|
+
end
|
217
|
+
else
|
218
|
+
false
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
if matching_threads.empty?
|
223
|
+
@api.post_inline_comment(body, m.file, m.line)
|
224
|
+
|
225
|
+
# Not reject because this comment has not completed
|
226
|
+
next false
|
227
|
+
else
|
228
|
+
# Remove the surviving comment so we don't strike it out
|
229
|
+
danger_threads.reject! { |c| matching_threads.include? c }
|
230
|
+
|
231
|
+
# Update the comment to remove the strikethrough if present
|
232
|
+
thread = matching_threads.first
|
233
|
+
@api.update_comment(thread[:id], thread[:comments].first[:id], body)
|
234
|
+
end
|
235
|
+
|
236
|
+
# Remove this element from the array
|
237
|
+
next true
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
private
|
242
|
+
|
243
|
+
def regular_violations_group(warnings: [], errors: [], messages: [], markdowns: [])
|
244
|
+
{
|
245
|
+
warnings: warnings.reject(&:inline?),
|
246
|
+
errors: errors.reject(&:inline?),
|
247
|
+
messages: messages.reject(&:inline?),
|
248
|
+
markdowns: markdowns.reject(&:inline?)
|
249
|
+
}
|
250
|
+
end
|
251
|
+
|
252
|
+
def inline_violations_group(warnings: [], errors: [], messages: [], markdowns: [])
|
253
|
+
cmp = proc do |a, b|
|
254
|
+
next -1 unless a.file && a.line
|
255
|
+
next 1 unless b.file && b.line
|
256
|
+
|
257
|
+
next a.line <=> b.line if a.file == b.file
|
258
|
+
|
259
|
+
next a.file <=> b.file
|
260
|
+
end
|
261
|
+
|
262
|
+
# Sort to group inline comments by file
|
263
|
+
{
|
264
|
+
warnings: warnings.select(&:inline?).sort(&cmp),
|
265
|
+
errors: errors.select(&:inline?).sort(&cmp),
|
266
|
+
messages: messages.select(&:inline?).sort(&cmp),
|
267
|
+
markdowns: markdowns.select(&:inline?).sort(&cmp)
|
268
|
+
}
|
269
|
+
end
|
270
|
+
|
271
|
+
def merge_violations(*violation_groups)
|
272
|
+
violation_groups.inject({}) do |accumulator, group|
|
273
|
+
accumulator.merge(group) { |_, old, fresh| old + fresh }
|
274
|
+
end
|
275
|
+
end
|
115
276
|
end
|
116
277
|
end
|
117
278
|
end
|