danger 8.0.4
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 +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 +161 -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,53 @@
|
|
1
|
+
require "danger/commands/local_helpers/pry_setup"
|
2
|
+
require "fileutils"
|
3
|
+
require "tmpdir"
|
4
|
+
|
5
|
+
module Danger
|
6
|
+
class Staging < Runner
|
7
|
+
self.summary = "Run the Dangerfile locally against local master"
|
8
|
+
self.command = "staging"
|
9
|
+
|
10
|
+
def self.options
|
11
|
+
[
|
12
|
+
["--pry", "Drop into a Pry shell after evaluating the Dangerfile."]
|
13
|
+
]
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(argv)
|
17
|
+
show_help = true if argv.arguments == ["-h"]
|
18
|
+
|
19
|
+
# Currently CLAide doesn't support short option like -h https://github.com/CocoaPods/CLAide/pull/60
|
20
|
+
# when user pass in -h, mimic the behavior of passing in --help.
|
21
|
+
argv = CLAide::ARGV.new ["--help"] if show_help
|
22
|
+
|
23
|
+
super
|
24
|
+
|
25
|
+
if argv.flag?("pry", false)
|
26
|
+
@dangerfile_path = PrySetup.new(cork).setup_pry(@dangerfile_path)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def validate!
|
31
|
+
super
|
32
|
+
unless @dangerfile_path
|
33
|
+
help! "Could not find a Dangerfile."
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def run
|
38
|
+
ENV["DANGER_USE_LOCAL_ONLY_GIT"] = "YES"
|
39
|
+
|
40
|
+
env = EnvironmentManager.new(ENV, cork)
|
41
|
+
dm = Dangerfile.new(env, cork)
|
42
|
+
|
43
|
+
dm.run(
|
44
|
+
Danger::EnvironmentManager.danger_base_branch,
|
45
|
+
Danger::EnvironmentManager.danger_head_branch,
|
46
|
+
@dangerfile_path,
|
47
|
+
nil,
|
48
|
+
nil,
|
49
|
+
nil
|
50
|
+
)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Danger
|
2
|
+
class Systems < Runner
|
3
|
+
self.abstract_command = true
|
4
|
+
self.description = "For commands related to passing information from Danger to Danger.Systems."
|
5
|
+
self.summary = "Create data for Danger.Systems."
|
6
|
+
end
|
7
|
+
|
8
|
+
class CIDocs < Systems
|
9
|
+
self.command = "ci_docs"
|
10
|
+
self.summary = "Outputs the up-to-date CI documentation for Danger."
|
11
|
+
|
12
|
+
def run
|
13
|
+
here = File.dirname(__FILE__)
|
14
|
+
ci_source_paths = Dir.glob(here + "/../ci_source/*.rb")
|
15
|
+
|
16
|
+
require "yard"
|
17
|
+
# Pull out all the Danger::CI subclasses docs
|
18
|
+
registry = YARD::Registry.load(ci_source_paths, true)
|
19
|
+
ci_sources = begin
|
20
|
+
registry.all(:class)
|
21
|
+
.select { |klass| klass.inheritance_tree.map(&:name).include? :CI }
|
22
|
+
.reject { |source| source.name == :CI }
|
23
|
+
.reject { |source| source.name == :LocalGitRepo }
|
24
|
+
end
|
25
|
+
|
26
|
+
# Fail if anything is added and not documented
|
27
|
+
cis_without_docs = ci_sources.select { |source| source.base_docstring.empty? }
|
28
|
+
unless cis_without_docs.empty?
|
29
|
+
cork.puts "Please add docs to: #{cis_without_docs.map(&:name).join(', ')}"
|
30
|
+
abort("Failed.".red)
|
31
|
+
end
|
32
|
+
|
33
|
+
# Output a JSON array of name and details
|
34
|
+
require "json"
|
35
|
+
cork.puts ci_sources.map { |ci|
|
36
|
+
{
|
37
|
+
name: ci.name,
|
38
|
+
docs: ci.docstring
|
39
|
+
}
|
40
|
+
}.to_json
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
<%- @tables.each do |table| -%>
|
2
|
+
<%- if table[:content].any? || table[:resolved].any? -%>
|
3
|
+
| | <%= table[:count] %> <%= table[:name] %><%= "s" unless table[:count] == 1 %> |
|
4
|
+
|---|---|
|
5
|
+
<%- table[:content].each do |violation| -%>
|
6
|
+
| <%= @emoji_mapper.map(table[:emoji]) %> | <%= violation.message %> |
|
7
|
+
<%- end -%>
|
8
|
+
<%- table[:resolved].each do |message| -%>
|
9
|
+
| @emoji_mapper.map("white_check_mark") | <%= message %> |
|
10
|
+
<%- end -%>
|
11
|
+
|
12
|
+
<%- end -%>
|
13
|
+
<%- end -%>
|
14
|
+
|
15
|
+
<%- @markdowns.each do |current| -%>
|
16
|
+
<%= current %>
|
17
|
+
<%# the previous line has to be aligned far to the left, otherwise markdown can break easily %>
|
18
|
+
<%- end -%>
|
19
|
+
|
20
|
+
Generated by :no_entry_sign: [Danger](https://danger.systems/ "generated_by_<%= @danger_id %>")
|
@@ -0,0 +1,15 @@
|
|
1
|
+
<%- @tables.each do |table| -%>
|
2
|
+
<%- table[:content].each do |violation| -%>
|
3
|
+
<%= @emoji_mapper.map(table[:emoji]) if table[:emoji] %> <%= violation.message %>
|
4
|
+
<%- end -%>
|
5
|
+
<%- table[:resolved] && table[:resolved].each do |message| -%>
|
6
|
+
<%= @emoji_mapper.map("white_check_mark") %> <%= message %>
|
7
|
+
<%- end -%>
|
8
|
+
<%- end -%>
|
9
|
+
|
10
|
+
<%- @markdowns.each do |current| -%>
|
11
|
+
<%= current %>
|
12
|
+
<%# the previous line has to be aligned far to the left, otherwise markdown can break easily %>
|
13
|
+
<%- end -%>
|
14
|
+
|
15
|
+
Generated by :no_entry_sign: [Danger](https://danger.systems/ "generated_by_<%= @danger_id %>")
|
@@ -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 %>")
|
@@ -0,0 +1,55 @@
|
|
1
|
+
<!--
|
2
|
+
<%- @tables.each do |table| -%>
|
3
|
+
<%= pluralize(table[:name], table[:count]) %><%= ": #{truncate(table[:content].first.message)}" if table[:count] > 0 %>
|
4
|
+
<%- end -%>
|
5
|
+
<%= pluralize("Markdown", @markdowns.size) %>
|
6
|
+
-->
|
7
|
+
<%- @tables.each do |table| -%>
|
8
|
+
<%- if table[:content].any? || table[:resolved].any? -%>
|
9
|
+
<table>
|
10
|
+
<thead>
|
11
|
+
<tr>
|
12
|
+
<th width="50"></th>
|
13
|
+
<th width="100%" data-danger-table="true" data-kind="<%= table[:name] %>">
|
14
|
+
<%- if table[:count] > 0 -%>
|
15
|
+
<%= pluralize(table[:name], table[:count]) %>
|
16
|
+
<%- else -%>
|
17
|
+
:white_check_mark: <%= random_compliment %>
|
18
|
+
<%- end -%>
|
19
|
+
</th>
|
20
|
+
</tr>
|
21
|
+
</thead>
|
22
|
+
<tbody>
|
23
|
+
<%- max_num_violations = FindMaxNumViolations.new(table[:content]).call -%>
|
24
|
+
<%- table[:content].take(max_num_violations).each do |violation| -%>
|
25
|
+
<tr>
|
26
|
+
<td>:<%= table[:emoji] %>:</td>
|
27
|
+
<td data-sticky="<%= violation.sticky %>"><%= violation.message %></td>
|
28
|
+
</tr>
|
29
|
+
<%- end -%>
|
30
|
+
<%- if table[:content].length > max_num_violations -%>
|
31
|
+
<tr>
|
32
|
+
<td>:warning:</td>
|
33
|
+
<td>
|
34
|
+
Danger found <%= table[:content].length %> violations with this PR. Due to GitHub's max issue comment size, the number shown has been truncated to <%= max_num_violations %>.
|
35
|
+
</td>
|
36
|
+
</tr>
|
37
|
+
<%- end -%>
|
38
|
+
<%- table[:resolved].each do |message| -%>
|
39
|
+
<tr>
|
40
|
+
<td>:white_check_mark:</td>
|
41
|
+
<td data-sticky="true"><del><%= message %></del></td>
|
42
|
+
</tr>
|
43
|
+
<%- end -%>
|
44
|
+
</tbody>
|
45
|
+
</table>
|
46
|
+
<%- end -%>
|
47
|
+
<%- end -%>
|
48
|
+
|
49
|
+
<%- @markdowns.each do |current| -%>
|
50
|
+
<%= current %>
|
51
|
+
<%# the previous line has to be aligned far to the left, otherwise markdown can break easily %>
|
52
|
+
<%- end -%>
|
53
|
+
<p align="right" data-meta="generated_by_<%= @danger_id %>">
|
54
|
+
Generated by :no_entry_sign: <a href="https://danger.systems/">Danger</a>
|
55
|
+
</p>
|
@@ -0,0 +1,26 @@
|
|
1
|
+
<%- @tables.each do |table| -%>
|
2
|
+
<%- if table[:content].any? -%>
|
3
|
+
<table data-meta="generated_by_<%= @danger_id %>">
|
4
|
+
<tbody>
|
5
|
+
<%- table[:content].each do |violation| -%>
|
6
|
+
<tr>
|
7
|
+
<td>:<%= table[:emoji] %>:</td>
|
8
|
+
<td width="100%" data-sticky="<%= violation.sticky %>"><%= "<del>" if table[:resolved] %><%= violation.message %><%= "</del>" if table[:resolved] %></td>
|
9
|
+
</tr>
|
10
|
+
<%- end -%>
|
11
|
+
</tbody>
|
12
|
+
</table>
|
13
|
+
<%- end -%>
|
14
|
+
<%- end -%>
|
15
|
+
|
16
|
+
<%- @markdowns.each do |current| -%>
|
17
|
+
<%= current %>
|
18
|
+
<%# the previous line has to be aligned far to the left, otherwise markdown can break easily %>
|
19
|
+
<%- end -%>
|
20
|
+
<%# We need to add the generated_by_ to identify comments from danger. But with inlines %>
|
21
|
+
<%# it might be a little annoying, so we set on the table, but if we have markdown we add the footer anyway %>
|
22
|
+
<%- if @markdowns.count > 0 -%>
|
23
|
+
<p align="right" data-meta="generated_by_<%= @danger_id %>">
|
24
|
+
Generated by :no_entry_sign: <a href="http://danger.systems/">Danger</a>
|
25
|
+
</p>
|
26
|
+
<%- end -%>
|
@@ -0,0 +1,40 @@
|
|
1
|
+
<%- @tables.each do |table| -%>
|
2
|
+
<%- if table[:content].any? || table[:resolved].any? -%>
|
3
|
+
<table>
|
4
|
+
<thead>
|
5
|
+
<tr>
|
6
|
+
<th width="5%"></th>
|
7
|
+
<th width="95%" data-danger-table="true" data-kind="<%= table[:name] %>">
|
8
|
+
<%- if table[:count] > 0 -%>
|
9
|
+
<%= table[:count] %> <%= table[:name] %><%= "s" unless table[:count] == 1 %>
|
10
|
+
<%- else -%>
|
11
|
+
:white_check_mark: <%= random_compliment %>
|
12
|
+
<%- end -%>
|
13
|
+
</th>
|
14
|
+
</tr>
|
15
|
+
</thead>
|
16
|
+
<tbody>
|
17
|
+
<%- table[:content].each do |violation| -%>
|
18
|
+
<tr>
|
19
|
+
<td>:<%= table[:emoji] %>:</td>
|
20
|
+
<td data-sticky="<%= violation.sticky %>"><%= violation.message %></td>
|
21
|
+
</tr>
|
22
|
+
<%- end -%>
|
23
|
+
<%- table[:resolved].each do |message| -%>
|
24
|
+
<tr>
|
25
|
+
<td>:white_check_mark:</td>
|
26
|
+
<td data-sticky="true"><del><%= message %></del></td>
|
27
|
+
</tr>
|
28
|
+
<%- end -%>
|
29
|
+
</tbody>
|
30
|
+
</table>
|
31
|
+
<%- end -%>
|
32
|
+
<%- end -%>
|
33
|
+
|
34
|
+
<%- @markdowns.each do |current| -%>
|
35
|
+
<%= current %>
|
36
|
+
<%# the previous line has to be aligned far to the left, otherwise markdown can break easily %>
|
37
|
+
<%- end -%>
|
38
|
+
<p align="right" data-meta="generated_by_<%= @danger_id %>">
|
39
|
+
Generated by :no_entry_sign: <a href="https://github.com/danger/danger/">Danger</a>
|
40
|
+
</p>
|
@@ -0,0 +1,26 @@
|
|
1
|
+
<%- @tables.each do |table| -%>
|
2
|
+
<%- if table[:content].any? -%>
|
3
|
+
<table data-meta="generated_by_<%= @danger_id %>">
|
4
|
+
<tbody>
|
5
|
+
<%- table[:content].each do |violation| -%>
|
6
|
+
<tr>
|
7
|
+
<td>:<%= table[:emoji] %>:</td>
|
8
|
+
<td width="100%" data-sticky="<%= violation.sticky %>"><%= "<del>" if table[:resolved] %><%= violation.message %><%= "</del>" if table[:resolved] %></td>
|
9
|
+
</tr>
|
10
|
+
<%- end -%>
|
11
|
+
</tbody>
|
12
|
+
</table>
|
13
|
+
<%- end -%>
|
14
|
+
<%- end -%>
|
15
|
+
|
16
|
+
<%- @markdowns.each do |current| -%>
|
17
|
+
<%= current %>
|
18
|
+
<%# the previous line has to be aligned far to the left, otherwise markdown can break easily %>
|
19
|
+
<%- end -%>
|
20
|
+
<%# We need to add the generated_by_ to identify comments from danger. But with inlines %>
|
21
|
+
<%# it might be a little annoying, so we set on the table, but if we have markdown we add the footer anyway %>
|
22
|
+
<%- if @markdowns.count > 0 -%>
|
23
|
+
<p align="right" data-meta="generated_by_<%= @danger_id %>">
|
24
|
+
Generated by :no_entry_sign: <a href="http://danger.systems/">Danger</a>
|
25
|
+
</p>
|
26
|
+
<%- end -%>
|
@@ -0,0 +1,20 @@
|
|
1
|
+
<%- @tables.each do |table| -%>
|
2
|
+
<%- if table[:content].any? || table[:resolved].any? -%>
|
3
|
+
| | <%= table[:count] %> <%= table[:name] %><%= "s" unless table[:count] == 1 %> |
|
4
|
+
|---|---|
|
5
|
+
<%- table[:content].each do |violation| -%>
|
6
|
+
| <%= @emoji_mapper.map(table[:emoji]) %> | <%= violation.message %> |
|
7
|
+
<%- end -%>
|
8
|
+
<%- table[:resolved].each do |message| -%>
|
9
|
+
| @emoji_mapper.map("white_check_mark") | <%= message %> |
|
10
|
+
<%- end -%>
|
11
|
+
|
12
|
+
<%- end -%>
|
13
|
+
<%- end -%>
|
14
|
+
|
15
|
+
<%- @markdowns.each do |current| -%>
|
16
|
+
<%= current %>
|
17
|
+
<%# the previous line has to be aligned far to the left, otherwise markdown can break easily %>
|
18
|
+
<%- end -%>
|
19
|
+
|
20
|
+
Generated by :no_entry_sign: [Danger](https://danger.systems/ "generated_by_<%= @danger_id %>")
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require "danger/helpers/array_subclass"
|
2
|
+
|
3
|
+
module Danger
|
4
|
+
class FileList
|
5
|
+
include Helpers::ArraySubclass
|
6
|
+
|
7
|
+
# Information about pattern: http://ruby-doc.org/core-2.2.0/File.html#method-c-fnmatch
|
8
|
+
# e.g. "**/something.*" for any file called something with any extension
|
9
|
+
def include?(pattern)
|
10
|
+
self.each do |current|
|
11
|
+
unless current.nil?
|
12
|
+
return true if File.fnmatch(pattern, current) || pattern == current
|
13
|
+
end
|
14
|
+
end
|
15
|
+
return false
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class String
|
2
|
+
# @return [String] the plural form of self determined by count
|
3
|
+
def danger_pluralize(count)
|
4
|
+
"#{count} #{self}#{'s' unless count == 1}"
|
5
|
+
end
|
6
|
+
|
7
|
+
# @return [String] converts to underscored, lowercase form
|
8
|
+
def danger_underscore
|
9
|
+
self.gsub(/::/, "/".freeze).
|
10
|
+
gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2'.freeze).
|
11
|
+
gsub(/([a-z\d])([A-Z])/, '\1_\2'.freeze).
|
12
|
+
tr("-".freeze, "_".freeze).
|
13
|
+
downcase
|
14
|
+
end
|
15
|
+
|
16
|
+
# @return [String] truncates string with ellipsis when exceeding the limit
|
17
|
+
def danger_truncate(limit)
|
18
|
+
length > limit ? "#{self[0...limit]}..." : self
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,341 @@
|
|
1
|
+
# So much was ripped direct from CocoaPods-Core - thanks!
|
2
|
+
|
3
|
+
require "danger/danger_core/dangerfile_dsl"
|
4
|
+
require "danger/danger_core/standard_error"
|
5
|
+
require "danger/danger_core/message_aggregator"
|
6
|
+
|
7
|
+
require "danger/danger_core/plugins/dangerfile_messaging_plugin"
|
8
|
+
require "danger/danger_core/plugins/dangerfile_danger_plugin"
|
9
|
+
require "danger/danger_core/plugins/dangerfile_git_plugin"
|
10
|
+
require "danger/danger_core/plugins/dangerfile_github_plugin"
|
11
|
+
require "danger/danger_core/plugins/dangerfile_gitlab_plugin"
|
12
|
+
require "danger/danger_core/plugins/dangerfile_bitbucket_server_plugin"
|
13
|
+
require "danger/danger_core/plugins/dangerfile_bitbucket_cloud_plugin"
|
14
|
+
require "danger/danger_core/plugins/dangerfile_vsts_plugin"
|
15
|
+
require "danger/danger_core/plugins/dangerfile_local_only_plugin"
|
16
|
+
|
17
|
+
module Danger
|
18
|
+
class Dangerfile
|
19
|
+
include Danger::Dangerfile::DSL
|
20
|
+
|
21
|
+
attr_accessor :env, :verbose, :plugins, :ui
|
22
|
+
|
23
|
+
# @return [Pathname] the path where the Dangerfile was loaded from. It is nil
|
24
|
+
# if the Dangerfile was generated programmatically.
|
25
|
+
#
|
26
|
+
attr_accessor :defined_in_file
|
27
|
+
|
28
|
+
# @return [String] a string useful to represent the Dangerfile in a message
|
29
|
+
# presented to the user.
|
30
|
+
#
|
31
|
+
def to_s
|
32
|
+
"Dangerfile"
|
33
|
+
end
|
34
|
+
|
35
|
+
# These are the classes that are allowed to also use method_missing
|
36
|
+
# in order to provide broader plugin support
|
37
|
+
def self.core_plugin_classes
|
38
|
+
[DangerfileMessagingPlugin]
|
39
|
+
end
|
40
|
+
|
41
|
+
# The ones that everything would break without
|
42
|
+
def self.essential_plugin_classes
|
43
|
+
[DangerfileMessagingPlugin, DangerfileGitPlugin, DangerfileDangerPlugin, DangerfileGitHubPlugin, DangerfileGitLabPlugin, DangerfileBitbucketServerPlugin, DangerfileBitbucketCloudPlugin, DangerfileVSTSPlugin, DangerfileLocalOnlyPlugin]
|
44
|
+
end
|
45
|
+
|
46
|
+
# Both of these methods exist on all objects
|
47
|
+
# http://ruby-doc.org/core-2.2.3/Kernel.html#method-i-warn
|
48
|
+
# http://ruby-doc.org/core-2.2.3/Kernel.html#method-i-fail
|
49
|
+
# However, as we're using using them in the DSL, they won't
|
50
|
+
# get method_missing called correctly without overriding them.
|
51
|
+
|
52
|
+
def warn(*args, &blk)
|
53
|
+
method_missing(:warn, *args, &blk)
|
54
|
+
end
|
55
|
+
|
56
|
+
def fail(*args, &blk)
|
57
|
+
method_missing(:fail, *args, &blk)
|
58
|
+
end
|
59
|
+
|
60
|
+
# When an undefined method is called, we check to see if it's something
|
61
|
+
# that the core DSLs have, then starts looking at plugins support.
|
62
|
+
|
63
|
+
# rubocop:disable Style/MethodMissing
|
64
|
+
def method_missing(method_sym, *arguments, &_block)
|
65
|
+
@core_plugins.each do |plugin|
|
66
|
+
if plugin.public_methods(false).include?(method_sym)
|
67
|
+
return plugin.send(method_sym, *arguments)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
super
|
71
|
+
end
|
72
|
+
|
73
|
+
# cork_board not being set comes from plugins #585
|
74
|
+
def initialize(env_manager, cork_board = nil)
|
75
|
+
@plugins = {}
|
76
|
+
@core_plugins = []
|
77
|
+
@ui = cork_board || Cork::Board.new(silent: false, verbose: false)
|
78
|
+
|
79
|
+
# Triggers the core plugins
|
80
|
+
@env = env_manager
|
81
|
+
|
82
|
+
# Triggers local plugins from the root of a project
|
83
|
+
Dir["./danger_plugins/*.rb"].each do |file|
|
84
|
+
require File.expand_path(file)
|
85
|
+
end
|
86
|
+
|
87
|
+
refresh_plugins if env_manager.pr?
|
88
|
+
end
|
89
|
+
|
90
|
+
# Iterate through available plugin classes and initialize them with
|
91
|
+
# a reference to this Dangerfile
|
92
|
+
def refresh_plugins
|
93
|
+
plugins = Plugin.all_plugins
|
94
|
+
plugins.each do |klass|
|
95
|
+
next if klass.respond_to?(:singleton_class?) && klass.singleton_class?
|
96
|
+
plugin = klass.new(self)
|
97
|
+
next if plugin.nil? || @plugins[klass]
|
98
|
+
|
99
|
+
name = plugin.class.instance_name
|
100
|
+
self.class.send(:attr_reader, name)
|
101
|
+
instance_variable_set("@#{name}", plugin)
|
102
|
+
|
103
|
+
@plugins[klass] = plugin
|
104
|
+
@core_plugins << plugin if self.class.core_plugin_classes.include? klass
|
105
|
+
end
|
106
|
+
end
|
107
|
+
alias init_plugins refresh_plugins
|
108
|
+
|
109
|
+
def core_dsl_attributes
|
110
|
+
@core_plugins.map { |plugin| { plugin: plugin, methods: plugin.public_methods(false) } }
|
111
|
+
end
|
112
|
+
|
113
|
+
def external_dsl_attributes
|
114
|
+
plugins.values.reject { |plugin| @core_plugins.include? plugin } .map { |plugin| { plugin: plugin, methods: plugin.public_methods(false) } }
|
115
|
+
end
|
116
|
+
|
117
|
+
def method_values_for_plugin_hashes(plugin_hashes)
|
118
|
+
plugin_hashes.flat_map do |plugin_hash|
|
119
|
+
plugin = plugin_hash[:plugin]
|
120
|
+
methods = plugin_hash[:methods].select { |name| plugin.method(name).parameters.empty? }
|
121
|
+
|
122
|
+
methods.map do |method|
|
123
|
+
case method
|
124
|
+
when :api
|
125
|
+
value = "Octokit::Client"
|
126
|
+
|
127
|
+
when :pr_json, :mr_json
|
128
|
+
value = "[Skipped JSON]"
|
129
|
+
|
130
|
+
when :pr_diff, :mr_diff
|
131
|
+
value = "[Skipped Diff]"
|
132
|
+
|
133
|
+
else
|
134
|
+
value = plugin.send(method)
|
135
|
+
value = wrap_text(value.encode("utf-8")) if value.kind_of?(String)
|
136
|
+
# So that we either have one value per row
|
137
|
+
# or we have [] for an empty array
|
138
|
+
value = value.join("\n") if value.kind_of?(Array) && value.count > 0
|
139
|
+
end
|
140
|
+
|
141
|
+
[method.to_s, value]
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
# Iterates through the DSL's attributes, and table's the output
|
147
|
+
def print_known_info
|
148
|
+
rows = []
|
149
|
+
rows += method_values_for_plugin_hashes(core_dsl_attributes)
|
150
|
+
rows << ["---", "---"]
|
151
|
+
rows += method_values_for_plugin_hashes(external_dsl_attributes)
|
152
|
+
rows << ["---", "---"]
|
153
|
+
rows << ["SCM", env.scm.class]
|
154
|
+
rows << ["Source", env.ci_source.class]
|
155
|
+
rows << ["Requests", env.request_source.class]
|
156
|
+
rows << ["Base Commit", env.meta_info_for_base]
|
157
|
+
rows << ["Head Commit", env.meta_info_for_head]
|
158
|
+
|
159
|
+
params = {}
|
160
|
+
params[:rows] = rows.each { |current| current[0] = current[0].yellow }
|
161
|
+
params[:title] = "Danger v#{Danger::VERSION}\nDSL Attributes".green
|
162
|
+
|
163
|
+
ui.section("Info:") do
|
164
|
+
ui.puts
|
165
|
+
table = Terminal::Table.new(params)
|
166
|
+
table.align_column(0, :right)
|
167
|
+
ui.puts table
|
168
|
+
ui.puts
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
# Parses the file at a path, optionally takes the content of the file for DI
|
173
|
+
#
|
174
|
+
def parse(path, contents = nil)
|
175
|
+
print_known_info if verbose
|
176
|
+
|
177
|
+
contents ||= File.open(path, "r:utf-8", &:read)
|
178
|
+
|
179
|
+
# Work around for Rubinius incomplete encoding in 1.9 mode
|
180
|
+
if contents.respond_to?(:encoding) && contents.encoding.name != "UTF-8"
|
181
|
+
contents.encode!("UTF-8")
|
182
|
+
end
|
183
|
+
|
184
|
+
if contents.tr!("“”‘’‛", %(""'''))
|
185
|
+
# Changes have been made
|
186
|
+
ui.puts "Your #{path.basename} has had smart quotes sanitised. " \
|
187
|
+
"To avoid issues in the future, you should not use " \
|
188
|
+
"TextEdit for editing it. If you are not using TextEdit, " \
|
189
|
+
"you should turn off smart quotes in your editor of choice.".red
|
190
|
+
end
|
191
|
+
|
192
|
+
if contents.include?("puts")
|
193
|
+
ui.puts "You used `puts` in your Dangerfile. To print out text to GitHub use `message` instead"
|
194
|
+
end
|
195
|
+
|
196
|
+
self.defined_in_file = path
|
197
|
+
instance_eval do
|
198
|
+
# rubocop:disable Lint/RescueException
|
199
|
+
begin
|
200
|
+
eval_file(contents, path)
|
201
|
+
rescue Exception => e
|
202
|
+
message = "Invalid `#{path.basename}` file: #{e.message}"
|
203
|
+
raise DSLError.new(message, path, e.backtrace, contents)
|
204
|
+
end
|
205
|
+
# rubocop:enable Lint/RescueException
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
def print_results
|
210
|
+
status = status_report
|
211
|
+
violations = violation_report
|
212
|
+
return if (violations[:errors] + violations[:warnings] + violations[:messages] + status[:markdowns]).count.zero?
|
213
|
+
|
214
|
+
ui.section("Results:") do
|
215
|
+
%i(errors warnings messages).each do |key|
|
216
|
+
formatted = key.to_s.capitalize + ":"
|
217
|
+
title = case key
|
218
|
+
when :errors
|
219
|
+
formatted.red
|
220
|
+
when :warnings
|
221
|
+
formatted.yellow
|
222
|
+
else
|
223
|
+
formatted
|
224
|
+
end
|
225
|
+
rows = violations[key].uniq
|
226
|
+
print_list(title, rows)
|
227
|
+
end
|
228
|
+
|
229
|
+
if status[:markdowns].count > 0
|
230
|
+
ui.title("Markdown:") do
|
231
|
+
status[:markdowns].each do |current_markdown|
|
232
|
+
ui.puts "#{current_markdown.file}\#L#{current_markdown.line}" if current_markdown.file && current_markdown.line
|
233
|
+
ui.puts current_markdown.message
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
def failed?
|
241
|
+
violation_report[:errors].count > 0
|
242
|
+
end
|
243
|
+
|
244
|
+
def post_results(danger_id, new_comment, remove_previous_comments)
|
245
|
+
violations = violation_report
|
246
|
+
report = {
|
247
|
+
warnings: violations[:warnings].uniq,
|
248
|
+
errors: violations[:errors].uniq,
|
249
|
+
messages: violations[:messages].uniq,
|
250
|
+
markdowns: status_report[:markdowns].uniq,
|
251
|
+
danger_id: danger_id
|
252
|
+
}
|
253
|
+
|
254
|
+
if env.request_source.respond_to?(:update_pr_by_line!) && ENV["DANGER_MESSAGE_AGGREGATION"]
|
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])
|
259
|
+
else
|
260
|
+
env.request_source.update_pull_request!(
|
261
|
+
**report,
|
262
|
+
new_comment: new_comment,
|
263
|
+
remove_previous_comments: remove_previous_comments
|
264
|
+
)
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
def setup_for_running(base_branch, head_branch)
|
269
|
+
env.ensure_danger_branches_are_setup
|
270
|
+
env.scm.diff_for_folder(".".freeze, from: base_branch, to: head_branch, lookup_top_level: true)
|
271
|
+
end
|
272
|
+
|
273
|
+
def run(base_branch, head_branch, dangerfile_path, danger_id, new_comment, remove_previous_comments)
|
274
|
+
# Setup internal state
|
275
|
+
init_plugins
|
276
|
+
env.fill_environment_vars
|
277
|
+
|
278
|
+
begin
|
279
|
+
# Sets up the git environment
|
280
|
+
setup_for_running(base_branch, head_branch)
|
281
|
+
|
282
|
+
# Parse the local Dangerfile
|
283
|
+
parse(Pathname.new(dangerfile_path))
|
284
|
+
|
285
|
+
# Push results to the API
|
286
|
+
# Pass along the details of the run to the request source
|
287
|
+
# to send back to the code review site.
|
288
|
+
post_results(danger_id, new_comment, remove_previous_comments) unless danger_id.nil?
|
289
|
+
|
290
|
+
# Print results in the terminal
|
291
|
+
print_results
|
292
|
+
rescue DSLError => ex
|
293
|
+
# Push exception to the API and re-raise
|
294
|
+
post_exception(ex, danger_id, new_comment) unless danger_id.nil?
|
295
|
+
raise
|
296
|
+
ensure
|
297
|
+
# Makes sure that Danger specific git branches are cleaned
|
298
|
+
env.clean_up
|
299
|
+
end
|
300
|
+
|
301
|
+
failed?
|
302
|
+
end
|
303
|
+
|
304
|
+
private
|
305
|
+
|
306
|
+
def eval_file(contents, path)
|
307
|
+
eval(contents, nil, path.to_s) # rubocop:disable Eval
|
308
|
+
end
|
309
|
+
|
310
|
+
def print_list(title, rows)
|
311
|
+
unless rows.empty?
|
312
|
+
ui.title(title) do
|
313
|
+
rows.each do |row|
|
314
|
+
if row.file && row.line
|
315
|
+
path = "#{row.file}\#L#{row.line}: "
|
316
|
+
else
|
317
|
+
path = ""
|
318
|
+
end
|
319
|
+
|
320
|
+
ui.puts("- [ ] #{path}#{row.message}")
|
321
|
+
end
|
322
|
+
end
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
def wrap_text(text, width = 80)
|
327
|
+
text.gsub(/.{,#{width}}/) do |line|
|
328
|
+
line.strip!
|
329
|
+
"#{line}\n"
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|
333
|
+
def post_exception(ex, danger_id, new_comment)
|
334
|
+
env.request_source.update_pull_request!(
|
335
|
+
danger_id: danger_id,
|
336
|
+
new_comment: new_comment,
|
337
|
+
markdowns: [ex.to_markdown]
|
338
|
+
)
|
339
|
+
end
|
340
|
+
end
|
341
|
+
end
|