danger 8.4.2 → 9.2.0
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 +4 -4
- data/LICENSE +1 -1
- data/README.md +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 +7 -13
- data/lib/danger/ci_source/concourse.rb +4 -5
- 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 +13 -19
- data/lib/danger/ci_source/jenkins.rb +22 -23
- data/lib/danger/ci_source/local_git_repo.rb +36 -38
- data/lib/danger/ci_source/local_only_git_repo.rb +5 -8
- data/lib/danger/ci_source/support/find_repo_info_from_url.rb +11 -10
- data/lib/danger/ci_source/support/pull_request_finder.rb +47 -43
- 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 +1 -1
- 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 +19 -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 +3 -1
- 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/array_subclass.rb +2 -2
- 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 +3 -6
- data/lib/danger/request_sources/bitbucket_cloud_api.rb +5 -7
- data/lib/danger/request_sources/bitbucket_server.rb +47 -11
- data/lib/danger/request_sources/bitbucket_server_api.rb +17 -14
- data/lib/danger/request_sources/code_insights_api.rb +9 -14
- data/lib/danger/request_sources/github/github.rb +30 -38
- 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 +53 -75
- data/lib/danger/request_sources/local_only.rb +1 -4
- data/lib/danger/request_sources/request_source.rb +20 -8
- data/lib/danger/request_sources/support/get_ignored_violation.rb +1 -1
- data/lib/danger/request_sources/vsts.rb +175 -15
- data/lib/danger/request_sources/vsts_api.rb +41 -7
- data/lib/danger/scm_source/git_repo.rb +2 -1
- data/lib/danger/version.rb +1 -1
- data/lib/danger.rb +1 -0
- metadata +39 -37
- data/lib/danger/ci_source/vsts.rb +0 -73
|
@@ -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"
|
|
@@ -8,7 +7,7 @@ module Danger
|
|
|
8
7
|
module RequestSources
|
|
9
8
|
class GitLab < RequestSource
|
|
10
9
|
include Danger::Helpers::CommentsHelper
|
|
11
|
-
attr_accessor :mr_json, :commits_json, :dismiss_out_of_range_messages
|
|
10
|
+
attr_accessor :mr_json, :commits_json, :dismiss_out_of_range_messages, :endpoint, :host
|
|
12
11
|
|
|
13
12
|
FIRST_GITLAB_GEM_WITH_VERSION_CHECK = Gem::Version.new("4.6.0")
|
|
14
13
|
FIRST_VERSION_WITH_INLINE_COMMENTS = Gem::Version.new("10.8.0")
|
|
@@ -23,20 +22,19 @@ module Danger
|
|
|
23
22
|
|
|
24
23
|
def initialize(ci_source, environment)
|
|
25
24
|
self.ci_source = ci_source
|
|
26
|
-
self.environment = environment
|
|
27
25
|
self.dismiss_out_of_range_messages = false
|
|
28
|
-
|
|
29
|
-
@
|
|
26
|
+
@endpoint = environment["DANGER_GITLAB_API_BASE_URL"] || environment.fetch("CI_API_V4_URL", "https://gitlab.com/api/v4")
|
|
27
|
+
@host = environment.fetch("DANGER_GITLAB_HOST", URI.parse(endpoint).host) || "gitlab.com"
|
|
28
|
+
@token = environment["DANGER_GITLAB_API_TOKEN"]
|
|
30
29
|
end
|
|
31
30
|
|
|
32
31
|
def client
|
|
33
|
-
token
|
|
34
|
-
raise "No API token given, please provide one using `DANGER_GITLAB_API_TOKEN`" unless token
|
|
32
|
+
raise "No API token given, please provide one using `DANGER_GITLAB_API_TOKEN`" unless @token
|
|
35
33
|
|
|
36
34
|
# The require happens inline so that it won't cause exceptions when just using the `danger` gem.
|
|
37
35
|
require "gitlab"
|
|
38
36
|
|
|
39
|
-
@client ||= Gitlab.client(endpoint: endpoint, private_token: token)
|
|
37
|
+
@client ||= Gitlab.client(endpoint: endpoint, private_token: @token)
|
|
40
38
|
rescue LoadError => e
|
|
41
39
|
if e.path == "gitlab"
|
|
42
40
|
puts "The GitLab gem was not installed, you will need to change your Gem from `danger` to `danger-gitlab`.".red
|
|
@@ -48,7 +46,7 @@ module Danger
|
|
|
48
46
|
end
|
|
49
47
|
|
|
50
48
|
def validates_as_ci?
|
|
51
|
-
includes_port =
|
|
49
|
+
includes_port = host.include? ":"
|
|
52
50
|
raise "Port number included in `DANGER_GITLAB_HOST`, this will fail with GitLab CI Runners" if includes_port
|
|
53
51
|
|
|
54
52
|
# We don't call super because in some cases the Git remote doesn't match the GitLab instance host.
|
|
@@ -66,14 +64,6 @@ module Danger
|
|
|
66
64
|
@scm ||= GitRepo.new
|
|
67
65
|
end
|
|
68
66
|
|
|
69
|
-
def endpoint
|
|
70
|
-
@endpoint ||= @environment["DANGER_GITLAB_API_BASE_URL"] || @environment["CI_API_V4_URL"] || "https://gitlab.com/api/v4"
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
def host
|
|
74
|
-
@host ||= @environment["DANGER_GITLAB_HOST"] || URI.parse(endpoint).host || "gitlab.com"
|
|
75
|
-
end
|
|
76
|
-
|
|
77
67
|
def base_commit
|
|
78
68
|
@base_commit ||= self.mr_json.diff_refs.base_sha
|
|
79
69
|
end
|
|
@@ -81,20 +71,18 @@ module Danger
|
|
|
81
71
|
def mr_comments
|
|
82
72
|
# @raw_comments contains what we got back from the server.
|
|
83
73
|
# @comments contains Comment objects (that have less information)
|
|
84
|
-
@comments ||=
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
end
|
|
97
|
-
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
|
|
98
86
|
end
|
|
99
87
|
|
|
100
88
|
def mr_discussions
|
|
@@ -105,10 +93,10 @@ module Danger
|
|
|
105
93
|
@mr_diff ||= begin
|
|
106
94
|
diffs = mr_changes.changes.map do |change|
|
|
107
95
|
diff = change["diff"]
|
|
108
|
-
if diff.start_with?(
|
|
96
|
+
if diff.start_with?("--- a/")
|
|
109
97
|
diff
|
|
110
98
|
else
|
|
111
|
-
"--- a/#{change[
|
|
99
|
+
"--- a/#{change['old_path']}\n+++ b/#{change['new_path']}\n#{diff}"
|
|
112
100
|
end
|
|
113
101
|
end
|
|
114
102
|
diffs.join("\n")
|
|
@@ -116,24 +104,18 @@ module Danger
|
|
|
116
104
|
end
|
|
117
105
|
|
|
118
106
|
def mr_changed_paths
|
|
119
|
-
@mr_changed_paths ||=
|
|
120
|
-
|
|
121
|
-
.changes.map { |change| change["new_path"] }
|
|
122
|
-
end
|
|
107
|
+
@mr_changed_paths ||= mr_changes
|
|
108
|
+
.changes.map { |change| change["new_path"] }
|
|
123
109
|
|
|
124
110
|
@mr_changed_paths
|
|
125
111
|
end
|
|
126
112
|
|
|
127
113
|
def mr_changes
|
|
128
|
-
@mr_changes ||=
|
|
129
|
-
client.merge_request_changes(ci_source.repo_slug, ci_source.pull_request_id)
|
|
130
|
-
end
|
|
114
|
+
@mr_changes ||= client.merge_request_changes(ci_source.repo_slug, ci_source.pull_request_id)
|
|
131
115
|
end
|
|
132
116
|
|
|
133
117
|
def mr_closes_issues
|
|
134
|
-
@mr_closes_issues ||=
|
|
135
|
-
client.merge_request_closes_issues(ci_source.repo_slug, ci_source.pull_request_id)
|
|
136
|
-
end
|
|
118
|
+
@mr_closes_issues ||= client.merge_request_closes_issues(ci_source.repo_slug, ci_source.pull_request_id)
|
|
137
119
|
end
|
|
138
120
|
|
|
139
121
|
def setup_danger_branches
|
|
@@ -163,16 +145,14 @@ module Danger
|
|
|
163
145
|
end
|
|
164
146
|
|
|
165
147
|
def supports_inline_comments
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
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)
|
|
172
153
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
end
|
|
154
|
+
current_version >= FIRST_VERSION_WITH_INLINE_COMMENTS
|
|
155
|
+
end
|
|
176
156
|
end
|
|
177
157
|
|
|
178
158
|
def update_pull_request!(warnings: [], errors: [], messages: [], markdowns: [], danger_id: "danger", new_comment: false, remove_previous_comments: false)
|
|
@@ -262,11 +242,11 @@ module Danger
|
|
|
262
242
|
delete_old_comments!(danger_id: danger_id)
|
|
263
243
|
else
|
|
264
244
|
body = generate_comment(warnings: warnings,
|
|
265
|
-
|
|
245
|
+
errors: errors,
|
|
266
246
|
messages: messages,
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
247
|
+
markdowns: markdowns,
|
|
248
|
+
previous_violations: previous_violations,
|
|
249
|
+
danger_id: danger_id,
|
|
270
250
|
template: "gitlab")
|
|
271
251
|
|
|
272
252
|
if editable_comments.empty? or should_create_new_comment
|
|
@@ -287,11 +267,10 @@ module Danger
|
|
|
287
267
|
|
|
288
268
|
def delete_old_comments!(except: nil, danger_id: "danger")
|
|
289
269
|
@raw_comments.each do |raw_comment|
|
|
290
|
-
|
|
291
270
|
comment = Comment.from_gitlab(raw_comment)
|
|
292
271
|
next unless comment.generated_by_danger?(danger_id)
|
|
293
272
|
next if comment.id == except
|
|
294
|
-
next unless raw_comment.
|
|
273
|
+
next unless raw_comment.kind_of?(Hash) && raw_comment["position"].nil?
|
|
295
274
|
|
|
296
275
|
begin
|
|
297
276
|
client.delete_merge_request_comment(
|
|
@@ -299,7 +278,7 @@ module Danger
|
|
|
299
278
|
ci_source.pull_request_id,
|
|
300
279
|
comment.id
|
|
301
280
|
)
|
|
302
|
-
rescue
|
|
281
|
+
rescue StandardError
|
|
303
282
|
end
|
|
304
283
|
end
|
|
305
284
|
end
|
|
@@ -307,7 +286,7 @@ module Danger
|
|
|
307
286
|
def markdown_link_to_message(message, _)
|
|
308
287
|
"#{message.file}#L#{message.line}: "
|
|
309
288
|
end
|
|
310
|
-
|
|
289
|
+
|
|
311
290
|
# @return [String] The organisation name, is nil if it can't be detected
|
|
312
291
|
def organisation
|
|
313
292
|
nil # TODO: Implement this
|
|
@@ -324,13 +303,12 @@ module Danger
|
|
|
324
303
|
end
|
|
325
304
|
|
|
326
305
|
# @return [String] A URL to the specific file, ready to be downloaded
|
|
327
|
-
def file_url(organisation: nil, repository: nil, branch: nil, path: nil)
|
|
328
|
-
|
|
329
|
-
token = @environment["DANGER_GITLAB_API_TOKEN"]
|
|
306
|
+
def file_url(organisation: nil, repository: nil, ref: nil, branch: nil, path: nil)
|
|
307
|
+
ref ||= (branch || "master")
|
|
330
308
|
# According to GitLab Repositories API docs path and id(slug) should be encoded.
|
|
331
309
|
path = URI.encode_www_form_component(path)
|
|
332
310
|
repository = URI.encode_www_form_component(repository)
|
|
333
|
-
"#{endpoint}/projects/#{repository}/repository/files/#{path}/raw?ref=#{
|
|
311
|
+
"#{endpoint}/projects/#{repository}/repository/files/#{path}/raw?ref=#{ref}&private_token=#{@token}"
|
|
334
312
|
end
|
|
335
313
|
|
|
336
314
|
def regular_violations_group(warnings: [], errors: [], messages: [], markdowns: [])
|
|
@@ -348,6 +326,7 @@ module Danger
|
|
|
348
326
|
next 1 unless b.file && b.line
|
|
349
327
|
|
|
350
328
|
next a.line <=> b.line if a.file == b.file
|
|
329
|
+
|
|
351
330
|
next a.file <=> b.file
|
|
352
331
|
end
|
|
353
332
|
|
|
@@ -369,7 +348,7 @@ module Danger
|
|
|
369
348
|
def submit_inline_comments!(warnings: [], errors: [], messages: [], markdowns: [], previous_violations: [], danger_id: "danger")
|
|
370
349
|
comments = mr_discussions
|
|
371
350
|
.auto_paginate
|
|
372
|
-
.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 }) } }
|
|
373
352
|
.select { |comment| Comment.from_gitlab(comment).inline? }
|
|
374
353
|
|
|
375
354
|
danger_comments = comments.select { |comment| Comment.from_gitlab(comment).generated_by_danger?(danger_id) }
|
|
@@ -411,7 +390,7 @@ module Danger
|
|
|
411
390
|
}
|
|
412
391
|
end
|
|
413
392
|
|
|
414
|
-
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")
|
|
415
394
|
previous_violations ||= []
|
|
416
395
|
is_markdown_content = kind == :markdown
|
|
417
396
|
emoji = { warning: "warning", error: "no_entry_sign", message: "book" }[kind]
|
|
@@ -450,7 +429,7 @@ module Danger
|
|
|
450
429
|
params = {
|
|
451
430
|
body: body,
|
|
452
431
|
position: {
|
|
453
|
-
position_type:
|
|
432
|
+
position_type: "text",
|
|
454
433
|
new_path: m.file,
|
|
455
434
|
new_line: m.line,
|
|
456
435
|
old_path: old_position[:path],
|
|
@@ -560,20 +539,19 @@ module Danger
|
|
|
560
539
|
line_number = 0
|
|
561
540
|
diff.each_line do |line|
|
|
562
541
|
if line.match range_header_regexp
|
|
563
|
-
line = line.split(
|
|
564
|
-
line = line.split(
|
|
565
|
-
range_string = line.split(
|
|
542
|
+
line = line.split("+").last
|
|
543
|
+
line = line.split(" ").first
|
|
544
|
+
range_string = line.split(",")
|
|
566
545
|
line_number = range_string[0].to_i - 1
|
|
567
|
-
elsif line.start_with?(
|
|
546
|
+
elsif line.start_with?("+")
|
|
568
547
|
addition_lines.push(line_number)
|
|
569
|
-
elsif line.start_with?(
|
|
570
|
-
line_number
|
|
548
|
+
elsif line.start_with?("-")
|
|
549
|
+
line_number -= 1
|
|
571
550
|
end
|
|
572
|
-
line_number
|
|
551
|
+
line_number += 1
|
|
573
552
|
end
|
|
574
553
|
addition_lines
|
|
575
554
|
end
|
|
576
|
-
|
|
577
555
|
end
|
|
578
556
|
end
|
|
579
557
|
end
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
# coding: utf-8
|
|
2
|
-
|
|
3
1
|
require "danger/helpers/comments_helper"
|
|
4
2
|
require "danger/helpers/comment"
|
|
5
3
|
|
|
@@ -13,9 +11,8 @@ module Danger
|
|
|
13
11
|
["DANGER_LOCAL_ONLY"]
|
|
14
12
|
end
|
|
15
13
|
|
|
16
|
-
def initialize(ci_source,
|
|
14
|
+
def initialize(ci_source, _environment)
|
|
17
15
|
self.ci_source = ci_source
|
|
18
|
-
self.environment = environment
|
|
19
16
|
end
|
|
20
17
|
|
|
21
18
|
def validates_as_ci?
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Danger
|
|
2
4
|
module RequestSources
|
|
3
5
|
class RequestSource
|
|
4
|
-
DANGER_REPO_NAME = "danger"
|
|
6
|
+
DANGER_REPO_NAME = "danger"
|
|
5
7
|
|
|
6
|
-
attr_accessor :ci_source, :
|
|
8
|
+
attr_accessor :ci_source, :scm, :host, :ignored_violations
|
|
7
9
|
|
|
8
10
|
def self.env_vars
|
|
9
11
|
raise "Subclass and overwrite self.env_vars"
|
|
@@ -23,12 +25,12 @@ module Danger
|
|
|
23
25
|
end
|
|
24
26
|
|
|
25
27
|
def self.source_name
|
|
26
|
-
to_s.sub("Danger::RequestSources::"
|
|
28
|
+
to_s.sub("Danger::RequestSources::", "")
|
|
27
29
|
end
|
|
28
30
|
|
|
29
31
|
def self.available_source_names_and_envs
|
|
30
32
|
available_request_sources.map do |klass|
|
|
31
|
-
" - #{klass.source_name}: #{klass.env_vars.join(', '
|
|
33
|
+
" - #{klass.source_name}: #{klass.env_vars.join(', ').yellow}"
|
|
32
34
|
end
|
|
33
35
|
end
|
|
34
36
|
|
|
@@ -36,6 +38,16 @@ module Danger
|
|
|
36
38
|
raise "Subclass and overwrite initialize"
|
|
37
39
|
end
|
|
38
40
|
|
|
41
|
+
def inspect
|
|
42
|
+
inspected = super
|
|
43
|
+
|
|
44
|
+
inspected.gsub!(@token, "********") if @token
|
|
45
|
+
inspected.gsub!(@access_token, "********") if @access_token
|
|
46
|
+
inspected.gsub!(@bearer_token, "********") if @bearer_token
|
|
47
|
+
|
|
48
|
+
inspected
|
|
49
|
+
end
|
|
50
|
+
|
|
39
51
|
# @return [Boolean] whether scm.origins is a valid git repository or not
|
|
40
52
|
def validates_as_ci?
|
|
41
53
|
!!self.scm.origins.match(%r{#{Regexp.escape self.host}(:|/)(.+/.+?)(?:\.git)?$})
|
|
@@ -73,12 +85,12 @@ module Danger
|
|
|
73
85
|
raise "Subclass and overwrite organisation"
|
|
74
86
|
end
|
|
75
87
|
|
|
76
|
-
def file_url(_organisation: nil, _repository: nil, _branch:
|
|
88
|
+
def file_url(_organisation: nil, _repository: nil, _ref: nil, _branch: nil, _path: nil)
|
|
77
89
|
raise "Subclass and overwrite file_url"
|
|
78
90
|
end
|
|
79
|
-
|
|
80
|
-
def update_build_status(
|
|
81
|
-
|
|
91
|
+
|
|
92
|
+
def update_build_status(_status)
|
|
93
|
+
raise "Subclass and overwrite update_build_status"
|
|
82
94
|
end
|
|
83
95
|
end
|
|
84
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
|
|
|
@@ -24,16 +22,14 @@ module Danger
|
|
|
24
22
|
|
|
25
23
|
def initialize(ci_source, environment)
|
|
26
24
|
self.ci_source = ci_source
|
|
27
|
-
self.environment = environment
|
|
28
25
|
|
|
29
|
-
@
|
|
26
|
+
@is_vsts_ci = environment.key? "DANGER_VSTS_HOST"
|
|
30
27
|
|
|
31
|
-
|
|
32
|
-
@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)
|
|
33
29
|
end
|
|
34
30
|
|
|
35
31
|
def validates_as_ci?
|
|
36
|
-
@
|
|
32
|
+
@is_vsts_ci
|
|
37
33
|
end
|
|
38
34
|
|
|
39
35
|
def validates_as_api_source?
|
|
@@ -44,6 +40,10 @@ module Danger
|
|
|
44
40
|
@scm ||= GitRepo.new
|
|
45
41
|
end
|
|
46
42
|
|
|
43
|
+
def client
|
|
44
|
+
@api
|
|
45
|
+
end
|
|
46
|
+
|
|
47
47
|
def host
|
|
48
48
|
@host ||= @api.host
|
|
49
49
|
end
|
|
@@ -77,15 +77,36 @@ module Danger
|
|
|
77
77
|
return
|
|
78
78
|
end
|
|
79
79
|
|
|
80
|
-
|
|
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])
|
|
81
104
|
comment += "\n\n"
|
|
82
|
-
comment += generate_comment(
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
danger_id: danger_id,
|
|
88
|
-
template: "vsts")
|
|
105
|
+
comment += generate_comment(**{
|
|
106
|
+
previous_violations: {},
|
|
107
|
+
danger_id: danger_id,
|
|
108
|
+
template: "vsts"
|
|
109
|
+
}.merge(main_violations))
|
|
89
110
|
if new_comment || remove_previous_comments
|
|
90
111
|
post_new_comment(comment)
|
|
91
112
|
else
|
|
@@ -106,6 +127,9 @@ module Danger
|
|
|
106
127
|
comment_content = comment[:content].nil? ? "" : comment[:content]
|
|
107
128
|
# Skip the comment if it wasn't posted by danger
|
|
108
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
|
+
|
|
109
133
|
# Updated the danger posted comment
|
|
110
134
|
@api.update_comment(thread_id, comment_id, new_comment)
|
|
111
135
|
comment_updated = true
|
|
@@ -113,6 +137,142 @@ module Danger
|
|
|
113
137
|
# If no comment was updated, post a new one
|
|
114
138
|
post_new_comment(new_comment) unless comment_updated
|
|
115
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
|
|
116
276
|
end
|
|
117
277
|
end
|
|
118
278
|
end
|