danger 8.0.3 → 8.2.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: f89ff08f152cedf23e9fcb48adc8b256ddb1ef8992c682bb6ad6ef1620ba1f5f
4
- data.tar.gz: d9f689cd3b403177e3475d364f2aebe5b49a78e72eebfaeab49fad8d6ec3f619
3
+ metadata.gz: a23a15079e019e675afdc325babf115a1a6f38ddbd06a5ba11dd93243ea1dfa0
4
+ data.tar.gz: 380335b8eb423be1096f3b25b3f2602d24d7288b70deb69e8b9991e6dcf09d16
5
5
  SHA512:
6
- metadata.gz: 9b1db5d7f0ed5106614a967c5bd45cdb8b896327f29512d259f662c0ad994438bb2c9240c122aab93f228eb21bf2f80029d6cf851d7f315f7559e491aa60cb04
7
- data.tar.gz: 51413afca0478a350693672cb831e67e5ed92ff5a6d026caa805bdb58ff09bf7b8bfbbdd5cfc16c83878d8164af26088036fbc5aa354d57c990c75dcb15f8f6f
6
+ metadata.gz: 2d68ba968f860e6b4631536548d23279677645d20e7cb5d9567c73222a87128c027664e72f176bca01a31adbbbc2b8f123f5f20997e005a428cc2321e979d023
7
+ data.tar.gz: 10ab5f0cb6c3810e0f4520724854a3a8e3e4aeef35c252ed7a3ac729a2407c73df382a6cb98b1682170efd215bc495a11a312fa1d47f5d1b546632bd415b8d0f
@@ -50,16 +50,29 @@ module Danger
50
50
  self.repo_url = env["GIT_REPOSITORY_URL"]
51
51
 
52
52
  matcher_url = self.repo_url
53
+ self.repo_slug = repo_slug_from(self.repo_url)
54
+ end
53
55
 
54
- #If the URL contains https:// as :// leads to inaccurate matching. So we remove it and proceed to match.
55
- if repo_url.include? "https://"
56
- matcher_url["https://"] = ''
56
+ def repo_slug_from(url)
57
+ if url =~ URI::regexp
58
+ # Try to parse the URL as a valid URI. This should cover the cases of http/https/ssh URLs.
59
+ begin
60
+ uri = URI.parse(url)
61
+ return uri.path.sub(/^(\/)/,'').sub(/(.git)$/,'')
62
+ rescue URI::InvalidURIError
63
+ # In case URL could not be parsed fallback to git URL parsing.
64
+ repo_slug_asgiturl(url)
65
+ end
66
+ else
67
+ # In case URL could not be parsed fallback to git URL parsing. git@github.com:organization/repo.git
68
+ repo_slug_asgiturl(url)
57
69
  end
70
+ end
58
71
 
72
+ def repo_slug_asgiturl(url)
73
+ matcher_url = url
59
74
  repo_matches = matcher_url.match(%r{([\/:])(([^\/]+\/)+[^\/]+?)(\.git$|$)})[2]
60
-
61
- self.repo_slug = repo_matches unless repo_matches.nil?
62
-
75
+ return repo_matches unless repo_matches.nil?
63
76
  end
64
77
  end
65
78
  end
@@ -0,0 +1,61 @@
1
+ require "git"
2
+ require "danger/request_sources/local_only"
3
+
4
+ module Danger
5
+ # Concourse CI Integration
6
+ #
7
+ # https://concourse-ci.org/
8
+ #
9
+ # ### CI Setup
10
+ #
11
+ # With Concourse, you run the docker images yourself, so you will want to add `yarn danger ci` within one of your build jobs.
12
+ #
13
+ # ``` shell
14
+ # build:
15
+ # image: golang
16
+ # commands:
17
+ # - ...
18
+ # - yarn danger ci
19
+ # ```
20
+ #
21
+ # ### Environment Variable Setup
22
+ #
23
+ # As this is self-hosted, you will need to add the `CONCOURSE` environment variable `export CONCOURSE=true` to your build environment,
24
+ # as well as setting environment variables for `PULL_REQUEST_ID` and `REPO_SLUG`. Assuming you are using the github pull request resource
25
+ # https://github.com/jtarchie/github-pullrequest-resource the id of the PR can be accessed from `git config --get pullrequest.id`.
26
+ #
27
+ # ### Token Setup
28
+ #
29
+ # Once again as this is self-hosted, you will need to add `DANGER_GITHUB_API_TOKEN` environment variable to the build environment.
30
+ # The suggested method of storing the token is within the vault - https://concourse-ci.org/creds.html
31
+
32
+ class Concourse < CI
33
+ def self.validates_as_ci?(env)
34
+ env.key? "CONCOURSE"
35
+ end
36
+
37
+ def self.validates_as_pr?(env)
38
+ exists = ["PULL_REQUEST_ID", "REPO_SLUG"].all? { |x| env[x] && !env[x].empty? }
39
+ exists && env["PULL_REQUEST_ID"].to_i > 0
40
+ end
41
+
42
+ def supported_request_sources
43
+ @supported_request_sources ||= [
44
+ Danger::RequestSources::GitHub,
45
+ Danger::RequestSources::GitLab,
46
+ Danger::RequestSources::BitbucketServer,
47
+ Danger::RequestSources::BitbucketCloud
48
+ ]
49
+ end
50
+
51
+ def initialize(env)
52
+ self.repo_slug = env["REPO_SLUG"]
53
+
54
+ if env["PULL_REQUEST_ID"].to_i > 0
55
+ self.pull_request_id = env["PULL_REQUEST_ID"]
56
+ end
57
+ self.repo_url = GitRepo.new.origins
58
+ end
59
+
60
+ end
61
+ end
@@ -21,7 +21,8 @@ module Danger
21
21
  end
22
22
 
23
23
  def self.validates_as_pr?(env)
24
- env["GITHUB_EVENT_NAME"] == "pull_request"
24
+ value = env["GITHUB_EVENT_NAME"]
25
+ value == "pull_request" || value == "pull_request_target"
25
26
  end
26
27
 
27
28
  def supported_request_sources
@@ -27,6 +27,8 @@ module Danger
27
27
  # branch="%teamcity.build.branch%"
28
28
  # export GITHUB_PULL_REQUEST_ID=(${branch//\// })
29
29
  # ```
30
+ # Or if you are using the pull request feature you can set an environment parameter called `GITHUB_PULL_REQUEST_ID`
31
+ # to the value of: `%teamcity.pullRequest.number`
30
32
  #
31
33
  # #### GitLab
32
34
  #
@@ -9,7 +9,7 @@ module Danger
9
9
  def include?(pattern)
10
10
  self.each do |current|
11
11
  unless current.nil?
12
- return true if File.fnmatch(pattern, current) || pattern == current
12
+ return true if File.fnmatch(pattern, current, File::FNM_EXTGLOB) || pattern == current
13
13
  end
14
14
  end
15
15
  return false
@@ -227,6 +227,23 @@ module Danger
227
227
  paths.first(paths.count - 1).join(", ") + " & " + paths.last
228
228
  end
229
229
 
230
+ # @!group Gitlab Misc
231
+ # Use to ignore inline messages which lay outside a diff's range, thereby not posting the comment.
232
+ # You can set hash to change behavior per each kinds. (ex. `{warning: true, error: false}`)
233
+ # @param [Bool] or [Hash<Symbol, Bool>] dismiss
234
+ # Ignore out of range inline messages, defaults to `true`
235
+ #
236
+ # @return [void]
237
+ def dismiss_out_of_range_messages(dismiss = true)
238
+ if dismiss.kind_of?(Hash)
239
+ @gitlab.dismiss_out_of_range_messages = dismiss
240
+ elsif dismiss.kind_of?(TrueClass)
241
+ @gitlab.dismiss_out_of_range_messages = true
242
+ elsif dismiss.kind_of?(FalseClass)
243
+ @gitlab.dismiss_out_of_range_messages = false
244
+ end
245
+ end
246
+
230
247
  %i(title body author labels json diff).each do |suffix|
231
248
  alias_method "pr_#{suffix}".to_sym, "mr_#{suffix}".to_sym
232
249
  end
@@ -11,7 +11,7 @@ module Danger
11
11
  include Danger::Helpers::CommentsParsingHelper
12
12
 
13
13
  def markdown_parser(text)
14
- Kramdown::Document.new(text, input: "GFM")
14
+ Kramdown::Document.new(text, input: "GFM", smart_quotes: %w[apos apos quot quot])
15
15
  end
16
16
 
17
17
  # !@group Extension points
@@ -2,6 +2,8 @@
2
2
 
3
3
  require "danger/helpers/comments_helper"
4
4
  require "danger/request_sources/bitbucket_server_api"
5
+ require "danger/request_sources/code_insights_api"
6
+ require_relative "request_source"
5
7
 
6
8
  module Danger
7
9
  module RequestSources
@@ -17,12 +19,21 @@ module Danger
17
19
  ]
18
20
  end
19
21
 
22
+ def self.optional_env_vars
23
+ ["DANGER_BITBUCKETSERVER_CODE_INSIGHTS_REPORT_KEY",
24
+ "DANGER_BITBUCKETSERVER_CODE_INSIGHTS_REPORT_TITLE",
25
+ "DANGER_BITBUCKETSERVER_CODE_INSIGHTS_REPORT_DESCRIPTION",
26
+ "DANGER_BITBUCKETSERVER_CODE_INSIGHTS_REPORT_LOGO_URL"
27
+ ]
28
+ end
29
+
20
30
  def initialize(ci_source, environment)
21
31
  self.ci_source = ci_source
22
32
  self.environment = environment
23
33
 
24
34
  project, slug = ci_source.repo_slug.split("/")
25
35
  @api = BitbucketServerAPI.new(project, slug, ci_source.pull_request_id, environment)
36
+ @code_insights = CodeInsightsAPI.new(project, slug, environment)
26
37
  end
27
38
 
28
39
  def validates_as_ci?
@@ -73,16 +84,42 @@ module Danger
73
84
  def update_pull_request!(warnings: [], errors: [], messages: [], markdowns: [], danger_id: "danger", new_comment: false, remove_previous_comments: false)
74
85
  delete_old_comments(danger_id: danger_id) if !new_comment || remove_previous_comments
75
86
 
76
- comment = generate_description(warnings: warnings, errors: errors)
87
+ # If configured, send a Code Insights API to provide the PR with a quality report
88
+ # which includes inline code violations found by Danger as Annotations.
89
+ # If no inline violations occurred, an empty, successful (green) report will be sent.
90
+ if @code_insights.ready?
91
+ inline_violations = inline_violations_group(warnings: warnings, errors: errors, messages: messages)
92
+ inline_warnings = inline_violations[:warnings] || []
93
+ inline_errors = inline_violations[:errors] || []
94
+ inline_messages = inline_violations[:messages] || []
95
+
96
+ head_commit = self.pr_json[:fromRef][:latestCommit]
97
+ @code_insights.send_report(head_commit,
98
+ inline_warnings,
99
+ inline_errors,
100
+ inline_messages)
101
+ end
102
+
103
+ # If we're sending inline comments separately via Code Insights,
104
+ # the main body comment should contain only generic, non-file specific messages.
105
+ if @code_insights.ready?
106
+ main_violations = main_violations_group(warnings: warnings, errors: errors, messages: messages)
107
+ warnings = main_violations[:warnings] || []
108
+ errors = main_violations[:errors] || []
109
+ messages = main_violations[:messages] || []
110
+ markdowns = main_violations[:markdowns] || []
111
+ end
112
+
113
+ comment = generate_description(warnings: warnings,
114
+ errors: errors)
77
115
  comment += "\n\n"
78
116
  comment += generate_comment(warnings: warnings,
79
- errors: errors,
80
- messages: messages,
81
- markdowns: markdowns,
82
- previous_violations: {},
83
- danger_id: danger_id,
84
- template: "bitbucket_server")
85
-
117
+ errors: errors,
118
+ messages: messages,
119
+ markdowns: markdowns,
120
+ previous_violations: {},
121
+ danger_id: danger_id,
122
+ template: "bitbucket_server")
86
123
  @api.post_comment(comment)
87
124
  end
88
125
 
@@ -91,7 +128,34 @@ module Danger
91
128
  @api.delete_comment(c[:id], c[:version]) if c[:text] =~ /generated_by_#{danger_id}/
92
129
  end
93
130
  end
94
-
131
+
132
+ def main_violations_group(warnings: [], errors: [], messages: [], markdowns: [])
133
+ {
134
+ warnings: warnings.reject(&:inline?),
135
+ errors: errors.reject(&:inline?),
136
+ messages: messages.reject(&:inline?),
137
+ markdowns: markdowns.reject(&:inline?)
138
+ }
139
+ end
140
+
141
+ def inline_violations_group(warnings: [], errors: [], messages: [], markdowns: [])
142
+ cmp = proc do |a, b|
143
+ next -1 unless a.file && a.line
144
+ next 1 unless b.file && b.line
145
+
146
+ next a.line <=> b.line if a.file == b.file
147
+ next a.file <=> b.file
148
+ end
149
+
150
+ # Sort to group inline comments by file
151
+ {
152
+ warnings: warnings.select(&:inline?).sort(&cmp),
153
+ errors: errors.select(&:inline?).sort(&cmp),
154
+ messages: messages.select(&:inline?).sort(&cmp),
155
+ markdowns: markdowns.select(&:inline?).sort(&cmp)
156
+ }
157
+ end
158
+
95
159
  def update_pr_build_status(status, build_job_link, description)
96
160
  changeset = self.pr_json[:fromRef][:latestCommit]
97
161
  # Support for older versions of Bitbucket Server
@@ -0,0 +1,147 @@
1
+ # coding: utf-8
2
+
3
+ module Danger
4
+ module RequestSources
5
+ #
6
+ # Provides ability for Danger to interact with Atlassian's Code Insights API in order to provide code quality
7
+ # reports along with inline comments for specific lines in specific files.
8
+ # See https://developer.atlassian.com/server/bitbucket/how-tos/code-insights/ for more details.
9
+ #
10
+ # Currently this functionality is implemented only for Bitbucket Server request source.
11
+ class CodeInsightsAPI
12
+ attr_accessor :username, :password, :host, :report_key, :report_title, :report_description, :logo_url
13
+
14
+ def initialize(project, slug, environment)
15
+ @username = environment["DANGER_BITBUCKETSERVER_USERNAME"] || ""
16
+ @password = environment["DANGER_BITBUCKETSERVER_PASSWORD"] || ""
17
+ @host = environment["DANGER_BITBUCKETSERVER_HOST"] || ""
18
+ @report_key = environment["DANGER_BITBUCKETSERVER_CODE_INSIGHTS_REPORT_KEY"] || ""
19
+ @report_title = environment["DANGER_BITBUCKETSERVER_CODE_INSIGHTS_REPORT_TITLE"] || ""
20
+ @report_description = environment["DANGER_BITBUCKETSERVER_CODE_INSIGHTS_REPORT_DESCRIPTION"] || ""
21
+ @logo_url = environment["DANGER_BITBUCKETSERVER_CODE_INSIGHTS_REPORT_LOGO_URL"] || ""
22
+ @project = project
23
+ @slug = slug
24
+ end
25
+
26
+ def inspect
27
+ inspected = super
28
+
29
+ if @password
30
+ inspected = inspected.sub! @password, "********".freeze
31
+ end
32
+
33
+ inspected
34
+ end
35
+
36
+ def ready?
37
+ !(@report_key.empty? || @report_title.empty? || @report_description.empty? || @username.empty? || @password.empty? || @host.empty?)
38
+ end
39
+
40
+ def delete_report(commit)
41
+ uri = URI(report_endpoint_at_commit(commit))
42
+ request = Net::HTTP::Delete.new(uri.request_uri, {"Content-Type" => "application/json"})
43
+ request.basic_auth @username, @password
44
+ response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: use_ssl) do |http|
45
+ http.request(request)
46
+ end
47
+
48
+ # show failure when server returns an error
49
+ case response
50
+ when Net::HTTPClientError, Net::HTTPServerError
51
+ # HTTP 4xx - 5xx
52
+ abort "\nError deleting report from Code Insights API: #{response.code} (#{response.message}) - #{response.body}\n\n"
53
+ end
54
+
55
+ end
56
+
57
+ def send_report(commit, inline_warnings, inline_errors, inline_messages)
58
+ delete_report(commit)
59
+ put_report(commit, inline_errors.count)
60
+ should_post_annotations = !(inline_warnings + inline_errors + inline_messages).empty?
61
+ if should_post_annotations
62
+ post_annotations(commit, inline_warnings, inline_errors, inline_messages)
63
+ end
64
+ end
65
+
66
+ def put_report(commit, inline_errors_count)
67
+ uri = URI(report_endpoint_at_commit(commit))
68
+ request = Net::HTTP::Put.new(uri.request_uri, {"Content-Type" => "application/json"})
69
+ request.basic_auth @username, @password
70
+ request.body = {"title": @report_title,
71
+ "details": @report_description,
72
+ "result": (inline_errors_count > 0) ? "FAIL" : "PASS",
73
+ "reporter": @username,
74
+ "link": "https://github.com/danger/danger",
75
+ "logoURL": @logo_url
76
+ }.to_json
77
+
78
+ response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: use_ssl) do |http|
79
+ http.request(request)
80
+ end
81
+
82
+ # show failure when server returns an error
83
+ case response
84
+ when Net::HTTPClientError, Net::HTTPServerError
85
+ # HTTP 4xx - 5xx
86
+ abort "\nError putting report to Code Insights API: #{response.code} (#{response.message}) - #{response.body}\n\n"
87
+ end
88
+ end
89
+
90
+ def post_annotations(commit, inline_warnings, inline_errors, inline_messages)
91
+ uri = URI(annotation_endpoint_at_commit(commit))
92
+
93
+ annotations = []
94
+
95
+ inline_messages.each do |violation|
96
+ annotations << violation_hash_with_severity(violation, "LOW")
97
+ end
98
+
99
+ inline_warnings.each do |violation|
100
+ annotations << violation_hash_with_severity(violation, "MEDIUM")
101
+ end
102
+
103
+ inline_errors.each do |violation|
104
+ annotations << violation_hash_with_severity(violation, "HIGH")
105
+ end
106
+
107
+ body = {annotations: annotations}.to_json
108
+ request = Net::HTTP::Post.new(uri.request_uri, {"Content-Type" => "application/json"})
109
+ request.basic_auth @username, @password
110
+ request.body = body
111
+
112
+ response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: use_ssl) do |http|
113
+ http.request(request)
114
+ end
115
+
116
+ # show failure when server returns an error
117
+ case response
118
+ when Net::HTTPClientError, Net::HTTPServerError
119
+ # HTTP 4xx - 5xx
120
+ abort "\nError posting comment to Code Insights API: #{response.code} (#{response.message}) - #{response.body}\n\n"
121
+ end
122
+ end
123
+
124
+ def violation_hash_with_severity(violation, severity)
125
+ annotation = {}
126
+ annotation["message"] = violation.message
127
+ annotation["severity"] = severity
128
+ annotation["path"] = violation.file
129
+ annotation["line"] = violation.line.to_i
130
+ return annotation
131
+ end
132
+
133
+ def report_endpoint_at_commit(commit)
134
+ "#{@host}/rest/insights/1.0/projects/#{@project}/repos/#{@slug}/commits/#{commit}/reports/#{@report_key}"
135
+ end
136
+
137
+ def annotation_endpoint_at_commit(commit)
138
+ report_endpoint_at_commit(commit) + "/annotations"
139
+ end
140
+
141
+ def use_ssl
142
+ @host.include? "https://"
143
+ end
144
+
145
+ end
146
+ end
147
+ end
@@ -171,10 +171,10 @@ module Danger
171
171
  markdowns: markdowns
172
172
  )
173
173
 
174
- rest_inline_violations = submit_inline_comments!({
174
+ rest_inline_violations = submit_inline_comments!(**{
175
175
  danger_id: danger_id,
176
176
  previous_violations: previous_violations
177
- }.merge(**inline_violations))
177
+ }.merge(inline_violations))
178
178
 
179
179
  main_violations = merge_violations(
180
180
  regular_violations, rest_inline_violations
@@ -189,11 +189,11 @@ module Danger
189
189
 
190
190
  # If there are still violations to show
191
191
  if main_violations_sum.any?
192
- body = generate_comment({
192
+ body = generate_comment(**{
193
193
  template: "github",
194
194
  danger_id: danger_id,
195
195
  previous_violations: previous_violations
196
- }.merge(**main_violations))
196
+ }.merge(main_violations))
197
197
 
198
198
  comment_result =
199
199
  if should_create_new_comment
@@ -8,7 +8,7 @@ module Danger
8
8
  module RequestSources
9
9
  class GitLab < RequestSource
10
10
  include Danger::Helpers::CommentsHelper
11
- attr_accessor :mr_json, :commits_json
11
+ attr_accessor :mr_json, :commits_json, :dismiss_out_of_range_messages
12
12
 
13
13
  FIRST_GITLAB_GEM_WITH_VERSION_CHECK = Gem::Version.new("4.6.0")
14
14
  FIRST_VERSION_WITH_INLINE_COMMENTS = Gem::Version.new("10.8.0")
@@ -24,6 +24,7 @@ module Danger
24
24
  def initialize(ci_source, environment)
25
25
  self.ci_source = ci_source
26
26
  self.environment = environment
27
+ self.dismiss_out_of_range_messages = false
27
28
 
28
29
  @token = @environment["DANGER_GITLAB_API_TOKEN"]
29
30
  end
@@ -205,7 +206,7 @@ module Danger
205
206
  markdowns: markdowns
206
207
  )
207
208
 
208
- rest_inline_violations = submit_inline_comments!({
209
+ rest_inline_violations = submit_inline_comments!(**{
209
210
  danger_id: danger_id,
210
211
  previous_violations: previous_violations
211
212
  }.merge(inline_violations))
@@ -223,7 +224,7 @@ module Danger
223
224
 
224
225
  # If there are still violations to show
225
226
  if main_violations_sum.any?
226
- body = generate_comment({
227
+ body = generate_comment(**{
227
228
  template: "gitlab",
228
229
  danger_id: danger_id,
229
230
  previous_violations: previous_violations
@@ -302,6 +303,16 @@ module Danger
302
303
  nil # TODO: Implement this
303
304
  end
304
305
 
306
+ def dismiss_out_of_range_messages_for(kind)
307
+ if self.dismiss_out_of_range_messages.kind_of?(Hash) && self.dismiss_out_of_range_messages[kind]
308
+ self.dismiss_out_of_range_messages[kind]
309
+ elsif self.dismiss_out_of_range_messages == true
310
+ self.dismiss_out_of_range_messages
311
+ else
312
+ false
313
+ end
314
+ end
315
+
305
316
  # @return [String] A URL to the specific file, ready to be downloaded
306
317
  def file_url(organisation: nil, repository: nil, branch: nil, path: nil)
307
318
  branch ||= 'master'
@@ -397,10 +408,9 @@ module Danger
397
408
 
398
409
  messages.reject do |m|
399
410
  next false unless m.file && m.line
400
-
401
- # Keep the change it's in a file changed in this diff
402
- next if !mr_changed_paths.include?(m.file)
403
-
411
+ # Reject if it's out of range and in dismiss mode
412
+ next true if dismiss_out_of_range_messages_for(kind) && is_out_of_range(mr_changes.changes, m)
413
+
404
414
  # Once we know we're gonna submit it, we format it
405
415
  if is_markdown_content
406
416
  body = generate_inline_markdown_body(m, danger_id: danger_id, template: "gitlab")
@@ -473,7 +483,6 @@ module Danger
473
483
  range_header_regexp = /@@ -(?<old>[0-9]+)(,([0-9]+))? \+(?<new>[0-9]+)(,([0-9]+))? @@.*/
474
484
 
475
485
  change = changes.find { |c| c["new_path"] == message.file }
476
-
477
486
  # If there is no changes or rename only or deleted, return nil.
478
487
  return nil if change.nil? || change["diff"].empty? || change["deleted_file"]
479
488
 
@@ -520,6 +529,41 @@ module Danger
520
529
  line: current_old_line - current_new_line + message.line.to_i
521
530
  }
522
531
  end
532
+
533
+ def is_out_of_range(changes, message)
534
+ change = changes.find { |c| c["new_path"] == message.file }
535
+ # If there is no changes or rename only or deleted, return out of range.
536
+ return true if change.nil? || change["diff"].empty? || change["deleted_file"]
537
+
538
+ # If new file then return in range
539
+ return false if change["new_file"]
540
+
541
+ addition_lines = generate_addition_lines(change["diff"])
542
+ return false if addition_lines.include?(message.line.to_i)
543
+
544
+ return true
545
+ end
546
+
547
+ def generate_addition_lines(diff)
548
+ range_header_regexp = /@@ -(?<old>[0-9]+)(,([0-9]+))? \+(?<new>[0-9]+)(,([0-9]+))? @@.*/
549
+ addition_lines = []
550
+ line_number = 0
551
+ diff.each_line do |line|
552
+ if line.match range_header_regexp
553
+ line = line.split('+').last
554
+ line = line.split(' ').first
555
+ range_string = line.split(',')
556
+ line_number = range_string[0].to_i - 1
557
+ elsif line.start_with?('+')
558
+ addition_lines.push(line_number)
559
+ elsif line.start_with?('-')
560
+ line_number=line_number-1
561
+ end
562
+ line_number=line_number+1
563
+ end
564
+ addition_lines
565
+ end
566
+
523
567
  end
524
568
  end
525
569
  end
@@ -1,4 +1,4 @@
1
1
  module Danger
2
- VERSION = "8.0.3".freeze
2
+ VERSION = "8.2.0".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.0.3
4
+ version: 8.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: 2020-07-10 00:00:00.000000000 Z
12
+ date: 2020-10-26 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: claide
@@ -107,14 +107,14 @@ dependencies:
107
107
  requirements:
108
108
  - - "~>"
109
109
  - !ruby/object:Gem::Version
110
- version: '2.0'
110
+ version: '2.3'
111
111
  type: :runtime
112
112
  prerelease: false
113
113
  version_requirements: !ruby/object:Gem::Requirement
114
114
  requirements:
115
115
  - - "~>"
116
116
  - !ruby/object:Gem::Version
117
- version: '2.0'
117
+ version: '2.3'
118
118
  - !ruby/object:Gem::Dependency
119
119
  name: kramdown-parser-gfm
120
120
  requirement: !ruby/object:Gem::Requirement
@@ -214,6 +214,7 @@ files:
214
214
  - lib/danger/ci_source/code_build.rb
215
215
  - lib/danger/ci_source/codefresh.rb
216
216
  - lib/danger/ci_source/codeship.rb
217
+ - lib/danger/ci_source/concourse.rb
217
218
  - lib/danger/ci_source/dotci.rb
218
219
  - lib/danger/ci_source/drone.rb
219
220
  - lib/danger/ci_source/github_actions.rb
@@ -301,6 +302,7 @@ files:
301
302
  - lib/danger/request_sources/bitbucket_cloud_api.rb
302
303
  - lib/danger/request_sources/bitbucket_server.rb
303
304
  - lib/danger/request_sources/bitbucket_server_api.rb
305
+ - lib/danger/request_sources/code_insights_api.rb
304
306
  - lib/danger/request_sources/github/github.rb
305
307
  - lib/danger/request_sources/github/github_review.rb
306
308
  - lib/danger/request_sources/github/github_review_resolver.rb