danger 3.1.1 → 3.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/lib/danger.rb +14 -0
- data/lib/danger/ci_source/jenkins.rb +1 -1
- data/lib/danger/ci_source/local_git_repo.rb +4 -0
- data/lib/danger/clients/rubygems_client.rb +14 -0
- data/lib/danger/comment_generators/bitbucket_server.md.erb +20 -0
- data/lib/danger/comment_generators/github_inline.md.erb +26 -0
- data/lib/danger/danger_core/dangerfile.rb +15 -6
- data/lib/danger/danger_core/messages/markdown.rb +28 -0
- data/lib/danger/danger_core/messages/violation.rb +35 -0
- data/lib/danger/danger_core/plugins/dangerfile_bitbucket_server_plugin.rb +182 -0
- data/lib/danger/danger_core/plugins/dangerfile_danger_plugin.rb +61 -6
- data/lib/danger/danger_core/plugins/dangerfile_messaging_plugin.rb +30 -9
- data/lib/danger/danger_core/standard_error.rb +10 -1
- data/lib/danger/helpers/comments_helper.rb +94 -33
- data/lib/danger/helpers/comments_parsing_helper.rb +52 -0
- data/lib/danger/request_source/bitbucket_server.rb +78 -0
- data/lib/danger/request_source/bitbucket_server_api.rb +70 -0
- data/lib/danger/request_source/github.rb +207 -9
- data/lib/danger/scm_source/git_repo.rb +10 -1
- data/lib/danger/version.rb +1 -1
- metadata +13 -4
- data/lib/danger/danger_core/violation.rb +0 -10
@@ -100,16 +100,42 @@ module Danger
|
|
100
100
|
previous_violations = parse_comment(comment)
|
101
101
|
end
|
102
102
|
|
103
|
-
|
103
|
+
main_violations = (warnings + errors + messages + markdowns).reject(&:inline?)
|
104
|
+
if previous_violations.empty? && main_violations.empty?
|
104
105
|
# Just remove the comment, if there's nothing to say.
|
105
106
|
delete_old_comments!(danger_id: danger_id)
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
107
|
+
end
|
108
|
+
|
109
|
+
cmp = proc do |a, b|
|
110
|
+
next -1 unless a.file
|
111
|
+
next 1 unless b.file
|
112
|
+
|
113
|
+
next a.line <=> b.line if a.file == b.file
|
114
|
+
next a.file <=> b.file
|
115
|
+
end
|
116
|
+
|
117
|
+
# Sort to group inline comments by file
|
118
|
+
# We copy because we need to mutate this arrays for inlines
|
119
|
+
comment_warnings = warnings.sort(&cmp)
|
120
|
+
comment_errors = errors.sort(&cmp)
|
121
|
+
comment_messages = messages.sort(&cmp)
|
122
|
+
comment_markdowns = markdowns.sort(&cmp)
|
123
|
+
|
124
|
+
submit_inline_comments!(warnings: comment_warnings,
|
125
|
+
errors: comment_errors,
|
126
|
+
messages: comment_messages,
|
127
|
+
markdowns: comment_markdowns,
|
128
|
+
previous_violations: previous_violations,
|
129
|
+
danger_id: danger_id)
|
130
|
+
|
131
|
+
# If there are still violations to show
|
132
|
+
unless main_violations.empty?
|
133
|
+
body = generate_comment(warnings: comment_warnings,
|
134
|
+
errors: comment_errors,
|
135
|
+
messages: comment_messages,
|
136
|
+
markdowns: comment_markdowns,
|
137
|
+
previous_violations: previous_violations,
|
138
|
+
danger_id: danger_id,
|
113
139
|
template: "github")
|
114
140
|
|
115
141
|
if editable_comments.empty?
|
@@ -124,7 +150,7 @@ module Danger
|
|
124
150
|
# Note: this can terminate the entire process.
|
125
151
|
submit_pull_request_status!(warnings: warnings,
|
126
152
|
errors: errors,
|
127
|
-
details_url: comment_result[
|
153
|
+
details_url: comment_result[:html_url])
|
128
154
|
end
|
129
155
|
|
130
156
|
def submit_pull_request_status!(warnings: [], errors: [], details_url: [])
|
@@ -170,6 +196,178 @@ module Danger
|
|
170
196
|
end
|
171
197
|
end
|
172
198
|
|
199
|
+
def submit_inline_comments!(warnings: [], errors: [], messages: [], markdowns: [], previous_violations: [], danger_id: "danger")
|
200
|
+
# Avoid doing any fetchs if there's no inline comments
|
201
|
+
return if (warnings + errors + messages).select(&:inline?).empty?
|
202
|
+
|
203
|
+
diff_lines = self.pr_diff.lines
|
204
|
+
pr_comments = client.pull_request_comments(ci_source.repo_slug, ci_source.pull_request_id)
|
205
|
+
danger_comments = pr_comments.select { |comment| comment[:body].include?("generated_by_#{danger_id}") }
|
206
|
+
non_danger_comments = pr_comments - danger_comments
|
207
|
+
|
208
|
+
submit_inline_comments_for_kind!("warning", warnings, diff_lines, danger_comments, previous_violations[:warning], danger_id: danger_id)
|
209
|
+
submit_inline_comments_for_kind!("no_entry_sign", errors, diff_lines, danger_comments, previous_violations[:error], danger_id: danger_id)
|
210
|
+
submit_inline_comments_for_kind!("book", messages, diff_lines, danger_comments, previous_violations[:message], danger_id: danger_id)
|
211
|
+
submit_inline_comments_for_kind!(nil, markdowns, diff_lines, danger_comments, [], danger_id: danger_id)
|
212
|
+
|
213
|
+
# submit removes from the array all comments that are still in force
|
214
|
+
# so we strike out all remaining ones
|
215
|
+
danger_comments.each do |comment|
|
216
|
+
violation = violations_from_table(comment[:body]).first
|
217
|
+
if !violation.nil? && violation.sticky
|
218
|
+
body = generate_inline_comment_body("white_check_mark", violation, danger_id: danger_id, resolved: true, template: "github")
|
219
|
+
client.update_pull_request_comment(ci_source.repo_slug, comment[:id], body)
|
220
|
+
else
|
221
|
+
# We remove non-sticky violations that have no replies
|
222
|
+
# Since there's no direct concept of a reply in GH, we simply consider
|
223
|
+
# the existance of non-danger comments in that line as replies
|
224
|
+
replies = non_danger_comments.select do |potential|
|
225
|
+
potential[:path] == comment[:path] &&
|
226
|
+
potential[:position] == comment[:position] &&
|
227
|
+
potential[:commit_id] == comment[:commit_id]
|
228
|
+
end
|
229
|
+
|
230
|
+
client.delete_pull_request_comment(ci_source.repo_slug, comment[:id]) if replies.empty?
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
def messages_are_equivalent(m1, m2)
|
236
|
+
blob_regexp = %r{blob/[0-9a-z]+/}
|
237
|
+
m1.file == m2.file && m1.line == m2.line &&
|
238
|
+
m1.message.sub(blob_regexp, "") == m2.message.sub(blob_regexp, "")
|
239
|
+
end
|
240
|
+
|
241
|
+
def submit_inline_comments_for_kind!(emoji, messages, diff_lines, danger_comments, previous_violations, danger_id: "danger")
|
242
|
+
head_ref = pr_json[:head][:sha]
|
243
|
+
previous_violations ||= []
|
244
|
+
is_markdown_content = emoji.nil?
|
245
|
+
|
246
|
+
submit_inline = proc do |m|
|
247
|
+
next false unless m.file && m.line
|
248
|
+
|
249
|
+
position = find_position_in_diff diff_lines, m
|
250
|
+
|
251
|
+
# Keep the change if it's line is not in the diff
|
252
|
+
next false if position.nil?
|
253
|
+
|
254
|
+
# Once we know we're gonna submit it, we format it
|
255
|
+
if is_markdown_content
|
256
|
+
body = generate_inline_markdown_body(m, danger_id: danger_id, template: "github")
|
257
|
+
else
|
258
|
+
# Hide the inline link behind a span
|
259
|
+
m = process_markdown(m, true)
|
260
|
+
body = generate_inline_comment_body(emoji, m, danger_id: danger_id, template: "github")
|
261
|
+
# A comment might be in previous_violations because only now it's part of the unified diff
|
262
|
+
# We remove from the array since it won't have a place in the table anymore
|
263
|
+
previous_violations.reject! { |v| messages_are_equivalent(v, m) }
|
264
|
+
end
|
265
|
+
|
266
|
+
matching_comments = danger_comments.select do |comment_data|
|
267
|
+
if comment_data[:path] == m.file && comment_data[:commit_id] == head_ref && comment_data[:position] == position
|
268
|
+
# Parse it to avoid problems with strikethrough
|
269
|
+
violation = violations_from_table(comment_data[:body]).first
|
270
|
+
if violation
|
271
|
+
messages_are_equivalent(violation, m)
|
272
|
+
else
|
273
|
+
comment_data[:body] == body
|
274
|
+
end
|
275
|
+
else
|
276
|
+
false
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
if matching_comments.empty?
|
281
|
+
client.create_pull_request_comment(ci_source.repo_slug, ci_source.pull_request_id,
|
282
|
+
body, head_ref, m.file, position)
|
283
|
+
else
|
284
|
+
# Remove the surviving comment so we don't strike it out
|
285
|
+
danger_comments.reject! { |c| matching_comments.include? c }
|
286
|
+
|
287
|
+
# Update the comment to remove the strikethrough if present
|
288
|
+
comment = matching_comments.first
|
289
|
+
client.update_pull_request_comment(ci_source.repo_slug, comment[:id], body)
|
290
|
+
end
|
291
|
+
|
292
|
+
# Remove this element from the array
|
293
|
+
next true
|
294
|
+
end
|
295
|
+
|
296
|
+
messages.reject!(&submit_inline)
|
297
|
+
end
|
298
|
+
|
299
|
+
def find_position_in_diff(diff_lines, message)
|
300
|
+
range_header_regexp = /@@ -([0-9]+),([0-9]+) \+(?<start>[0-9]+)(,(?<end>[0-9]+))? @@.*/
|
301
|
+
file_header_regexp = %r{ a/.*}
|
302
|
+
|
303
|
+
pattern = "+++ b/" + message.file + "\n"
|
304
|
+
file_start = diff_lines.index(pattern)
|
305
|
+
|
306
|
+
return nil if file_start.nil?
|
307
|
+
|
308
|
+
position = -1
|
309
|
+
file_line = nil
|
310
|
+
|
311
|
+
diff_lines.drop(file_start).each do |line|
|
312
|
+
match = line.match range_header_regexp
|
313
|
+
|
314
|
+
# file_line is set once we find the hunk the line is in
|
315
|
+
# we need to count how many lines in new file we have
|
316
|
+
# so we do it one by one ignoring the deleted lines
|
317
|
+
if !file_line.nil? && !line.start_with?("-")
|
318
|
+
break if file_line == message.line
|
319
|
+
file_line += 1
|
320
|
+
end
|
321
|
+
|
322
|
+
# We need to count how many diff lines are between us and
|
323
|
+
# the line we're looking for
|
324
|
+
position += 1
|
325
|
+
|
326
|
+
next unless match
|
327
|
+
|
328
|
+
# If we found the start of another file diff, we went too far
|
329
|
+
break if line.match file_header_regexp
|
330
|
+
|
331
|
+
range_start = match[:start].to_i
|
332
|
+
if match[:end]
|
333
|
+
range_end = match[:end].to_i + range_start
|
334
|
+
else
|
335
|
+
range_end = range_start
|
336
|
+
end
|
337
|
+
|
338
|
+
# We are past the line position, just abort
|
339
|
+
break if message.line < range_start
|
340
|
+
next unless message.line >= range_start && message.line <= range_end
|
341
|
+
|
342
|
+
file_line = range_start
|
343
|
+
end
|
344
|
+
|
345
|
+
position unless file_line.nil?
|
346
|
+
end
|
347
|
+
|
348
|
+
# See the tests for examples of data coming in looks like
|
349
|
+
def parse_message_from_row(row)
|
350
|
+
message_regexp = %r{(<(a |span data-)href="https://github.com/#{ci_source.repo_slug}/blob/[0-9a-z]+/(?<file>[^#]+)#L(?<line>[0-9]+)"(>[^<]*</a> - |/>))?(?<message>.*?)}im
|
351
|
+
match = message_regexp.match(row)
|
352
|
+
|
353
|
+
if match[:line]
|
354
|
+
line = match[:line].to_i
|
355
|
+
else
|
356
|
+
line = nil
|
357
|
+
end
|
358
|
+
Violation.new(row, true, match[:file], line)
|
359
|
+
end
|
360
|
+
|
361
|
+
def markdown_link_to_message(message, hide_link)
|
362
|
+
url = "https://github.com/#{ci_source.repo_slug}/blob/#{pr_json[:head][:sha]}/#{message.file}#L#{message.line}"
|
363
|
+
|
364
|
+
if hide_link
|
365
|
+
"<span data-href=\"#{url}\"/>"
|
366
|
+
else
|
367
|
+
"[#{message.file}#L#{message.line}](#{url}) - "
|
368
|
+
end
|
369
|
+
end
|
370
|
+
|
173
371
|
# @return [String] The organisation name, is nil if it can't be detected
|
174
372
|
def organisation
|
175
373
|
matched = self.issue_json[:repository_url].match(%r{repos\/(.*)\/})
|
@@ -15,7 +15,10 @@ module Danger
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def exec(string)
|
18
|
-
|
18
|
+
require "open3"
|
19
|
+
Open3.popen2(default_env, "git #{string}") do |_stdin, stdout, _wait_thr|
|
20
|
+
stdout.read.rstrip
|
21
|
+
end
|
19
22
|
end
|
20
23
|
|
21
24
|
def head_commit
|
@@ -25,6 +28,12 @@ module Danger
|
|
25
28
|
def origins
|
26
29
|
exec("remote show origin -n").lines.grep(/Fetch URL/)[0].split(": ", 2)[1].chomp
|
27
30
|
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def default_env
|
35
|
+
{ "LANG" => "en_US.UTF-8" }
|
36
|
+
end
|
28
37
|
end
|
29
38
|
end
|
30
39
|
|
data/lib/danger/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: danger
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Orta Therox
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2016-09-
|
12
|
+
date: 2016-09-03 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: claide
|
@@ -376,6 +376,7 @@ files:
|
|
376
376
|
- lib/danger/ci_source/teamcity.rb
|
377
377
|
- lib/danger/ci_source/travis.rb
|
378
378
|
- lib/danger/ci_source/xcode_server.rb
|
379
|
+
- lib/danger/clients/rubygems_client.rb
|
379
380
|
- lib/danger/commands/init.rb
|
380
381
|
- lib/danger/commands/init_helpers/interviewer.rb
|
381
382
|
- lib/danger/commands/local.rb
|
@@ -385,7 +386,9 @@ files:
|
|
385
386
|
- lib/danger/commands/plugins/plugin_readme.rb
|
386
387
|
- lib/danger/commands/runner.rb
|
387
388
|
- lib/danger/commands/systems.rb
|
389
|
+
- lib/danger/comment_generators/bitbucket_server.md.erb
|
388
390
|
- lib/danger/comment_generators/github.md.erb
|
391
|
+
- lib/danger/comment_generators/github_inline.md.erb
|
389
392
|
- lib/danger/comment_generators/gitlab.md.erb
|
390
393
|
- lib/danger/core_ext/file_list.rb
|
391
394
|
- lib/danger/core_ext/string.rb
|
@@ -393,19 +396,24 @@ files:
|
|
393
396
|
- lib/danger/danger_core/dangerfile_dsl.rb
|
394
397
|
- lib/danger/danger_core/environment_manager.rb
|
395
398
|
- lib/danger/danger_core/executor.rb
|
399
|
+
- lib/danger/danger_core/messages/markdown.rb
|
400
|
+
- lib/danger/danger_core/messages/violation.rb
|
401
|
+
- lib/danger/danger_core/plugins/dangerfile_bitbucket_server_plugin.rb
|
396
402
|
- lib/danger/danger_core/plugins/dangerfile_danger_plugin.rb
|
397
403
|
- lib/danger/danger_core/plugins/dangerfile_git_plugin.rb
|
398
404
|
- lib/danger/danger_core/plugins/dangerfile_github_plugin.rb
|
399
405
|
- lib/danger/danger_core/plugins/dangerfile_gitlab_plugin.rb
|
400
406
|
- lib/danger/danger_core/plugins/dangerfile_messaging_plugin.rb
|
401
407
|
- lib/danger/danger_core/standard_error.rb
|
402
|
-
- lib/danger/danger_core/violation.rb
|
403
408
|
- lib/danger/helpers/comments_helper.rb
|
409
|
+
- lib/danger/helpers/comments_parsing_helper.rb
|
404
410
|
- lib/danger/plugin_support/plugin.rb
|
405
411
|
- lib/danger/plugin_support/plugin_file_resolver.rb
|
406
412
|
- lib/danger/plugin_support/plugin_linter.rb
|
407
413
|
- lib/danger/plugin_support/plugin_parser.rb
|
408
414
|
- lib/danger/plugin_support/templates/readme_table.html.erb
|
415
|
+
- lib/danger/request_source/bitbucket_server.rb
|
416
|
+
- lib/danger/request_source/bitbucket_server_api.rb
|
409
417
|
- lib/danger/request_source/github.rb
|
410
418
|
- lib/danger/request_source/gitlab.rb
|
411
419
|
- lib/danger/request_source/request_source.rb
|
@@ -431,8 +439,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
431
439
|
version: '0'
|
432
440
|
requirements: []
|
433
441
|
rubyforge_project:
|
434
|
-
rubygems_version: 2.
|
442
|
+
rubygems_version: 2.4.8
|
435
443
|
signing_key:
|
436
444
|
specification_version: 4
|
437
445
|
summary: Like Unit Tests, but for your Team Culture.
|
438
446
|
test_files: []
|
447
|
+
has_rdoc:
|