danger 8.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +22 -0
- data/README.md +94 -0
- data/bin/danger +5 -0
- data/lib/assets/DangerfileTemplate +13 -0
- data/lib/danger.rb +44 -0
- data/lib/danger/ci_source/appcenter.rb +55 -0
- data/lib/danger/ci_source/appveyor.rb +60 -0
- data/lib/danger/ci_source/azure_pipelines.rb +44 -0
- data/lib/danger/ci_source/bamboo.rb +41 -0
- data/lib/danger/ci_source/bitbucket_pipelines.rb +37 -0
- data/lib/danger/ci_source/bitrise.rb +65 -0
- data/lib/danger/ci_source/buddybuild.rb +62 -0
- data/lib/danger/ci_source/buildkite.rb +51 -0
- data/lib/danger/ci_source/ci_source.rb +37 -0
- data/lib/danger/ci_source/circle.rb +94 -0
- data/lib/danger/ci_source/circle_api.rb +51 -0
- data/lib/danger/ci_source/cirrus.rb +31 -0
- data/lib/danger/ci_source/code_build.rb +57 -0
- data/lib/danger/ci_source/codefresh.rb +53 -0
- data/lib/danger/ci_source/codeship.rb +44 -0
- data/lib/danger/ci_source/dotci.rb +52 -0
- data/lib/danger/ci_source/drone.rb +71 -0
- data/lib/danger/ci_source/github_actions.rb +43 -0
- data/lib/danger/ci_source/gitlab_ci.rb +86 -0
- data/lib/danger/ci_source/jenkins.rb +149 -0
- data/lib/danger/ci_source/local_git_repo.rb +119 -0
- data/lib/danger/ci_source/local_only_git_repo.rb +47 -0
- data/lib/danger/ci_source/screwdriver.rb +47 -0
- data/lib/danger/ci_source/semaphore.rb +37 -0
- data/lib/danger/ci_source/support/commits.rb +17 -0
- data/lib/danger/ci_source/support/find_repo_info_from_logs.rb +35 -0
- data/lib/danger/ci_source/support/find_repo_info_from_url.rb +42 -0
- data/lib/danger/ci_source/support/local_pull_request.rb +14 -0
- data/lib/danger/ci_source/support/no_pull_request.rb +7 -0
- data/lib/danger/ci_source/support/no_repo_info.rb +5 -0
- data/lib/danger/ci_source/support/pull_request_finder.rb +179 -0
- data/lib/danger/ci_source/support/remote_pull_request.rb +15 -0
- data/lib/danger/ci_source/support/repo_info.rb +10 -0
- data/lib/danger/ci_source/surf.rb +37 -0
- data/lib/danger/ci_source/teamcity.rb +159 -0
- data/lib/danger/ci_source/travis.rb +51 -0
- data/lib/danger/ci_source/vsts.rb +73 -0
- data/lib/danger/ci_source/xcode_server.rb +48 -0
- data/lib/danger/clients/rubygems_client.rb +14 -0
- data/lib/danger/commands/dangerfile/gem.rb +43 -0
- data/lib/danger/commands/dangerfile/init.rb +30 -0
- data/lib/danger/commands/dry_run.rb +54 -0
- data/lib/danger/commands/init.rb +297 -0
- data/lib/danger/commands/init_helpers/interviewer.rb +92 -0
- data/lib/danger/commands/local.rb +83 -0
- data/lib/danger/commands/local_helpers/http_cache.rb +36 -0
- data/lib/danger/commands/local_helpers/local_setup.rb +46 -0
- data/lib/danger/commands/local_helpers/pry_setup.rb +31 -0
- data/lib/danger/commands/plugins/plugin_json.rb +46 -0
- data/lib/danger/commands/plugins/plugin_lint.rb +54 -0
- data/lib/danger/commands/plugins/plugin_readme.rb +45 -0
- data/lib/danger/commands/pr.rb +92 -0
- data/lib/danger/commands/runner.rb +94 -0
- data/lib/danger/commands/staging.rb +53 -0
- data/lib/danger/commands/systems.rb +43 -0
- data/lib/danger/comment_generators/bitbucket_server.md.erb +20 -0
- data/lib/danger/comment_generators/bitbucket_server_inline.md.erb +15 -0
- data/lib/danger/comment_generators/bitbucket_server_message_group.md.erb +12 -0
- data/lib/danger/comment_generators/github.md.erb +55 -0
- data/lib/danger/comment_generators/github_inline.md.erb +26 -0
- data/lib/danger/comment_generators/gitlab.md.erb +40 -0
- data/lib/danger/comment_generators/gitlab_inline.md.erb +26 -0
- data/lib/danger/comment_generators/vsts.md.erb +20 -0
- data/lib/danger/core_ext/file_list.rb +18 -0
- data/lib/danger/core_ext/string.rb +20 -0
- data/lib/danger/danger_core/dangerfile.rb +341 -0
- data/lib/danger/danger_core/dangerfile_dsl.rb +29 -0
- data/lib/danger/danger_core/dangerfile_generator.rb +11 -0
- data/lib/danger/danger_core/environment_manager.rb +123 -0
- data/lib/danger/danger_core/executor.rb +92 -0
- data/lib/danger/danger_core/message_aggregator.rb +49 -0
- data/lib/danger/danger_core/message_group.rb +68 -0
- data/lib/danger/danger_core/messages/base.rb +56 -0
- data/lib/danger/danger_core/messages/markdown.rb +42 -0
- data/lib/danger/danger_core/messages/violation.rb +54 -0
- data/lib/danger/danger_core/plugins/dangerfile_bitbucket_cloud_plugin.rb +144 -0
- data/lib/danger/danger_core/plugins/dangerfile_bitbucket_server_plugin.rb +211 -0
- data/lib/danger/danger_core/plugins/dangerfile_danger_plugin.rb +248 -0
- data/lib/danger/danger_core/plugins/dangerfile_git_plugin.rb +158 -0
- data/lib/danger/danger_core/plugins/dangerfile_github_plugin.rb +254 -0
- data/lib/danger/danger_core/plugins/dangerfile_gitlab_plugin.rb +240 -0
- data/lib/danger/danger_core/plugins/dangerfile_local_only_plugin.rb +42 -0
- data/lib/danger/danger_core/plugins/dangerfile_messaging_plugin.rb +218 -0
- data/lib/danger/danger_core/plugins/dangerfile_vsts_plugin.rb +191 -0
- data/lib/danger/danger_core/standard_error.rb +143 -0
- data/lib/danger/helpers/array_subclass.rb +61 -0
- data/lib/danger/helpers/comment.rb +32 -0
- data/lib/danger/helpers/comments_helper.rb +178 -0
- data/lib/danger/helpers/comments_parsing_helper.rb +70 -0
- data/lib/danger/helpers/emoji_mapper.rb +41 -0
- data/lib/danger/helpers/find_max_num_violations.rb +31 -0
- data/lib/danger/helpers/message_groups_array_helper.rb +31 -0
- data/lib/danger/plugin_support/gems_resolver.rb +77 -0
- data/lib/danger/plugin_support/plugin.rb +49 -0
- data/lib/danger/plugin_support/plugin_file_resolver.rb +30 -0
- data/lib/danger/plugin_support/plugin_linter.rb +161 -0
- data/lib/danger/plugin_support/plugin_parser.rb +199 -0
- data/lib/danger/plugin_support/templates/readme_table.html.erb +26 -0
- data/lib/danger/request_sources/bitbucket_cloud.rb +171 -0
- data/lib/danger/request_sources/bitbucket_cloud_api.rb +181 -0
- data/lib/danger/request_sources/bitbucket_server.rb +105 -0
- data/lib/danger/request_sources/bitbucket_server_api.rb +117 -0
- data/lib/danger/request_sources/github/github.rb +530 -0
- data/lib/danger/request_sources/github/github_review.rb +126 -0
- data/lib/danger/request_sources/github/github_review_resolver.rb +19 -0
- data/lib/danger/request_sources/github/github_review_unsupported.rb +25 -0
- data/lib/danger/request_sources/gitlab.rb +525 -0
- data/lib/danger/request_sources/local_only.rb +53 -0
- data/lib/danger/request_sources/request_source.rb +85 -0
- data/lib/danger/request_sources/support/get_ignored_violation.rb +17 -0
- data/lib/danger/request_sources/vsts.rb +118 -0
- data/lib/danger/request_sources/vsts_api.rb +138 -0
- data/lib/danger/scm_source/git_repo.rb +181 -0
- data/lib/danger/version.rb +4 -0
- metadata +339 -0
@@ -0,0 +1,143 @@
|
|
1
|
+
require "claide"
|
2
|
+
require "claide/informative_error"
|
3
|
+
|
4
|
+
module Danger
|
5
|
+
# From below here - this entire file was taken verbatim for CocoaPods-Core.
|
6
|
+
|
7
|
+
#-------------------------------------------------------------------------#
|
8
|
+
|
9
|
+
# Wraps an exception raised by a DSL file in order to show to the user the
|
10
|
+
# contents of the line that raised the exception.
|
11
|
+
#
|
12
|
+
class DSLError < StandardError
|
13
|
+
# @return [String] the description that should be presented to the user.
|
14
|
+
#
|
15
|
+
attr_reader :description
|
16
|
+
|
17
|
+
# @return [String] the path of the dsl file that raised the exception.
|
18
|
+
#
|
19
|
+
attr_reader :dsl_path
|
20
|
+
|
21
|
+
# @return [Exception] the backtrace of the exception raised by the
|
22
|
+
# evaluation of the dsl file.
|
23
|
+
#
|
24
|
+
attr_reader :backtrace
|
25
|
+
|
26
|
+
# @param [Exception] backtrace @see backtrace
|
27
|
+
# @param [String] dsl_path @see dsl_path
|
28
|
+
#
|
29
|
+
def initialize(description, dsl_path, backtrace, contents = nil)
|
30
|
+
@description = description
|
31
|
+
@dsl_path = dsl_path
|
32
|
+
@backtrace = backtrace
|
33
|
+
@contents = contents
|
34
|
+
end
|
35
|
+
|
36
|
+
# @return [String] the contents of the DSL that cause the exception to
|
37
|
+
# be raised.
|
38
|
+
#
|
39
|
+
def contents
|
40
|
+
@contents ||= begin
|
41
|
+
dsl_path && File.exist?(dsl_path) && File.read(dsl_path)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# The message of the exception reports the content of podspec for the
|
46
|
+
# line that generated the original exception.
|
47
|
+
#
|
48
|
+
# @example Output
|
49
|
+
#
|
50
|
+
# Invalid podspec at `RestKit.podspec` - undefined method
|
51
|
+
# `exclude_header_search_paths=' for #<Pod::Specification for
|
52
|
+
# `RestKit/Network (0.9.3)`>
|
53
|
+
#
|
54
|
+
# from spec-repos/master/RestKit/0.9.3/RestKit.podspec:36
|
55
|
+
# -------------------------------------------
|
56
|
+
# # because it would break: #import <CoreData/CoreData.h>
|
57
|
+
# > ns.exclude_header_search_paths = 'Code/RestKit.h'
|
58
|
+
# end
|
59
|
+
# -------------------------------------------
|
60
|
+
#
|
61
|
+
# @return [String] the message of the exception.
|
62
|
+
#
|
63
|
+
def message
|
64
|
+
@message ||= begin
|
65
|
+
description, stacktrace = parse.values_at(:description, :stacktrace)
|
66
|
+
|
67
|
+
msg = description
|
68
|
+
msg = msg.red if msg.respond_to?(:red)
|
69
|
+
msg << stacktrace if stacktrace
|
70
|
+
msg
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def to_markdown
|
75
|
+
@markdown ||= begin
|
76
|
+
description, stacktrace = parse.values_at(:description, :stacktrace)
|
77
|
+
|
78
|
+
# Highlight failed method in markdown
|
79
|
+
description = description.tr("'", "`")
|
80
|
+
|
81
|
+
# Escape markdown brackets
|
82
|
+
description = description.gsub(/<|>/) { |bracket| "\\#{bracket}" }
|
83
|
+
|
84
|
+
md = "## Danger has errored"
|
85
|
+
md << "#{description}\n"
|
86
|
+
md << "```#{stacktrace}```" if stacktrace
|
87
|
+
|
88
|
+
Markdown.new(md, nil, nil)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
private
|
93
|
+
|
94
|
+
def parse
|
95
|
+
result = {}
|
96
|
+
|
97
|
+
trace_line, description = parse_line_number_from_description
|
98
|
+
latest_version = Danger.danger_outdated?
|
99
|
+
|
100
|
+
result[:description] = "\n[!] #{description}"
|
101
|
+
result[:description] << upgrade_message(latest_version) if latest_version
|
102
|
+
|
103
|
+
return result unless backtrace && dsl_path && contents
|
104
|
+
|
105
|
+
trace_line = backtrace.find { |l| l.include?(dsl_path.to_s) } || trace_line
|
106
|
+
return result unless trace_line
|
107
|
+
line_numer = trace_line.split(":")[1].to_i - 1
|
108
|
+
return result unless line_numer
|
109
|
+
|
110
|
+
lines = contents.lines
|
111
|
+
indent = " # "
|
112
|
+
indicator = indent.tr("#", ">")
|
113
|
+
first_line = line_numer.zero?
|
114
|
+
last_line = (line_numer == (lines.count - 1))
|
115
|
+
|
116
|
+
result[:stacktrace] = "\n"
|
117
|
+
result[:stacktrace] << "#{indent}from #{trace_line.gsub(/:in.*$/, '')}\n"
|
118
|
+
result[:stacktrace] << "#{indent}-------------------------------------------\n"
|
119
|
+
result[:stacktrace] << "#{indent}#{lines[line_numer - 1]}" unless first_line
|
120
|
+
result[:stacktrace] << "#{indicator}#{lines[line_numer]}"
|
121
|
+
result[:stacktrace] << "#{indent}#{lines[line_numer + 1]}" unless last_line
|
122
|
+
result[:stacktrace] << "\n" unless result[:stacktrace].end_with?("\n")
|
123
|
+
result[:stacktrace] << "#{indent}-------------------------------------------\n"
|
124
|
+
|
125
|
+
result
|
126
|
+
end
|
127
|
+
|
128
|
+
def parse_line_number_from_description
|
129
|
+
description = self.description
|
130
|
+
if dsl_path && description =~ /((#{Regexp.quote File.expand_path(dsl_path)}|#{Regexp.quote dsl_path.to_s}):\d+)/
|
131
|
+
trace_line = Regexp.last_match[1]
|
132
|
+
description = description.sub(/#{Regexp.quote trace_line}:\s*/, "")
|
133
|
+
end
|
134
|
+
[trace_line, description]
|
135
|
+
end
|
136
|
+
|
137
|
+
def upgrade_message(latest_version)
|
138
|
+
". Updating the Danger gem might fix the issue. "\
|
139
|
+
"Your Danger version: #{Danger::VERSION}, "\
|
140
|
+
"latest Danger version: #{latest_version}\n"
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module Danger
|
2
|
+
module Helpers
|
3
|
+
module ArraySubclass
|
4
|
+
include Comparable
|
5
|
+
|
6
|
+
def initialize(array)
|
7
|
+
@__array__ = array
|
8
|
+
end
|
9
|
+
|
10
|
+
def kind_of?(compare_class)
|
11
|
+
return true if compare_class == self.class
|
12
|
+
|
13
|
+
dummy.kind_of?(compare_class)
|
14
|
+
end
|
15
|
+
|
16
|
+
def method_missing(name, *args, &block)
|
17
|
+
super unless __array__.respond_to?(name)
|
18
|
+
|
19
|
+
respond_to_method(name, *args, &block)
|
20
|
+
end
|
21
|
+
|
22
|
+
def respond_to_missing?(name)
|
23
|
+
__array__.respond_to?(name) || super
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_a
|
27
|
+
__array__
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_ary
|
31
|
+
__array__
|
32
|
+
end
|
33
|
+
|
34
|
+
def <=>(other)
|
35
|
+
return unless other.kind_of?(self.class)
|
36
|
+
|
37
|
+
__array__ <=> other.instance_variable_get(:@__array__)
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
attr_accessor :__array__
|
43
|
+
|
44
|
+
def dummy
|
45
|
+
Class.new(Array).new
|
46
|
+
end
|
47
|
+
|
48
|
+
def respond_to_method(name, *args, &block)
|
49
|
+
result = __array__.send(name, *args, &block)
|
50
|
+
return result unless result.kind_of?(Array)
|
51
|
+
|
52
|
+
if name =~ /!/
|
53
|
+
__array__ = result
|
54
|
+
self
|
55
|
+
else
|
56
|
+
self.class.new(result)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Danger
|
2
|
+
class Comment
|
3
|
+
attr_reader :id, :body
|
4
|
+
|
5
|
+
def initialize(id, body, inline = nil)
|
6
|
+
@id = id
|
7
|
+
@body = body
|
8
|
+
@inline = inline
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.from_github(comment)
|
12
|
+
self.new(comment["id"], comment["body"])
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.from_gitlab(comment)
|
16
|
+
if comment.respond_to?(:id) && comment.respond_to?(:body)
|
17
|
+
type = comment.respond_to?(:type) ? comment.type : nil
|
18
|
+
self.new(comment.id, comment.body, type == "DiffNote")
|
19
|
+
else
|
20
|
+
self.new(comment["id"], comment["body"], comment["type"] == "DiffNote")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def generated_by_danger?(danger_id)
|
25
|
+
body.include?("\"generated_by_#{danger_id}\"")
|
26
|
+
end
|
27
|
+
|
28
|
+
def inline?
|
29
|
+
@inline.nil? ? body.include?("") : @inline
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,178 @@
|
|
1
|
+
require "kramdown"
|
2
|
+
require "danger/helpers/comments_parsing_helper"
|
3
|
+
require "danger/helpers/emoji_mapper"
|
4
|
+
require "danger/helpers/find_max_num_violations"
|
5
|
+
|
6
|
+
module Danger
|
7
|
+
module Helpers
|
8
|
+
module CommentsHelper
|
9
|
+
# This might be a bit weird, but table_kind_from_title is a shared dependency for
|
10
|
+
# parsing and generating. And rubocop was adamant about file size so...
|
11
|
+
include Danger::Helpers::CommentsParsingHelper
|
12
|
+
|
13
|
+
def markdown_parser(text)
|
14
|
+
Kramdown::Document.new(text, input: "GFM")
|
15
|
+
end
|
16
|
+
|
17
|
+
# !@group Extension points
|
18
|
+
# Produces a markdown link to the file the message points to
|
19
|
+
#
|
20
|
+
# request_source implementations are invited to override this method with their
|
21
|
+
# vendor specific link.
|
22
|
+
#
|
23
|
+
# @param [Violation or Markdown] message
|
24
|
+
# @param [Bool] Should hide any generated link created
|
25
|
+
#
|
26
|
+
# @return [String] The Markdown compatible link
|
27
|
+
def markdown_link_to_message(message, _)
|
28
|
+
"#{message.file}#L#{message.line}"
|
29
|
+
end
|
30
|
+
|
31
|
+
# !@group Extension points
|
32
|
+
# Determine whether two messages are equivalent
|
33
|
+
#
|
34
|
+
# request_source implementations are invited to override this method.
|
35
|
+
# This is mostly here to enable sources to detect when inlines change only in their
|
36
|
+
# commit hash and not in content per-se. since the link is implementation dependant
|
37
|
+
# so should be the comparison.
|
38
|
+
#
|
39
|
+
# @param [Violation or Markdown] m1
|
40
|
+
# @param [Violation or Markdown] m2
|
41
|
+
#
|
42
|
+
# @return [Boolean] whether they represent the same message
|
43
|
+
def messages_are_equivalent(m1, m2)
|
44
|
+
m1 == m2
|
45
|
+
end
|
46
|
+
|
47
|
+
def process_markdown(violation, hide_link = false)
|
48
|
+
message = violation.message
|
49
|
+
message = "#{markdown_link_to_message(violation, hide_link)}#{message}" if violation.file && violation.line
|
50
|
+
|
51
|
+
html = markdown_parser(message).to_html
|
52
|
+
# Remove the outer `<p>` and `</p>`.
|
53
|
+
html = html.strip.sub(%r{\A<p>(.*)</p>\z}m, '\1')
|
54
|
+
Violation.new(html, violation.sticky, violation.file, violation.line)
|
55
|
+
end
|
56
|
+
|
57
|
+
def table(name, emoji, violations, all_previous_violations, template: "github")
|
58
|
+
content = violations
|
59
|
+
content = content.map { |v| process_markdown(v) } unless ["bitbucket_server", "vsts"].include?(template)
|
60
|
+
|
61
|
+
kind = table_kind_from_title(name)
|
62
|
+
previous_violations = all_previous_violations[kind] || []
|
63
|
+
resolved_violations = previous_violations.reject do |pv|
|
64
|
+
content.count { |v| messages_are_equivalent(v, pv) } > 0
|
65
|
+
end
|
66
|
+
|
67
|
+
resolved_messages = resolved_violations.map(&:message).uniq
|
68
|
+
count = content.count
|
69
|
+
|
70
|
+
{
|
71
|
+
name: name,
|
72
|
+
emoji: emoji,
|
73
|
+
content: content,
|
74
|
+
resolved: resolved_messages,
|
75
|
+
count: count
|
76
|
+
}
|
77
|
+
end
|
78
|
+
|
79
|
+
def apply_template(tables: [], markdowns: [], danger_id: "danger", template: "github", request_source: template)
|
80
|
+
require "erb"
|
81
|
+
|
82
|
+
md_template = File.join(Danger.gem_path, "lib/danger/comment_generators/#{template}.md.erb")
|
83
|
+
|
84
|
+
# erb: http://www.rrn.dk/rubys-erb-templating-system
|
85
|
+
# for the extra args: http://stackoverflow.com/questions/4632879/erb-template-removing-the-trailing-line
|
86
|
+
@tables = tables
|
87
|
+
@markdowns = markdowns.map(&:message)
|
88
|
+
@danger_id = danger_id
|
89
|
+
@emoji_mapper = EmojiMapper.new(request_source.sub("_inline",""))
|
90
|
+
|
91
|
+
return ERB.new(File.read(md_template), 0, "-").result(binding)
|
92
|
+
end
|
93
|
+
|
94
|
+
def generate_comment(warnings: [], errors: [], messages: [], markdowns: [], previous_violations: {}, danger_id: "danger", template: "github")
|
95
|
+
apply_template(
|
96
|
+
tables: [
|
97
|
+
table("Error", "no_entry_sign", errors, previous_violations, template: template),
|
98
|
+
table("Warning", "warning", warnings, previous_violations, template: template),
|
99
|
+
table("Message", "book", messages, previous_violations, template: template)
|
100
|
+
],
|
101
|
+
markdowns: markdowns,
|
102
|
+
danger_id: danger_id,
|
103
|
+
template: template
|
104
|
+
)
|
105
|
+
end
|
106
|
+
|
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: false,
|
132
|
+
template: "github")
|
133
|
+
apply_template(
|
134
|
+
tables: [{ content: [message], resolved: resolved, emoji: emoji }],
|
135
|
+
danger_id: danger_id,
|
136
|
+
template: "#{template}_inline"
|
137
|
+
)
|
138
|
+
end
|
139
|
+
|
140
|
+
def generate_inline_markdown_body(markdown, danger_id: "danger", template: "github")
|
141
|
+
apply_template(
|
142
|
+
markdowns: [markdown],
|
143
|
+
danger_id: danger_id,
|
144
|
+
template: "#{template}_inline"
|
145
|
+
)
|
146
|
+
end
|
147
|
+
|
148
|
+
def generate_description(warnings: nil, errors: nil, template: "github")
|
149
|
+
emoji_mapper = EmojiMapper.new(template)
|
150
|
+
if errors.empty? && warnings.empty?
|
151
|
+
return "All green. #{random_compliment}"
|
152
|
+
else
|
153
|
+
message = "#{emoji_mapper.map('warning')} "
|
154
|
+
message += "#{'Error'.danger_pluralize(errors.count)}. " unless errors.empty?
|
155
|
+
message += "#{'Warning'.danger_pluralize(warnings.count)}. " unless warnings.empty?
|
156
|
+
message += "Don't worry, everything is fixable."
|
157
|
+
return message
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
def random_compliment
|
162
|
+
["Well done.", "Congrats.", "Woo!",
|
163
|
+
"Yay.", "Jolly good show.", "Good on 'ya.", "Nice work."].sample
|
164
|
+
end
|
165
|
+
|
166
|
+
private
|
167
|
+
|
168
|
+
def pluralize(string, count)
|
169
|
+
string.danger_pluralize(count)
|
170
|
+
end
|
171
|
+
|
172
|
+
def truncate(string)
|
173
|
+
max_message_length = 30
|
174
|
+
string.danger_truncate(max_message_length)
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
module Danger
|
2
|
+
module Helpers
|
3
|
+
module CommentsParsingHelper
|
4
|
+
# !@group Extension points
|
5
|
+
# Produces a message-like from a row in a comment table
|
6
|
+
#
|
7
|
+
# @param [String] row
|
8
|
+
# The content of the row in the table
|
9
|
+
#
|
10
|
+
# @return [Violation or Markdown] the extracted message
|
11
|
+
def parse_message_from_row(row)
|
12
|
+
Violation.new(row, true)
|
13
|
+
end
|
14
|
+
|
15
|
+
def parse_tables_from_comment(comment)
|
16
|
+
comment.split("</table>")
|
17
|
+
end
|
18
|
+
|
19
|
+
def violations_from_table(table)
|
20
|
+
row_regex = %r{<td data-sticky="true">(?:<del>)?(.*?)(?:</del>)?\s*</td>}im
|
21
|
+
table.scan(row_regex).flatten.map do |row|
|
22
|
+
parse_message_from_row(row.strip)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def parse_comment(comment)
|
27
|
+
tables = parse_tables_from_comment(comment)
|
28
|
+
violations = {}
|
29
|
+
tables.each do |table|
|
30
|
+
match = danger_table?(table)
|
31
|
+
next unless match
|
32
|
+
title = match[1]
|
33
|
+
kind = table_kind_from_title(title)
|
34
|
+
next unless kind
|
35
|
+
|
36
|
+
violations[kind] = violations_from_table(table)
|
37
|
+
end
|
38
|
+
|
39
|
+
violations.reject { |_, v| v.empty? }
|
40
|
+
end
|
41
|
+
|
42
|
+
def table_kind_from_title(title)
|
43
|
+
if title =~ /error/i
|
44
|
+
:error
|
45
|
+
elsif title =~ /warning/i
|
46
|
+
:warning
|
47
|
+
elsif title =~ /message/i
|
48
|
+
:message
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
GITHUB_OLD_REGEX = %r{<th width="100%"(.*?)</th>}im
|
55
|
+
NEW_REGEX = %r{<th.*data-danger-table="true"(.*?)</th>}im
|
56
|
+
|
57
|
+
def danger_table?(table)
|
58
|
+
# The old GitHub specific method relied on
|
59
|
+
# the width of a `th` element to find the table
|
60
|
+
# title and determine if it was a danger table.
|
61
|
+
# The new method uses a more robust data-danger-table
|
62
|
+
# tag instead.
|
63
|
+
match = GITHUB_OLD_REGEX.match(table)
|
64
|
+
return match if match
|
65
|
+
|
66
|
+
return NEW_REGEX.match(table)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|