danger 6.3.2 → 7.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 27b09c31a2f456489426bf90c66b907f7c7b620bc0019387c3c7dd89e14267b6
4
- data.tar.gz: 7aeed8d94b83e5fb757ca0f319fe55e3c07a4fc641c93dd56408efc1aaeccf4a
3
+ metadata.gz: bac82d5de5c00b56576cd95681444543eb4b540f6bb6767ac1d407fb13150fbc
4
+ data.tar.gz: 032b2993f97a2c8c56b4d8f69690c7bbd7bbf6738e3631af54a0ea657811939f
5
5
  SHA512:
6
- metadata.gz: 267bc39cef40d450ec1be77ddeb0c279ef6b5b7f5cd8a3dd2afdb49f6a4b5fa32feb10622c84f0f2f85a3907b4fb05824ecfad0b517fcf4eacd0d4949423dc69
7
- data.tar.gz: de72c74f898bdc9a3c70bf730158e2c642aa6b392935a3e89a6980a457262475c549f10380e0123e4a5b92c03ae9b27018bf7cb8aa919667256edd5639d70149
6
+ metadata.gz: 74fa60f6fc40846e32837a0b8234b119f6132ff4a629abd705480a8c4ebee1bbb78ed19ad940fc63d8d08b427e238bea3edb2d67286d23ceef48ac8a7c9e0dd3
7
+ data.tar.gz: 7072368e374403c31ea5240b8004942c9e28f00806f4acb1d65fafe850d291b8a893f06a3b1a294a325e374fc594e732c43343cd50c36ea99ee5d52ffe281c0a
@@ -66,12 +66,15 @@ module Danger
66
66
 
67
67
  private
68
68
 
69
+ # this method is a duplicate of Commands::PR#configure_octokit
70
+ # - worth a refactor sometime?
69
71
  def configure_octokit(cache_dir)
70
72
  # setup caching for Github calls to hitting the API rate limit too quickly
71
73
  cache_file = File.join(cache_dir, "danger_local_cache")
72
74
  cache = HTTPCache.new(cache_file, clear_cache: @clear_http_cache)
73
75
  Octokit.middleware = Faraday::RackBuilder.new do |builder|
74
76
  builder.use Faraday::HttpCache, store: cache, serializer: Marshal, shared_cache: false
77
+ builder.use Octokit::Middleware::FollowRedirects
75
78
  builder.use Octokit::Response::RaiseError
76
79
  builder.adapter Faraday.default_adapter
77
80
  end
@@ -83,6 +83,7 @@ module Danger
83
83
  end
84
84
  Octokit.middleware = Faraday::RackBuilder.new do |builder|
85
85
  builder.use Faraday::HttpCache, store: cache, serializer: Marshal, shared_cache: false
86
+ builder.use Octokit::Middleware::FollowRedirects
86
87
  builder.use Octokit::Response::RaiseError
87
88
  builder.adapter Faraday.default_adapter
88
89
  end
@@ -0,0 +1,12 @@
1
+ <%- @message_group.messages.each do |message| -%>
2
+ <%- next if message.type == :markdown -%>
3
+ <%= @emoji_mapper.from_type(message.type) -%> <%= message.message %>
4
+
5
+ <%- end -%>
6
+ <%- @resolved.each do |message| -%>
7
+ <%= @emoji_mapper.map("white_check_mark") %> <%= message %>
8
+ <%- end -%>
9
+
10
+ <%= @message_group.markdowns.map(&:message).join("\n\n") %>
11
+
12
+ Generated by :no_entry_sign: [Danger](https://danger.systems/ "generated_by_<%= @danger_id %>")
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "danger/danger_core/dangerfile_dsl"
4
4
  require "danger/danger_core/standard_error"
5
+ require "danger/danger_core/message_aggregator"
5
6
 
6
7
  require "danger/danger_core/plugins/dangerfile_messaging_plugin"
7
8
  require "danger/danger_core/plugins/dangerfile_danger_plugin"
@@ -251,7 +252,10 @@ module Danger
251
252
  }
252
253
 
253
254
  if env.request_source.respond_to?(:update_pr_by_line!) && ENV["DANGER_MESSAGE_AGGREGATION"]
254
- env.request_source.update_pr_by_line!(messages: MessageAggregator.aggregate(**report))
255
+ env.request_source.update_pr_by_line!(message_groups: MessageAggregator.aggregate(**report),
256
+ new_comment: new_comment,
257
+ remove_previous_comments: remove_previous_comments,
258
+ danger_id: report[:danger_id])
255
259
  else
256
260
  env.request_source.update_pull_request!(
257
261
  **report,
@@ -1,12 +1,49 @@
1
- class MessageAggregator
2
- def self.aggregate(*args)
3
- new(*args).aggregate
4
- end
1
+ # frozen_string_literal: true
2
+ require "danger/danger_core/message_group"
3
+ require "danger/helpers/message_groups_array_helper"
4
+
5
+ module Danger
6
+ class MessageAggregator
7
+ def self.aggregate(*args)
8
+ new(*args).aggregate
9
+ end
10
+
11
+ def initialize(warnings: [],
12
+ errors: [],
13
+ messages: [],
14
+ markdowns: [],
15
+ danger_id: "danger")
16
+ @messages = warnings + errors + messages + markdowns
17
+ @danger_id = danger_id
18
+ end
19
+
20
+ # aggregates the messages into an array of MessageGroups
21
+ # @return [[MessageGroup]]
22
+ def aggregate
23
+ # oookay I took some shortcuts with this one.
24
+ # first, sort messages by file and line
25
+ @messages.sort! { |a, b| a.compare_by_file_and_line(b) }
26
+
27
+ # now create an initial empty message group
28
+ first_group = MessageGroup.new(file: nil,
29
+ line: nil)
30
+ @message_groups = @messages.reduce([first_group]) do |groups, msg|
31
+ # We get to take a shortcut because we sorted the messages earlier - only
32
+ # have to see if we can append msg to the last group in the list
33
+ if groups.last << msg
34
+ # we appended it, so return groups unchanged
35
+ groups
36
+ else
37
+ # have to create a new group since msg wasn't appended to the other
38
+ # group
39
+ new_group = MessageGroup.new(file: msg.file,
40
+ line: msg.line)
41
+ new_group << msg
42
+ groups << new_group
43
+ end
44
+ end
5
45
 
6
- def initialize(warnings: [],
7
- errors: [],
8
- messages: [],
9
- markdowns: [],
10
- danger_id: "danger")
46
+ @message_groups.extend(Helpers::MessageGroupsArrayHelper)
47
+ end
11
48
  end
12
49
  end
@@ -28,7 +28,18 @@ module Danger
28
28
  # @param message [Markdown, Violation] the message to add
29
29
  def <<(message)
30
30
  # TODO: insertion sort
31
- messages << message if same_line?(message)
31
+ return nil unless same_line?(message)
32
+
33
+ inserted = false
34
+ messages.each.with_index do |other, idx|
35
+ if (message <=> other) == -1
36
+ inserted = true
37
+ messages.insert(idx, message)
38
+ break
39
+ end
40
+ end
41
+ messages << message unless inserted
42
+ messages
32
43
  end
33
44
 
34
45
  # The list of messages in this group. This list will be sorted in decreasing
@@ -38,5 +49,20 @@ module Danger
38
49
  end
39
50
 
40
51
  attr_reader :file, :line
52
+
53
+ # @return a hash of statistics. Currently only :warnings_count and
54
+ # :errors_count
55
+ def stats
56
+ stats = { warnings_count: 0, errors_count: 0 }
57
+ messages.each do |msg|
58
+ stats[:warnings_count] += 1 if msg.type == :warning
59
+ stats[:errors_count] += 1 if msg.type == :error
60
+ end
61
+ stats
62
+ end
63
+
64
+ def markdowns
65
+ messages.select { |x| x.type == :markdown }
66
+ end
41
67
  end
42
68
  end
@@ -48,7 +48,7 @@ module Danger
48
48
  extra << "line: #{line}" if line
49
49
  extra << "type: #{type}"
50
50
 
51
- "Violation #{message} { #{extra.join ', '.freeze} }"
51
+ "Violation #{message} { #{extra.join ', '} }"
52
52
  end
53
53
  end
54
54
  end
@@ -136,14 +136,14 @@ module Danger
136
136
  # @return [Hash] with keys `:insertions`, `:deletions` giving line counts, and `:before`, `:after` giving file contents, or nil if the file has no changes or does not exist
137
137
  #
138
138
  def info_for_file(file)
139
- return nil unless modified_files.include?(file)
139
+ return nil unless modified_files.include?(file) || added_files.include?(file) || deleted_files.include?(file)
140
140
  stats = @git.diff.stats[:files][file]
141
141
  diff = @git.diff[file]
142
142
  {
143
143
  insertions: stats[:insertions],
144
144
  deletions: stats[:deletions],
145
- before: diff.blob(:src).contents,
146
- after: diff.blob(:dst).contents
145
+ before: added_files.include?(file) || deleted_files.include?(file) ? nil : diff.blob(:src).contents,
146
+ after: added_files.include?(file) || deleted_files.include?(file) ? nil : diff.blob(:dst).contents
147
147
  }
148
148
  end
149
149
 
@@ -76,7 +76,7 @@ module Danger
76
76
  }
77
77
  end
78
78
 
79
- def apply_template(tables: [], markdowns: [], danger_id: "danger", template: "github")
79
+ def apply_template(tables: [], markdowns: [], danger_id: "danger", template: "github", request_source: template)
80
80
  require "erb"
81
81
 
82
82
  md_template = File.join(Danger.gem_path, "lib/danger/comment_generators/#{template}.md.erb")
@@ -86,7 +86,7 @@ module Danger
86
86
  @tables = tables
87
87
  @markdowns = markdowns.map(&:message)
88
88
  @danger_id = danger_id
89
- @emoji_mapper = EmojiMapper.new(template)
89
+ @emoji_mapper = EmojiMapper.new(request_source.sub("_inline",""))
90
90
 
91
91
  return ERB.new(File.read(md_template), 0, "-").result(binding)
92
92
  end
@@ -104,7 +104,32 @@ module Danger
104
104
  )
105
105
  end
106
106
 
107
- def generate_inline_comment_body(emoji, message, danger_id: "danger", resolved: false, template: "github")
107
+ # resolved is essentially reserved for future use - eventually we might
108
+ # have some nice generic resolved-thing going :)
109
+ def generate_message_group_comment(message_group:,
110
+ danger_id: "danger",
111
+ resolved: [],
112
+ template: "github")
113
+ # cheating a bit - I don't want to alter the apply_template API
114
+ # so just sneak around behind its back setting some instance variables
115
+ # to get them to show up in the template
116
+ @message_group = message_group
117
+ @resolved = resolved
118
+ request_source_name = template.sub("_message_group", "")
119
+
120
+
121
+ apply_template(danger_id: danger_id,
122
+ markdowns: message_group.markdowns,
123
+ template: template,
124
+ request_source: request_source_name)
125
+ .sub(/\A\n*/, "")
126
+ end
127
+
128
+ def generate_inline_comment_body(emoji,
129
+ message,
130
+ danger_id: "danger",
131
+ resolved: [],
132
+ template: "github")
108
133
  apply_template(
109
134
  tables: [{ content: [message], resolved: resolved, emoji: emoji }],
110
135
  danger_id: danger_id,
@@ -15,16 +15,25 @@ module Danger
15
15
  }
16
16
  }.freeze
17
17
 
18
+ TYPE_TO_EMOJI = {
19
+ error: "no_entry_sign",
20
+ warning: "warning",
21
+ message: "book",
22
+ }.freeze
23
+
18
24
  def initialize(template)
19
- template.sub!('_inline', '')
20
25
  @template = DATA.has_key?(template) ? template : "github"
21
26
  end
22
27
 
23
28
  def map(emoji)
24
- emoji.delete! ":"
29
+ emoji&.delete! ":"
25
30
  DATA[template][emoji]
26
31
  end
27
32
 
33
+ def from_type(type)
34
+ map(TYPE_TO_EMOJI[type])
35
+ end
36
+
28
37
  private
29
38
 
30
39
  attr_reader :template
@@ -0,0 +1,31 @@
1
+ module Danger
2
+ module Helpers
3
+ module MessageGroupsArrayHelper
4
+ FakeArray = Struct.new(:count) do
5
+ def empty?
6
+ count.zero?
7
+ end
8
+ end
9
+
10
+ def fake_warnings_array
11
+ FakeArray.new(counts[:warnings])
12
+ end
13
+
14
+ def fake_errors_array
15
+ FakeArray.new(counts[:errors])
16
+ end
17
+
18
+ def counts
19
+ return @counts if @counts
20
+
21
+ @counts = { warnings: 0, errors: 0 }
22
+ each do |message_group, counts|
23
+ group_stats = message_group.stats
24
+ @counts[:warnings] += group_stats[:warnings_count]
25
+ @counts[:errors] += group_stats[:errors_count]
26
+ end
27
+ @counts
28
+ end
29
+ end
30
+ end
31
+ end
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "danger/helpers/comments_helper"
4
4
  require "danger/request_sources/bitbucket_cloud_api"
5
+ require "danger/danger_core/message_group"
5
6
 
6
7
  module Danger
7
8
  module RequestSources
@@ -12,6 +13,7 @@ module Danger
12
13
  def self.env_vars
13
14
  [
14
15
  "DANGER_BITBUCKETCLOUD_USERNAME",
16
+ "DANGER_BITBUCKETCLOUD_UUID",
15
17
  "DANGER_BITBUCKETCLOUD_PASSWORD"
16
18
  ]
17
19
  end
@@ -90,6 +92,50 @@ module Danger
90
92
  @api.post_comment(comment)
91
93
  end
92
94
 
95
+ def update_pr_by_line!(message_groups:,
96
+ danger_id: "danger",
97
+ new_comment: false,
98
+ remove_previous_comments: false)
99
+ if !new_comment || remove_previous_comments
100
+ delete_old_comments(danger_id: danger_id)
101
+ end
102
+
103
+ summary_body = generate_description(warnings: message_groups.fake_warnings_array,
104
+ errors: message_groups.fake_errors_array,
105
+ template: "bitbucket_server")
106
+ summary_body += "\n\n"
107
+
108
+
109
+ # this isn't the most elegant thing in the world, but we need the group
110
+ # with file: nil, line: nil so we can combine its info in with the
111
+ # summary_body
112
+ summary_group = message_groups.first
113
+ if summary_group && summary_group.file.nil? && summary_group.line.nil?
114
+ # remove summary_group from message_groups so it doesn't get a
115
+ # duplicate comment posted in the message_groups loop below
116
+ message_groups.shift
117
+ else
118
+ summary_group = MessageGroup.new(file: nil, line: nil)
119
+ end
120
+
121
+ summary_body += generate_message_group_comment(
122
+ message_group: summary_group,
123
+ danger_id: danger_id,
124
+ template: "bitbucket_server_message_group"
125
+ )
126
+
127
+ @api.post_comment(summary_body)
128
+
129
+ message_groups.each do |message_group|
130
+ body = generate_message_group_comment(message_group: message_group,
131
+ danger_id: danger_id,
132
+ template: "bitbucket_server_message_group")
133
+ @api.post_comment(body,
134
+ file: message_group.file,
135
+ line: message_group.line)
136
+ end
137
+ end
138
+
93
139
  def update_inline_comments_for_kind!(kind, messages, danger_id: "danger")
94
140
  emoji = { warnings: "warning", errors: "no_entry_sign", messages: "book" }[kind]
95
141
 
@@ -6,8 +6,10 @@ module Danger
6
6
  module RequestSources
7
7
  class BitbucketCloudAPI
8
8
  attr_accessor :host, :project, :slug, :access_token, :pull_request_id
9
+ attr_reader :my_uuid
9
10
 
10
11
  def initialize(repo_slug, pull_request_id, branch_name, environment)
12
+ initialize_my_uuid(environment["DANGER_BITBUCKETCLOUD_UUID"])
11
13
  @username = environment["DANGER_BITBUCKETCLOUD_USERNAME"]
12
14
  @password = environment["DANGER_BITBUCKETCLOUD_PASSWORD"]
13
15
  self.project, self.slug = repo_slug.split("/")
@@ -16,6 +18,17 @@ module Danger
16
18
  self.host = "https://bitbucket.org/"
17
19
  end
18
20
 
21
+ def initialize_my_uuid(uuid)
22
+ return if uuid.nil?
23
+ return @my_uuid = uuid if uuid.empty?
24
+
25
+ if uuid.start_with?("{") && uuid.end_with?("}")
26
+ @my_uuid = uuid
27
+ else
28
+ @my_uuid = "{#{uuid}}"
29
+ end
30
+ end
31
+
19
32
  def inspect
20
33
  inspected = super
21
34
 
@@ -27,12 +40,9 @@ module Danger
27
40
  end
28
41
 
29
42
  def credentials_given?
30
- @username && !@username.empty? && @password && !@password.empty?
31
- end
32
-
33
- def my_uuid
34
- uri = URI("https://api.bitbucket.org/2.0/users/#{@username}")
35
- @my_uuid ||= fetch_json(uri)[:uuid]
43
+ @my_uuid && !@my_uuid.empty? &&
44
+ @username && !@username.empty? &&
45
+ @password && !@password.empty?
36
46
  end
37
47
 
38
48
  def pull_request(*)
@@ -157,7 +167,9 @@ module Danger
157
167
  end
158
168
 
159
169
  def credentials_not_available
160
- "Credentials not available. Provide DANGER_BITBUCKETCLOUD_USERNAME and DANGER_BITBUCKETCLOUD_PASSWORD as environment variables."
170
+ "Credentials not available. Provide DANGER_BITBUCKETCLOUD_USERNAME, " \
171
+ "DANGER_BITBUCKETCLOUD_UUID, and DANGER_BITBUCKETCLOUD_PASSWORD " \
172
+ "as environment variables."
161
173
  end
162
174
 
163
175
  def error_fetching_json(url, status_code)
@@ -1,4 +1,4 @@
1
1
  module Danger
2
- VERSION = "6.3.2".freeze
2
+ VERSION = "7.0.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: 6.3.2
4
+ version: 7.0.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-03-26 00:00:00.000000000 Z
12
+ date: 2020-04-16 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: claide
@@ -71,16 +71,22 @@ dependencies:
71
71
  name: faraday
72
72
  requirement: !ruby/object:Gem::Requirement
73
73
  requirements:
74
- - - "~>"
74
+ - - ">="
75
75
  - !ruby/object:Gem::Version
76
- version: '0.9'
76
+ version: 0.9.0
77
+ - - "<"
78
+ - !ruby/object:Gem::Version
79
+ version: '2.0'
77
80
  type: :runtime
78
81
  prerelease: false
79
82
  version_requirements: !ruby/object:Gem::Requirement
80
83
  requirements:
81
- - - "~>"
84
+ - - ">="
82
85
  - !ruby/object:Gem::Version
83
- version: '0.9'
86
+ version: 0.9.0
87
+ - - "<"
88
+ - !ruby/object:Gem::Version
89
+ version: '2.0'
84
90
  - !ruby/object:Gem::Dependency
85
91
  name: faraday-http-cache
86
92
  requirement: !ruby/object:Gem::Requirement
@@ -250,6 +256,7 @@ files:
250
256
  - lib/danger/commands/systems.rb
251
257
  - lib/danger/comment_generators/bitbucket_server.md.erb
252
258
  - lib/danger/comment_generators/bitbucket_server_inline.md.erb
259
+ - lib/danger/comment_generators/bitbucket_server_message_group.md.erb
253
260
  - lib/danger/comment_generators/github.md.erb
254
261
  - lib/danger/comment_generators/github_inline.md.erb
255
262
  - lib/danger/comment_generators/gitlab.md.erb
@@ -283,6 +290,7 @@ files:
283
290
  - lib/danger/helpers/comments_parsing_helper.rb
284
291
  - lib/danger/helpers/emoji_mapper.rb
285
292
  - lib/danger/helpers/find_max_num_violations.rb
293
+ - lib/danger/helpers/message_groups_array_helper.rb
286
294
  - lib/danger/plugin_support/gems_resolver.rb
287
295
  - lib/danger/plugin_support/plugin.rb
288
296
  - lib/danger/plugin_support/plugin_file_resolver.rb