danger 8.4.5 → 8.6.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 55ca17556aed4215f86219bcdca5271049b481a1bd349e35211b4f9e509c2b15
4
- data.tar.gz: b2b1fb228f4325ce12ac2ff9c7a753d1b056966f0e8078bdce392a4fb9334b32
3
+ metadata.gz: 691f7a26ea0a29f107e6f848bdf7450d2043dc15f5c385c136c1a9d818120c3f
4
+ data.tar.gz: d5f84a85ec8419dbbfbdcb742ffb15b5fe075d3bf1f676859152a0bb7b466633
5
5
  SHA512:
6
- metadata.gz: f2769209f205e40a84f24426e4ce93b3681cbe8f4d57970114b0238d0a3f4c5bb8ff75bbd69936635abb7a8c64f933aaf1e18c4c2a0355ef18630d8365b99c60
7
- data.tar.gz: c260a71c30a49e4b6fad9975986324f795fc07750edd082e0e364f6c4975fc69e68619d7bd083bb48dac24f514f14a102d7cb7b95509de1c1b664608fbc63421
6
+ metadata.gz: b712f8566113397b952ebd93e33d1d42b38d1b1a9d04e678971c35feb46a5bfb057236b0ccffc250560df6b1da001fe31f848024de318850c93ecb6af6eb0994
7
+ data.tar.gz: c89ab31d3afe5d668046629643d65858d6eeeea3d5f67006170af38e9a8c31673789de472501d37ff923c41fb538193cce767ae9567ef4a9a474aca96cf4aad4
@@ -67,7 +67,8 @@ module Danger
67
67
  @dangerfile_path,
68
68
  nil,
69
69
  nil,
70
- nil
70
+ nil,
71
+ false
71
72
  )
72
73
  end
73
74
  end
@@ -0,0 +1,17 @@
1
+ <%- @tables.each do |table| -%>
2
+ <%- if table[:content].any? || table[:resolved].any? -%>
3
+ | | |
4
+ |---|---|
5
+ <%- table[:content].each do |violation| -%>
6
+ | <%= @emoji_mapper.map(table[:emoji]) %> | <%= "~~" if table[:resolved] %><%= violation.message %><%= "~~" if table[:resolved] %> |
7
+ <%- end -%>
8
+
9
+ <%- end -%>
10
+ <%- end -%>
11
+
12
+ <%- @markdowns.each do |current| -%>
13
+ <%= current %>
14
+ <%# the previous line has to be aligned far to the left, otherwise markdown can break easily %>
15
+ <%- end -%>
16
+
17
+ Generated by :no_entry_sign: [Danger](https://danger.systems/ "generated_by_<%= @danger_id %>")
@@ -274,7 +274,7 @@ module Danger
274
274
  env.scm.diff_for_folder(".".freeze, from: base_branch, to: head_branch, lookup_top_level: true)
275
275
  end
276
276
 
277
- def run(base_branch, head_branch, dangerfile_path, danger_id, new_comment, remove_previous_comments)
277
+ def run(base_branch, head_branch, dangerfile_path, danger_id, new_comment, remove_previous_comments, report_results = true)
278
278
  # Setup internal state
279
279
  init_plugins
280
280
  env.fill_environment_vars
@@ -289,7 +289,7 @@ module Danger
289
289
  # Push results to the API
290
290
  # Pass along the details of the run to the request source
291
291
  # to send back to the code review site.
292
- post_results(danger_id, new_comment, remove_previous_comments)
292
+ post_results(danger_id, new_comment, remove_previous_comments) if report_results
293
293
 
294
294
  # Print results in the terminal
295
295
  print_results
@@ -128,7 +128,7 @@ module Danger
128
128
  # @return [Git::Diff::DiffFile] from the gem `git`
129
129
  #
130
130
  def diff_for_file(file)
131
- (added_files + modified_files).include?(file) ? @git.diff[file] : nil
131
+ (added_files + modified_files + deleted_files).include?(file) ? @git.diff[file] : nil
132
132
  end
133
133
 
134
134
  # @!group Git Metadata
@@ -24,7 +24,8 @@ module Danger
24
24
  # @param [Bool] Should hide any generated link created
25
25
  #
26
26
  # @return [String] The Markdown compatible link
27
- def markdown_link_to_message(message, _)
27
+ def markdown_link_to_message(message, hide_link)
28
+ return "" if hide_link
28
29
  "#{message.file}#L#{message.line}"
29
30
  end
30
31
 
@@ -147,7 +148,7 @@ module Danger
147
148
 
148
149
  def generate_description(warnings: nil, errors: nil, template: "github")
149
150
  emoji_mapper = EmojiMapper.new(template)
150
- if errors.empty? && warnings.empty?
151
+ if (errors.nil? || errors.empty?) && (warnings.nil? || warnings.empty?)
151
152
  return ENV['DANGER_SUCCESS_MESSAGE'] || "All green. #{random_compliment}"
152
153
  else
153
154
  message = "#{emoji_mapper.map('warning')} "
@@ -43,6 +43,10 @@ module Danger
43
43
  @scm ||= GitRepo.new
44
44
  end
45
45
 
46
+ def client
47
+ @api
48
+ end
49
+
46
50
  def host
47
51
  @host ||= @api.host
48
52
  end
@@ -76,15 +80,36 @@ module Danger
76
80
  return
77
81
  end
78
82
 
79
- comment = generate_description(warnings: warnings, errors: errors)
83
+ regular_violations = regular_violations_group(
84
+ warnings: warnings,
85
+ errors: errors,
86
+ messages: messages,
87
+ markdowns: markdowns
88
+ )
89
+
90
+ inline_violations = inline_violations_group(
91
+ warnings: warnings,
92
+ errors: errors,
93
+ messages: messages,
94
+ markdowns: markdowns
95
+ )
96
+
97
+ rest_inline_violations = submit_inline_comments!(**{
98
+ danger_id: danger_id,
99
+ previous_violations: {}
100
+ }.merge(inline_violations))
101
+
102
+ main_violations = merge_violations(
103
+ regular_violations, rest_inline_violations
104
+ )
105
+
106
+ comment = generate_description(warnings: main_violations[:warnings], errors: main_violations[:errors])
80
107
  comment += "\n\n"
81
- comment += generate_comment(warnings: warnings,
82
- errors: errors,
83
- messages: messages,
84
- markdowns: markdowns,
85
- previous_violations: {},
86
- danger_id: danger_id,
87
- template: "vsts")
108
+ comment += generate_comment(**{
109
+ previous_violations: {},
110
+ danger_id: danger_id,
111
+ template: "vsts"
112
+ }.merge(main_violations))
88
113
  if new_comment || remove_previous_comments
89
114
  post_new_comment(comment)
90
115
  else
@@ -105,6 +130,8 @@ module Danger
105
130
  comment_content = comment[:content].nil? ? "" : comment[:content]
106
131
  # Skip the comment if it wasn't posted by danger
107
132
  next unless comment_content.include?("generated_by_#{danger_id}")
133
+ # Skip the comment if it's an inline comment
134
+ next unless c[:threadContext].nil?
108
135
  # Updated the danger posted comment
109
136
  @api.update_comment(thread_id, comment_id, new_comment)
110
137
  comment_updated = true
@@ -112,6 +139,142 @@ module Danger
112
139
  # If no comment was updated, post a new one
113
140
  post_new_comment(new_comment) unless comment_updated
114
141
  end
142
+
143
+ def submit_inline_comments!(warnings: [], errors: [], messages: [], markdowns: [], previous_violations: [], danger_id: "danger")
144
+ # Avoid doing any fetchs if there's no inline comments
145
+ return {} if (warnings + errors + messages + markdowns).select(&:inline?).empty?
146
+
147
+ pr_threads = @api.fetch_last_comments
148
+ danger_threads = pr_threads.select do |thread|
149
+ comment = thread[:comments].first
150
+ comment_content = comment[:content].nil? ? "" : comment[:content]
151
+
152
+ next comment_content.include?("generated_by_#{danger_id}")
153
+ end
154
+ non_danger_threads = pr_threads - danger_threads
155
+
156
+ warnings = submit_inline_comments_for_kind!(:warning, warnings, danger_threads, previous_violations["warning"], danger_id: danger_id)
157
+ errors = submit_inline_comments_for_kind!(:error, errors, danger_threads, previous_violations["error"], danger_id: danger_id)
158
+ messages = submit_inline_comments_for_kind!(:message, messages, danger_threads, previous_violations["message"], danger_id: danger_id)
159
+ markdowns = submit_inline_comments_for_kind!(:markdown, markdowns, danger_threads, [], danger_id: danger_id)
160
+
161
+ # submit removes from the array all comments that are still in force
162
+ # so we strike out all remaining ones
163
+ danger_threads.each do |thread|
164
+ violation = violations_from_table(thread[:comments].first[:content]).first
165
+ if !violation.nil? && violation.sticky
166
+ body = generate_inline_comment_body("white_check_mark", violation, danger_id: danger_id, resolved: true, template: "github")
167
+ @api.update_comment(thread[:id], thread[:comments].first[:id], body)
168
+ end
169
+ end
170
+
171
+ {
172
+ warnings: warnings,
173
+ errors: errors,
174
+ messages: messages,
175
+ markdowns: markdowns
176
+ }
177
+ end
178
+
179
+ def messages_are_equivalent(m1, m2)
180
+ blob_regexp = %r{blob/[0-9a-z]+/}
181
+ m1.file == m2.file && m1.line == m2.line &&
182
+ m1.message.sub(blob_regexp, "") == m2.message.sub(blob_regexp, "")
183
+ end
184
+
185
+ def submit_inline_comments_for_kind!(kind, messages, danger_threads, previous_violations, danger_id: "danger")
186
+ previous_violations ||= []
187
+ is_markdown_content = kind == :markdown
188
+ emoji = { warning: "warning", error: "no_entry_sign", message: "book" }[kind]
189
+
190
+ messages.reject do |m|
191
+ next false unless m.file && m.line
192
+
193
+ # Once we know we're gonna submit it, we format it
194
+ if is_markdown_content
195
+ body = generate_inline_markdown_body(m, danger_id: danger_id, template: "vsts")
196
+ else
197
+ # Hide the inline link behind a span
198
+ m.message.gsub!("\n", "<br />")
199
+ m = process_markdown(m, true)
200
+ body = generate_inline_comment_body(emoji, m, danger_id: danger_id, template: "vsts")
201
+ # A comment might be in previous_violations because only now it's part of the unified diff
202
+ # We remove from the array since it won't have a place in the table anymore
203
+ previous_violations.reject! { |v| messages_are_equivalent(v, m) }
204
+ end
205
+
206
+ matching_threads = danger_threads.select do |comment_data|
207
+ if comment_data.key?(:threadContext) && !comment_data[:threadContext].nil? &&
208
+ comment_data[:threadContext][:filePath] == m.file &&
209
+ comment_data[:threadContext].key?(:rightFileStart) &&
210
+ comment_data[:threadContext][:rightFileStart][:line] == m.line
211
+ # Parse it to avoid problems with strikethrough
212
+ violation = violations_from_table(comment_data[:comments].first[:content]).first
213
+ if violation
214
+ messages_are_equivalent(violation, m)
215
+ else
216
+ blob_regexp = %r{blob/[0-9a-z]+/}
217
+ comment_data[:comments].first[:content].sub(blob_regexp, "") == body.sub(blob_regexp, "")
218
+ end
219
+ else
220
+ false
221
+ end
222
+ end
223
+
224
+ if matching_threads.empty?
225
+ @api.post_inline_comment(body, m.file, m.line)
226
+
227
+ # Not reject because this comment has not completed
228
+ next false
229
+ else
230
+ # Remove the surviving comment so we don't strike it out
231
+ danger_threads.reject! { |c| matching_threads.include? c }
232
+
233
+ # Update the comment to remove the strikethrough if present
234
+ thread = matching_threads.first
235
+ @api.update_comment(thread[:id], thread[:comments].first[:id], body)
236
+ end
237
+
238
+ # Remove this element from the array
239
+ next true
240
+ end
241
+ end
242
+
243
+ private
244
+
245
+ def regular_violations_group(warnings: [], errors: [], messages: [], markdowns: [])
246
+ {
247
+ warnings: warnings.reject(&:inline?),
248
+ errors: errors.reject(&:inline?),
249
+ messages: messages.reject(&:inline?),
250
+ markdowns: markdowns.reject(&:inline?)
251
+ }
252
+ end
253
+
254
+ def inline_violations_group(warnings: [], errors: [], messages: [], markdowns: [])
255
+ cmp = proc do |a, b|
256
+ next -1 unless a.file && a.line
257
+ next 1 unless b.file && b.line
258
+
259
+ next a.line <=> b.line if a.file == b.file
260
+ next a.file <=> b.file
261
+ end
262
+
263
+ # Sort to group inline comments by file
264
+ {
265
+ warnings: warnings.select(&:inline?).sort(&cmp),
266
+ errors: errors.select(&:inline?).sort(&cmp),
267
+ messages: messages.select(&:inline?).sort(&cmp),
268
+ markdowns: markdowns.select(&:inline?).sort(&cmp)
269
+ }
270
+ end
271
+
272
+ def merge_violations(*violation_groups)
273
+ violation_groups.inject({}) do |accumulator, group|
274
+ accumulator.merge(group) { |_, old, fresh| old + fresh }
275
+ end
276
+ end
277
+
115
278
  end
116
279
  end
117
280
  end
@@ -76,6 +76,38 @@ module Danger
76
76
  post(uri, body)
77
77
  end
78
78
 
79
+ def post_inline_comment(text, file, line)
80
+ uri = URI("#{pr_api_endpoint}/threads?api-version=#{@api_version}")
81
+ body = {
82
+ "comments" => [
83
+ {
84
+ "parentCommentId" => 0,
85
+ "content" => text,
86
+ "commentType" => 1
87
+ }
88
+ ],
89
+ "properties" => {
90
+ "Microsoft.TeamFoundation.Discussion.SupportsMarkdown" => {
91
+ "type" => "System.Int32",
92
+ "value" => 1
93
+ }
94
+ },
95
+ "status" => 1,
96
+ "threadContext" => {
97
+ "filePath" => file,
98
+ "rightFileEnd" => {
99
+ "line" => line + 1,
100
+ "offset" => 1
101
+ },
102
+ "rightFileStart" => {
103
+ "line" => line,
104
+ "offset" => 1
105
+ }
106
+ }
107
+ }.to_json
108
+ post(uri, body)
109
+ end
110
+
79
111
  def update_comment(thread, id, new_comment)
80
112
  uri = URI("#{pr_api_endpoint}/threads/#{thread}/comments/#{id}?api-version=#{@api_version}")
81
113
  body = {
@@ -55,7 +55,8 @@ module Danger
55
55
  def exec(string)
56
56
  require "open3"
57
57
  Dir.chdir(self.folder || ".") do
58
- Open3.popen2(default_env, "git #{string}") do |_stdin, stdout, _wait_thr|
58
+ git_command = string.split(" ").dup.unshift("git")
59
+ Open3.popen2(default_env, *git_command) do |_stdin, stdout, _wait_thr|
59
60
  stdout.read.rstrip
60
61
  end
61
62
  end
@@ -1,4 +1,4 @@
1
1
  module Danger
2
- VERSION = "8.4.5".freeze
2
+ VERSION = "8.6.1".freeze
3
3
  DESCRIPTION = "Like Unit Tests, but for your Team Culture.".freeze
4
4
  end
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: 8.4.5
4
+ version: 8.6.1
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: 2022-03-04 00:00:00.000000000 Z
12
+ date: 2022-04-22 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: claide
@@ -271,6 +271,7 @@ files:
271
271
  - lib/danger/comment_generators/gitlab.md.erb
272
272
  - lib/danger/comment_generators/gitlab_inline.md.erb
273
273
  - lib/danger/comment_generators/vsts.md.erb
274
+ - lib/danger/comment_generators/vsts_inline.md.erb
274
275
  - lib/danger/core_ext/file_list.rb
275
276
  - lib/danger/core_ext/string.rb
276
277
  - lib/danger/danger_core/dangerfile.rb