danger 0.6.0 → 0.7.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 +4 -4
- data/README.md +54 -9
- data/lib/assets/PluginTemplate.rb.template +20 -0
- data/lib/danger/available_values.rb +3 -3
- data/lib/danger/ci_source/local_git_repo.rb +17 -15
- data/lib/danger/commands/init_helpers/interviewer.rb +1 -1
- data/lib/danger/commands/local.rb +7 -5
- data/lib/danger/commands/new_plugin.rb +43 -0
- data/lib/danger/commands/runner.rb +11 -5
- data/lib/danger/comment_generators/github.md.erb +21 -4
- data/lib/danger/core_ext/string.rb +13 -0
- data/lib/danger/dangerfile.rb +33 -6
- data/lib/danger/dangerfile_dsl.rb +90 -14
- data/lib/danger/environment_manager.rb +35 -0
- data/lib/danger/plugins/plugin.rb +26 -0
- data/lib/danger/plugins/protect_files.rb +24 -13
- data/lib/danger/request_sources/github.rb +92 -22
- data/lib/danger/scm_source/file_list.rb +12 -0
- data/lib/danger/scm_source/git_repo.rb +15 -11
- data/lib/danger/standard_error.rb +1 -1
- data/lib/danger/version.rb +2 -2
- data/lib/danger/violation.rb +10 -0
- data/lib/danger.rb +1 -0
- metadata +16 -11
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f405c58b164cfb051f33ce62eff96d6954ccedf8
|
|
4
|
+
data.tar.gz: e487a8349af60005ce0f63ec429cd8e73a561055
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3ce00623811798d3bf0cb0e77bc788bc0c99fac1045d00a33cf3c68b297983e669de41544bae3f8310257e3a34a3e8704aedb2d9f9fc2064e4f0a3e443cdcbc5
|
|
7
|
+
data.tar.gz: e0cdd1d536430c45226a3638ff0a2cd659db62a19e643c931230961e00967e7705321ec561c2afd276c0e73f6570d2335f7126b82017be95f5dcd0de18d9c906
|
data/README.md
CHANGED
|
@@ -38,7 +38,7 @@ bundle exec danger init
|
|
|
38
38
|
bundle exec danger
|
|
39
39
|
```
|
|
40
40
|
|
|
41
|
-
This will look at your `Dangerfile` and update the pull request accordingly. While you are setting up Danger, you may want to use: `--verbose` for more debug information.
|
|
41
|
+
This will look at your `Dangerfile` and update the pull request accordingly. While you are setting up Danger, you may want to use: `--verbose` for more debug information.
|
|
42
42
|
|
|
43
43
|
## What happens?
|
|
44
44
|
|
|
@@ -49,9 +49,9 @@ Danger runs at the end of a CI build, she will execute a `Dangerfile`. This file
|
|
|
49
49
|
| | Danger :no_entry_sign:
|
|
50
50
|
-------------: | ------------- | ----
|
|
51
51
|
:sparkles: | `lines_of_code` | The total amount of lines of code in the diff
|
|
52
|
-
:pencil2: | `
|
|
53
|
-
:ship: | `
|
|
54
|
-
:recycle: | `
|
|
52
|
+
:pencil2: | `modified_files` | The list of modified files
|
|
53
|
+
:ship: | `added_files` | The list of added files
|
|
54
|
+
:recycle: | `deleted_files` | The list of removed files
|
|
55
55
|
:abc: | `pr_title` | The title of the PR
|
|
56
56
|
:book: | `pr_body` | The body of the PR
|
|
57
57
|
:busts_in_silhouette: | `pr_author` | The author who submitted the PR
|
|
@@ -67,18 +67,18 @@ The `Dangerfile` is a ruby file, so really, you can do anything. However, at thi
|
|
|
67
67
|
declared_trivial = pr_title.include? "#trivial"
|
|
68
68
|
|
|
69
69
|
# Just to let people know
|
|
70
|
-
warn("PR is classed as Work in Progress") if pr_title.include? "[WIP]"
|
|
70
|
+
warn("PR is classed as Work in Progress", sticky: false) if pr_title.include? "[WIP]"
|
|
71
71
|
```
|
|
72
72
|
|
|
73
73
|
#### Being cautious around specific files
|
|
74
74
|
|
|
75
75
|
``` ruby
|
|
76
76
|
# Devs shouldn't ship changes to this file
|
|
77
|
-
fail("Developer Specific file shouldn't be changed") if
|
|
77
|
+
fail("Developer Specific file shouldn't be changed", sticky: false) if modified_files.include?("Artsy/View_Controllers/App_Navigation/ARTopMenuViewController+DeveloperExtras.m")
|
|
78
78
|
|
|
79
79
|
# Did you make analytics changes? Well you should also include a change to our analytics spec
|
|
80
|
-
made_analytics_changes =
|
|
81
|
-
made_analytics_specs_changes =
|
|
80
|
+
made_analytics_changes = modified_files.include?("/Artsy/App/ARAppDelegate+Analytics.m")
|
|
81
|
+
made_analytics_specs_changes = modified_files.include?("/Artsy_Tests/Analytics_Tests/ARAppAnalyticsSpec.m")
|
|
82
82
|
if made_analytics_changes
|
|
83
83
|
fail("Analytics changes should have reflected specs changes") if !made_analytics_specs_changes
|
|
84
84
|
|
|
@@ -91,7 +91,7 @@ end
|
|
|
91
91
|
#### Pinging people when a specific file has changed
|
|
92
92
|
|
|
93
93
|
```ruby
|
|
94
|
-
message("@orta something changed in elan!") if
|
|
94
|
+
message("@orta something changed in elan!") if modified_files.include? "/components/lib/variables/colors.json"
|
|
95
95
|
```
|
|
96
96
|
|
|
97
97
|
#### Exposing aspects of CI logs into the PR discussion
|
|
@@ -102,6 +102,40 @@ snapshots_url = build_log.match(%r{https://eigen-ci.s3.amazonaws.com/\d+/index.h
|
|
|
102
102
|
fail("There were [snapshot errors](#{snapshots_url})") if snapshots_url
|
|
103
103
|
```
|
|
104
104
|
|
|
105
|
+
#### Available commands
|
|
106
|
+
|
|
107
|
+
Command | Description
|
|
108
|
+
------------- | ----
|
|
109
|
+
`fail` | Causes the PR to fail and print out the error on the PR
|
|
110
|
+
`warn` | Prints out a warning to the PR, but still enables the merge button
|
|
111
|
+
`message` | Show neutral messages on the PR
|
|
112
|
+
`markdown` | Print raw markdown below the summary tables on the PR
|
|
113
|
+
|
|
114
|
+
## Plugins
|
|
115
|
+
|
|
116
|
+
Danger was built with a platform in mind: It can be used with any kind of software project and allows you to write your own action to have structured source code.
|
|
117
|
+
|
|
118
|
+
In your `Dangerfile` you can import local or remote actions using
|
|
119
|
+
|
|
120
|
+
```ruby
|
|
121
|
+
import "./danger_plugins/work_in_progress_warning"
|
|
122
|
+
# or
|
|
123
|
+
import "https://raw.githubusercontent.com/danger/danger/master/danger_plugins/work_in_progress_warning.rb"
|
|
124
|
+
|
|
125
|
+
# Call those actions using
|
|
126
|
+
work_in_progress_warning
|
|
127
|
+
|
|
128
|
+
custom_plugin(variable: "value")
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
To create a new plugin run
|
|
132
|
+
|
|
133
|
+
```
|
|
134
|
+
danger new_plugin
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
This will generate a new Ruby file which you can modify to fit your needs.
|
|
138
|
+
|
|
105
139
|
## Support
|
|
106
140
|
|
|
107
141
|
Danger currently is supported on Travis CI, Circle CI, BuildKite and Jenkins. These work via environment variables, so it's easy to extend to include your own.
|
|
@@ -132,6 +166,15 @@ You can tell Danger to ignore a specific warning or error by commenting on the P
|
|
|
132
166
|
> Danger: Ignore "Developer Specific file shouldn't be changed"
|
|
133
167
|
```
|
|
134
168
|
|
|
169
|
+
## Sticky
|
|
170
|
+
|
|
171
|
+
Danger can keep its history if a warning/error/message is marked as *sticky*. When the violation is resolved,
|
|
172
|
+
Danger will update the comment to cross it out. If you don't want this behavior, just use `sticky: false`.
|
|
173
|
+
|
|
174
|
+
```ruby
|
|
175
|
+
fail("PR needs labels", sticky: false) if pr_labels.empty?
|
|
176
|
+
```
|
|
177
|
+
|
|
135
178
|
## Useful bits of knowledge
|
|
136
179
|
|
|
137
180
|
* You can set the base branch in the command line arguments see: `bundle exec danger --help`, if you commonly merge into non-master branches.
|
|
@@ -141,6 +184,8 @@ Here are some real-world Dangerfiles: [artsy/eigen](https://github.com/artsy/eig
|
|
|
141
184
|
|
|
142
185
|
## License, Contributor's Guidelines and Code of Conduct
|
|
143
186
|
|
|
187
|
+
[Join our Slack Group](https://danger-slack.herokuapp.com/)
|
|
188
|
+
|
|
144
189
|
> This project is open source under the MIT license, which means you have full access to the source code and can modify it to fit your own needs.
|
|
145
190
|
|
|
146
191
|
> This project subscribes to the [Moya Contributors Guidelines](https://github.com/Moya/contributors) which TLDR: means we give out push access easily and often.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
module Danger
|
|
2
|
+
class Dangerfile
|
|
3
|
+
module DSL
|
|
4
|
+
class [[CLASS_NAME]] < Plugin
|
|
5
|
+
def run(parameter1: nil, parameter2: nil)
|
|
6
|
+
if (pr_body + pr_title).include?("WIP")
|
|
7
|
+
warn "Pull Request is Work in Progress"
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def self.description
|
|
12
|
+
[
|
|
13
|
+
"Describe what this plugin does",
|
|
14
|
+
"and how the user can use it"
|
|
15
|
+
].join(" ")
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# For more info see: https://github.com/schacon/ruby-git
|
|
2
2
|
|
|
3
|
-
require '
|
|
3
|
+
require 'git'
|
|
4
4
|
require 'uri'
|
|
5
5
|
|
|
6
6
|
module Danger
|
|
@@ -13,36 +13,38 @@ module Danger
|
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
def git
|
|
16
|
-
@git ||=
|
|
16
|
+
@git ||= GitRepo.new
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
def run_git(command)
|
|
20
|
-
|
|
21
|
-
git.sh "#{binary} #{command}"
|
|
20
|
+
git.exec command
|
|
22
21
|
end
|
|
23
22
|
|
|
24
|
-
def initialize(
|
|
23
|
+
def initialize(env = {})
|
|
24
|
+
github_host = env["DANGER_GITHUB_HOST"] || "github.com"
|
|
25
|
+
|
|
25
26
|
# get the remote URL
|
|
26
27
|
remote = run_git "remote show origin -n | grep \"Fetch URL\" | cut -d ':' -f 2-"
|
|
27
28
|
if remote
|
|
28
|
-
remote_url_matches = remote.
|
|
29
|
+
remote_url_matches = remote.match(%r{#{Regexp.escape github_host}(:|/)(?<repo_slug>.+/.+?)(?:\.git)?$})
|
|
29
30
|
if !remote_url_matches.nil? and remote_url_matches["repo_slug"]
|
|
30
31
|
self.repo_slug = remote_url_matches["repo_slug"]
|
|
31
32
|
else
|
|
32
|
-
puts "Danger local requires a repository hosted on
|
|
33
|
+
puts "Danger local requires a repository hosted on GitHub.com or GitHub Enterprise."
|
|
33
34
|
end
|
|
34
35
|
end
|
|
35
36
|
|
|
36
37
|
# get the most recent PR merge
|
|
37
|
-
|
|
38
|
-
pr_merge
|
|
39
|
-
|
|
40
|
-
self.pull_request_id = pr_merge.match("#[0-9]*")[0].delete("#")
|
|
41
|
-
sha = pr_merge.split(" ")[0]
|
|
42
|
-
parents = run_git "rev-list --parents -n 1 #{sha}"
|
|
43
|
-
self.base_commit = parents[0].strip.split(" ")[0]
|
|
44
|
-
self.head_commit = parents[0].strip.split(" ")[1]
|
|
38
|
+
pr_merge = run_git "log --since='2 weeks ago' --merges --oneline | grep \"Merge pull request\" | head -n 1".strip
|
|
39
|
+
if pr_merge.to_s.empty?
|
|
40
|
+
raise "No recent pull requests found for this repo, danger requires at least one PR for the local mode"
|
|
45
41
|
end
|
|
42
|
+
|
|
43
|
+
self.pull_request_id = pr_merge.match("#([0-9]+)")[1]
|
|
44
|
+
sha = pr_merge.split(" ")[0]
|
|
45
|
+
parents = run_git("rev-list --parents -n 1 #{sha}").strip.split(" ")
|
|
46
|
+
self.base_commit = parents[0]
|
|
47
|
+
self.head_commit = parents[1]
|
|
46
48
|
end
|
|
47
49
|
end
|
|
48
50
|
end
|
|
@@ -22,12 +22,14 @@ module Danger
|
|
|
22
22
|
dm.env = EnvironmentManager.new(ENV)
|
|
23
23
|
|
|
24
24
|
source = dm.env.ci_source
|
|
25
|
-
|
|
26
|
-
puts "danger local
|
|
25
|
+
if source.nil? or source.repo_slug.empty?
|
|
26
|
+
puts "danger local failed because it only works with GitHub projects at the moment. Sorry.".red
|
|
27
27
|
exit 0
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
gh = dm.env.request_source
|
|
31
|
+
|
|
32
|
+
puts "Running your Dangerfile against this PR - https://#{gh.github_host}/#{source.repo_slug}/pull/#{source.pull_request_id}"
|
|
31
33
|
|
|
32
34
|
if verbose != true
|
|
33
35
|
puts "Turning on --verbose"
|
|
@@ -36,7 +38,6 @@ module Danger
|
|
|
36
38
|
|
|
37
39
|
puts ""
|
|
38
40
|
|
|
39
|
-
gh = GitHub.new(dm.env.ci_source, ENV)
|
|
40
41
|
# We can use tokenless here, as it's running on someone's computer
|
|
41
42
|
# and is IP locked, as opposed to on the CI.
|
|
42
43
|
gh.support_tokenless_auth = true
|
|
@@ -47,7 +48,8 @@ module Danger
|
|
|
47
48
|
dm.env.scm = GitRepo.new
|
|
48
49
|
|
|
49
50
|
dm.env.scm.diff_for_folder(".", from: dm.env.ci_source.base_commit, to: dm.env.ci_source.head_commit)
|
|
50
|
-
dm.parse
|
|
51
|
+
dm.parse(Pathname.new(@dangerfile_path))
|
|
52
|
+
dm.print_results
|
|
51
53
|
end
|
|
52
54
|
end
|
|
53
55
|
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
module Danger
|
|
2
|
+
class NewPlugin < Runner
|
|
3
|
+
self.summary = 'Generate a new danger plugin.'
|
|
4
|
+
self.command = 'new_plugin'
|
|
5
|
+
|
|
6
|
+
def initialize(argv)
|
|
7
|
+
super
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def validate!
|
|
11
|
+
super
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def run
|
|
15
|
+
require 'fileutils'
|
|
16
|
+
|
|
17
|
+
puts "Must be lower case, and use a '_' between words. Do not use '.'".green
|
|
18
|
+
puts "examples: 'number_of_emojis', 'ensure_pr_title_contains_keyword'".green
|
|
19
|
+
puts "Name of your new plugin: "
|
|
20
|
+
name = STDIN.gets.strip
|
|
21
|
+
|
|
22
|
+
dir = Danger.gem_path
|
|
23
|
+
content = File.read(File.join(dir, "lib", "assets", "PluginTemplate.rb.template"))
|
|
24
|
+
content.gsub!("[[CLASS_NAME]]", name.danger_class)
|
|
25
|
+
|
|
26
|
+
plugins_path = "danger_plugins"
|
|
27
|
+
FileUtils.mkdir_p("plugins_path") unless File.directory?(plugins_path)
|
|
28
|
+
|
|
29
|
+
output_path = File.join(plugins_path, "#{name}.rb")
|
|
30
|
+
raise "File '#{output_path}' already exists!" if File.exist?(output_path)
|
|
31
|
+
File.write(output_path, content)
|
|
32
|
+
|
|
33
|
+
puts ""
|
|
34
|
+
puts "Successfully created new plugin at path '#{output_path}'".green
|
|
35
|
+
puts "Add this to your `Dangerfile` to use it:"
|
|
36
|
+
puts ""
|
|
37
|
+
puts "import \"#{output_path.gsub('.rb', '')}\"".blue
|
|
38
|
+
puts "#{name}(parameter1: 123, parameter2: \"Club Mate\")".blue
|
|
39
|
+
puts ""
|
|
40
|
+
puts "Enjoy ✨"
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -2,6 +2,7 @@ module Danger
|
|
|
2
2
|
class Runner < CLAide::Command
|
|
3
3
|
require 'danger/commands/init'
|
|
4
4
|
require 'danger/commands/local'
|
|
5
|
+
require 'danger/commands/new_plugin'
|
|
5
6
|
|
|
6
7
|
self.summary = 'Run the Dangerfile.'
|
|
7
8
|
self.command = 'danger'
|
|
@@ -33,22 +34,27 @@ module Danger
|
|
|
33
34
|
dm.verbose = verbose
|
|
34
35
|
dm.env = EnvironmentManager.new(ENV)
|
|
35
36
|
return unless dm.env.ci_source # if it's not a PR
|
|
36
|
-
dm.env.fill_environment_vars
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
ci_head = @head || gh.head_commit
|
|
38
|
+
dm.env.fill_environment_vars
|
|
39
|
+
dm.env.ensure_danger_branches_are_setup
|
|
41
40
|
|
|
41
|
+
# Offer the chance for a user to specify a branch through the command line
|
|
42
|
+
ci_base = @base || dm.env.danger_head_branch
|
|
43
|
+
ci_head = @head || dm.env.danger_base_branch
|
|
42
44
|
dm.env.scm.diff_for_folder(".", from: ci_base, to: ci_head)
|
|
43
45
|
|
|
44
46
|
dm.parse Pathname.new(@dangerfile_path)
|
|
45
47
|
|
|
46
48
|
post_results(dm)
|
|
49
|
+
|
|
50
|
+
dm.env.clean_up
|
|
51
|
+
|
|
52
|
+
dm.print_results
|
|
47
53
|
end
|
|
48
54
|
|
|
49
55
|
def post_results(dm)
|
|
50
56
|
gh = dm.env.request_source
|
|
51
|
-
gh.update_pull_request!(warnings: dm.warnings, errors: dm.errors, messages: dm.messages)
|
|
57
|
+
gh.update_pull_request!(warnings: dm.warnings, errors: dm.errors, messages: dm.messages, markdowns: dm.markdowns)
|
|
52
58
|
end
|
|
53
59
|
end
|
|
54
60
|
end
|
|
@@ -1,24 +1,41 @@
|
|
|
1
1
|
<% @tables.each do |table| %>
|
|
2
|
-
<% if table[:content].any? %>
|
|
2
|
+
<% if table[:content].any? || table[:resolved].any? %>
|
|
3
3
|
<table>
|
|
4
4
|
<thead>
|
|
5
5
|
<tr>
|
|
6
6
|
<th width="50"></th>
|
|
7
|
-
<th width="100%"
|
|
7
|
+
<th width="100%" 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>
|
|
8
14
|
</tr>
|
|
9
15
|
</thead>
|
|
10
16
|
<tbody>
|
|
11
|
-
<% table[:content].each do |
|
|
17
|
+
<% table[:content].each do |violation| -%>
|
|
12
18
|
<tr>
|
|
13
19
|
<td>:<%= table[:emoji] %>:</td>
|
|
14
|
-
<td><%= message %></td>
|
|
20
|
+
<td data-sticky="<%= violation.sticky %>"><%= violation.message %></td>
|
|
15
21
|
</tr>
|
|
16
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 %>
|
|
17
29
|
</tbody>
|
|
18
30
|
</table>
|
|
19
31
|
<% end %>
|
|
20
32
|
<% end %>
|
|
21
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
|
+
|
|
22
39
|
<p align="right" data-meta="generated_by_danger" data-base-commit="<%= @base_commit %>" data-head-commit="<%= @head_commit %>" >
|
|
23
40
|
Generated by :no_entry_sign: <a href="https://github.com/danger/danger/">danger</a>
|
|
24
41
|
</p>
|
data/lib/danger/dangerfile.rb
CHANGED
|
@@ -7,7 +7,7 @@ module Danger
|
|
|
7
7
|
class Dangerfile
|
|
8
8
|
include Danger::Dangerfile::DSL
|
|
9
9
|
|
|
10
|
-
attr_accessor :env, :warnings, :errors, :messages, :verbose
|
|
10
|
+
attr_accessor :env, :warnings, :errors, :messages, :markdowns, :verbose
|
|
11
11
|
|
|
12
12
|
# @return [Pathname] the path where the Dangerfile was loaded from. It is nil
|
|
13
13
|
# if the Dangerfile was generated programmatically.
|
|
@@ -26,8 +26,8 @@ module Danger
|
|
|
26
26
|
rows = []
|
|
27
27
|
|
|
28
28
|
AvailableValues.all.each do |key|
|
|
29
|
-
next if key == :pr_body
|
|
30
29
|
value = self.send(key)
|
|
30
|
+
value = value.scan(/.{,80}/).to_a.each(&:strip!).join("\n") if key == :pr_body
|
|
31
31
|
|
|
32
32
|
# So that we either have one value per row
|
|
33
33
|
# or we have [] for an empty array
|
|
@@ -40,8 +40,8 @@ module Danger
|
|
|
40
40
|
rows << ["SCM", env.scm.class]
|
|
41
41
|
rows << ["Source", env.ci_source.class]
|
|
42
42
|
rows << ["Requests", env.request_source.class]
|
|
43
|
-
rows << ["Base Commit", env.
|
|
44
|
-
rows << ["Head Commit", env.
|
|
43
|
+
rows << ["Base Commit", env.meta_info_for_base]
|
|
44
|
+
rows << ["Head Commit", env.meta_info_for_head]
|
|
45
45
|
|
|
46
46
|
params = {}
|
|
47
47
|
params[:rows] = rows.each { |current| current[0] = current[0].yellow }
|
|
@@ -49,8 +49,6 @@ module Danger
|
|
|
49
49
|
|
|
50
50
|
puts ""
|
|
51
51
|
puts Terminal::Table.new(params)
|
|
52
|
-
puts "PR Body:"
|
|
53
|
-
puts self.pr_body.cyan
|
|
54
52
|
puts ""
|
|
55
53
|
end
|
|
56
54
|
|
|
@@ -92,5 +90,34 @@ module Danger
|
|
|
92
90
|
# rubocop:enable Lint/RescueException
|
|
93
91
|
end
|
|
94
92
|
end
|
|
93
|
+
|
|
94
|
+
def print_results
|
|
95
|
+
return if (self.errors + self.warnings + self.messages + self.markdowns).count == 0
|
|
96
|
+
|
|
97
|
+
puts ""
|
|
98
|
+
puts "danger results:"
|
|
99
|
+
[:errors, :warnings, :messages].each do |current|
|
|
100
|
+
params = {}
|
|
101
|
+
params[:rows] = self.send(current).collect { |a| [a.message] }
|
|
102
|
+
next unless params[:rows].count > 0
|
|
103
|
+
params[:title] = case current
|
|
104
|
+
when :errors
|
|
105
|
+
current.to_s.capitalize.red
|
|
106
|
+
when :warnings
|
|
107
|
+
current.to_s.capitalize.yellow
|
|
108
|
+
else
|
|
109
|
+
current.to_s.capitalize
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
puts ""
|
|
113
|
+
puts Terminal::Table.new(params)
|
|
114
|
+
puts ""
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
puts "Markdown: ".green if self.markdowns.count > 0
|
|
118
|
+
self.markdowns.each do |current_markdown|
|
|
119
|
+
puts current_markdown
|
|
120
|
+
end
|
|
121
|
+
end
|
|
95
122
|
end
|
|
96
123
|
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
require 'danger/violation'
|
|
2
|
+
|
|
1
3
|
module Danger
|
|
2
4
|
class Dangerfile
|
|
3
5
|
module DSL
|
|
@@ -13,12 +15,47 @@ module Danger
|
|
|
13
15
|
self.warnings = []
|
|
14
16
|
self.errors = []
|
|
15
17
|
self.messages = []
|
|
16
|
-
|
|
18
|
+
self.markdowns = []
|
|
19
|
+
|
|
20
|
+
load_default_plugins
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def import(path)
|
|
24
|
+
raise "`import` requires a string" unless path.kind_of?(String)
|
|
25
|
+
path += ".rb" unless path.end_with?(".rb")
|
|
26
|
+
|
|
27
|
+
if path.start_with?("http")
|
|
28
|
+
import_url(path)
|
|
29
|
+
else
|
|
30
|
+
import_local(path)
|
|
31
|
+
end
|
|
17
32
|
end
|
|
18
33
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
34
|
+
# Download a remote plugin and use it locally
|
|
35
|
+
#
|
|
36
|
+
# @param [String] url
|
|
37
|
+
# https URL to the Ruby file to use
|
|
38
|
+
def import_url(url)
|
|
39
|
+
raise "URL is not https, for security reasons `danger` only supports encrypted requests" unless url.start_with?("https://")
|
|
40
|
+
|
|
41
|
+
require 'tmpdir'
|
|
42
|
+
require 'faraday'
|
|
43
|
+
content = Faraday.get(url)
|
|
44
|
+
Dir.mktmpdir do |dir|
|
|
45
|
+
path = File.join(dir, "temporary_remote_action.rb")
|
|
46
|
+
File.write(path, content.body)
|
|
47
|
+
import_local(path)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Import one or more local plugins
|
|
52
|
+
#
|
|
53
|
+
# @param [String] path
|
|
54
|
+
# The path to the file to import
|
|
55
|
+
# Can also be a pattern (./**/*plugin.rb)
|
|
56
|
+
def import_local(path)
|
|
57
|
+
Dir[path].each do |file|
|
|
58
|
+
require File.expand_path(file) # without the expand_path it would fail if the path doesn't start with ./
|
|
22
59
|
end
|
|
23
60
|
end
|
|
24
61
|
|
|
@@ -30,9 +67,11 @@ module Danger
|
|
|
30
67
|
#
|
|
31
68
|
# @param [String] message
|
|
32
69
|
# The message to present to the user
|
|
33
|
-
|
|
70
|
+
# @param [Boolean] sticky
|
|
71
|
+
# Whether the message should be kept after it was fixed
|
|
72
|
+
def fail(message, sticky: true)
|
|
34
73
|
return if should_ignore_violation(message)
|
|
35
|
-
self.errors << message
|
|
74
|
+
self.errors << Violation.new(message, sticky)
|
|
36
75
|
puts "Raising error '#{message}'"
|
|
37
76
|
end
|
|
38
77
|
|
|
@@ -40,9 +79,11 @@ module Danger
|
|
|
40
79
|
#
|
|
41
80
|
# @param [String] message
|
|
42
81
|
# The message to present to the user
|
|
43
|
-
|
|
82
|
+
# @param [Boolean] sticky
|
|
83
|
+
# Whether the message should be kept after it was fixed
|
|
84
|
+
def warn(message, sticky: true)
|
|
44
85
|
return if should_ignore_violation(message)
|
|
45
|
-
self.warnings << message
|
|
86
|
+
self.warnings << Violation.new(message, sticky)
|
|
46
87
|
puts "Printing warning '#{message}'"
|
|
47
88
|
end
|
|
48
89
|
|
|
@@ -50,26 +91,61 @@ module Danger
|
|
|
50
91
|
#
|
|
51
92
|
# @param [String] message
|
|
52
93
|
# The message to present to the user
|
|
53
|
-
|
|
54
|
-
|
|
94
|
+
# @param [Boolean] sticky
|
|
95
|
+
# Whether the message should be kept after it was fixed
|
|
96
|
+
def message(message, sticky: true)
|
|
97
|
+
self.messages << Violation.new(message, sticky)
|
|
55
98
|
puts "Printing message '#{message}'"
|
|
56
99
|
end
|
|
57
100
|
|
|
101
|
+
# Print markdown to below the table
|
|
102
|
+
#
|
|
103
|
+
# @param [String] message
|
|
104
|
+
# The markdown based message to be printed below the table
|
|
105
|
+
def markdown(message)
|
|
106
|
+
self.markdowns << message
|
|
107
|
+
puts "Printing markdown #{message}"
|
|
108
|
+
end
|
|
109
|
+
|
|
58
110
|
# When an undefined method is called, we check to see if it's something
|
|
59
111
|
# that either the `scm` or the `request_source` can handle.
|
|
60
112
|
# This opens us up to letting those object extend themselves naturally.
|
|
61
|
-
|
|
113
|
+
# This will also look for plugins
|
|
114
|
+
def method_missing(method_sym, *arguments, &_block)
|
|
115
|
+
# SCM Source
|
|
62
116
|
if AvailableValues.scm.include?(method_sym)
|
|
63
|
-
# SCM Source
|
|
64
117
|
return env.scm.send(method_sym)
|
|
65
118
|
end
|
|
66
119
|
|
|
120
|
+
# Request Source
|
|
67
121
|
if AvailableValues.request_source.include?(method_sym)
|
|
68
|
-
# Request Source
|
|
69
122
|
return env.request_source.send(method_sym)
|
|
70
123
|
end
|
|
71
124
|
|
|
72
|
-
|
|
125
|
+
# Plugins
|
|
126
|
+
class_name = method_sym.to_s.danger_class
|
|
127
|
+
if Danger::Dangerfile::DSL.const_defined?(class_name)
|
|
128
|
+
plugin_ref = Danger::Dangerfile::DSL.const_get(class_name)
|
|
129
|
+
if plugin_ref < Plugin
|
|
130
|
+
plugin_ref.new(self).run(*arguments)
|
|
131
|
+
else
|
|
132
|
+
raise "'#{method_sym}' is not a valid danger plugin".red
|
|
133
|
+
end
|
|
134
|
+
else
|
|
135
|
+
raise "Unknown method '#{method_sym}', please check out the documentation for available plugins".red
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
private
|
|
140
|
+
|
|
141
|
+
def load_default_plugins
|
|
142
|
+
Dir["./lib/danger/plugins/*.rb"].each do |file|
|
|
143
|
+
require File.expand_path(file)
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
Dir["./danger_plugins/*.rb"].each do |file|
|
|
147
|
+
require File.expand_path(file)
|
|
148
|
+
end
|
|
73
149
|
end
|
|
74
150
|
end
|
|
75
151
|
end
|
|
@@ -32,5 +32,40 @@ module Danger
|
|
|
32
32
|
|
|
33
33
|
self.scm = GitRepo.new # For now
|
|
34
34
|
end
|
|
35
|
+
|
|
36
|
+
def ensure_danger_branches_are_setup
|
|
37
|
+
# As this currently just works with GitHub, we can use a github specific feature here:
|
|
38
|
+
pull_id = ci_source.pull_request_id
|
|
39
|
+
test_branch = request_source.base_commit
|
|
40
|
+
|
|
41
|
+
# Next, we want to ensure that we have a version of the current branch that at a know location
|
|
42
|
+
scm.exec "branch #{danger_base_branch} #{test_branch}"
|
|
43
|
+
|
|
44
|
+
# OK, so we want to ensure that we have a known head branch, this will always represent
|
|
45
|
+
# the head ( e.g. the most recent commit that will be merged. )
|
|
46
|
+
scm.exec "fetch origin +refs/pull/#{pull_id}/merge:#{danger_head_branch}"
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def clean_up
|
|
50
|
+
[danger_base_branch, danger_base_branch].each do |branch|
|
|
51
|
+
scm.exec "branch -d #{branch}"
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def meta_info_for_base
|
|
56
|
+
scm.exec("--no-pager log #{danger_base_branch} -n1")
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def meta_info_for_head
|
|
60
|
+
scm.exec("--no-pager log #{danger_head_branch} -n1")
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def danger_head_branch
|
|
64
|
+
"danger_head"
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def danger_base_branch
|
|
68
|
+
"danger_base"
|
|
69
|
+
end
|
|
35
70
|
end
|
|
36
71
|
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
module Danger
|
|
2
|
+
class Dangerfile
|
|
3
|
+
module DSL
|
|
4
|
+
class Plugin
|
|
5
|
+
def initialize(dsl)
|
|
6
|
+
@dsl = dsl
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
# Since we have a reference to the DSL containing all the information
|
|
10
|
+
# We need to redirect the self calls to the DSL
|
|
11
|
+
def method_missing(method_sym, *arguments, &_block)
|
|
12
|
+
return @dsl.send(method_sym, *arguments) if @dsl.respond_to?(method_sym)
|
|
13
|
+
return @dsl.method_missing(method_sym, *arguments)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def run
|
|
17
|
+
raise "run method must be implemented"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def self.description
|
|
21
|
+
"Add plugin description here"
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -1,21 +1,32 @@
|
|
|
1
1
|
module Danger
|
|
2
2
|
class Dangerfile
|
|
3
3
|
module DSL
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
4
|
+
class ProtectFiles < Plugin
|
|
5
|
+
def run(path: nil, message: nil, fail_build: true)
|
|
6
|
+
raise "You have to provide a message" if message.to_s.length == 0
|
|
7
|
+
raise "You have to provide a path" if path.to_s.length == 0
|
|
8
|
+
|
|
9
|
+
broken_rule = false
|
|
10
|
+
|
|
11
|
+
Dir.glob(path) do |current|
|
|
12
|
+
broken_rule = true if self.env.scm.modified_files.include?(current)
|
|
13
|
+
end
|
|
12
14
|
|
|
13
|
-
|
|
15
|
+
return unless broken_rule
|
|
16
|
+
|
|
17
|
+
if fail_build
|
|
18
|
+
@dsl.errors << message
|
|
19
|
+
else
|
|
20
|
+
@dsl.warnings << message
|
|
21
|
+
end
|
|
22
|
+
end
|
|
14
23
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
24
|
+
def self.description
|
|
25
|
+
[
|
|
26
|
+
"Protect a file from being changed. This can",
|
|
27
|
+
"be used in combination with some kind of",
|
|
28
|
+
"permission check if a user is inside the org"
|
|
29
|
+
].join(" ")
|
|
19
30
|
end
|
|
20
31
|
end
|
|
21
32
|
end
|
|
@@ -4,7 +4,7 @@ require 'redcarpet'
|
|
|
4
4
|
|
|
5
5
|
module Danger
|
|
6
6
|
class GitHub
|
|
7
|
-
attr_accessor :ci_source, :pr_json, :issue_json, :environment, :base_commit, :head_commit, :support_tokenless_auth, :ignored_violations
|
|
7
|
+
attr_accessor :ci_source, :pr_json, :issue_json, :environment, :base_commit, :head_commit, :support_tokenless_auth, :ignored_violations, :github_host
|
|
8
8
|
|
|
9
9
|
def initialize(ci_source, environment)
|
|
10
10
|
self.ci_source = ci_source
|
|
@@ -12,19 +12,23 @@ module Danger
|
|
|
12
12
|
self.support_tokenless_auth = false
|
|
13
13
|
|
|
14
14
|
Octokit.auto_paginate = true
|
|
15
|
+
@token = @environment["DANGER_GITHUB_API_TOKEN"]
|
|
16
|
+
self.github_host = @environment["DANGER_GITHUB_HOST"] || "github.com"
|
|
17
|
+
if @environment["DANGER_GITHUB_API_HOST"]
|
|
18
|
+
Octokit.api_endpoint = @environment["DANGER_GITHUB_API_HOST"]
|
|
19
|
+
end
|
|
15
20
|
end
|
|
16
21
|
|
|
17
22
|
def client
|
|
18
|
-
|
|
19
|
-
raise "No API given, please provide one using `DANGER_GITHUB_API_TOKEN`" if !token && !support_tokenless_auth
|
|
23
|
+
raise "No API given, please provide one using `DANGER_GITHUB_API_TOKEN`" if !@token && !support_tokenless_auth
|
|
20
24
|
|
|
21
25
|
@client ||= Octokit::Client.new(
|
|
22
|
-
access_token: token
|
|
26
|
+
access_token: @token
|
|
23
27
|
)
|
|
24
28
|
end
|
|
25
29
|
|
|
26
30
|
def markdown_parser
|
|
27
|
-
@markdown_parser ||= Redcarpet::Markdown.new(Redcarpet::Render::HTML)
|
|
31
|
+
@markdown_parser ||= Redcarpet::Markdown.new(Redcarpet::Render::HTML, no_intra_emphasis: true)
|
|
28
32
|
end
|
|
29
33
|
|
|
30
34
|
def fetch_details
|
|
@@ -52,6 +56,10 @@ module Danger
|
|
|
52
56
|
self.pr_json[:head][:sha]
|
|
53
57
|
end
|
|
54
58
|
|
|
59
|
+
def branch_for_merge
|
|
60
|
+
self.pr_json[:base][:ref]
|
|
61
|
+
end
|
|
62
|
+
|
|
55
63
|
def pr_title
|
|
56
64
|
self.pr_json[:title].to_s
|
|
57
65
|
end
|
|
@@ -69,16 +77,28 @@ module Danger
|
|
|
69
77
|
end
|
|
70
78
|
|
|
71
79
|
# Sending data to GitHub
|
|
72
|
-
def update_pull_request!(warnings:
|
|
80
|
+
def update_pull_request!(warnings: [], errors: [], messages: [], markdowns: [])
|
|
73
81
|
comment_result = {}
|
|
74
82
|
|
|
75
|
-
|
|
83
|
+
issues = client.issue_comments(ci_source.repo_slug, ci_source.pull_request_id)
|
|
84
|
+
editable_issues = issues.reject { |issue| issue[:body].include?("generated_by_danger") == false }
|
|
85
|
+
|
|
86
|
+
if editable_issues.empty?
|
|
87
|
+
previous_violations = {}
|
|
88
|
+
else
|
|
89
|
+
comment = editable_issues.first[:body]
|
|
90
|
+
previous_violations = parse_comment(comment)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
if previous_violations.empty? && (warnings + errors + messages + markdowns).empty?
|
|
76
94
|
# Just remove the comment, if there's nothing to say.
|
|
77
95
|
delete_old_comments!
|
|
78
96
|
else
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
97
|
+
body = generate_comment(warnings: warnings,
|
|
98
|
+
errors: errors,
|
|
99
|
+
messages: messages,
|
|
100
|
+
markdowns: markdowns,
|
|
101
|
+
previous_violations: previous_violations)
|
|
82
102
|
|
|
83
103
|
if editable_issues.empty?
|
|
84
104
|
comment_result = client.add_comment(ci_source.repo_slug, ci_source.pull_request_id, body)
|
|
@@ -100,7 +120,7 @@ module Danger
|
|
|
100
120
|
message = generate_github_description(warnings: warnings, errors: errors)
|
|
101
121
|
client.create_status(ci_source.repo_slug, latest_pr_commit_ref, status, {
|
|
102
122
|
description: message,
|
|
103
|
-
context: "
|
|
123
|
+
context: "danger/danger",
|
|
104
124
|
target_url: details_url
|
|
105
125
|
})
|
|
106
126
|
rescue
|
|
@@ -125,11 +145,15 @@ module Danger
|
|
|
125
145
|
end
|
|
126
146
|
end
|
|
127
147
|
|
|
148
|
+
def random_compliment
|
|
149
|
+
compliment = ["Well done.", "Congrats.", "Woo!",
|
|
150
|
+
"Yay.", "Jolly good show.", "Good on 'ya.", "Nice work."]
|
|
151
|
+
compliment.sample
|
|
152
|
+
end
|
|
153
|
+
|
|
128
154
|
def generate_github_description(warnings: nil, errors: nil)
|
|
129
155
|
if errors.empty? && warnings.empty?
|
|
130
|
-
|
|
131
|
-
"Yay.", "Jolly good show.", "Good on 'ya.", "Nice work."]
|
|
132
|
-
return "All green. #{compliment.sample}"
|
|
156
|
+
return "All green. #{random_compliment}"
|
|
133
157
|
else
|
|
134
158
|
message = "⚠ "
|
|
135
159
|
message += "#{errors.count} Error#{errors.count == 1 ? '' : 's'}. " unless errors.empty?
|
|
@@ -139,7 +163,7 @@ module Danger
|
|
|
139
163
|
end
|
|
140
164
|
end
|
|
141
165
|
|
|
142
|
-
def generate_comment(warnings: [], errors: [], messages: [])
|
|
166
|
+
def generate_comment(warnings: [], errors: [], messages: [], markdowns: [], previous_violations: {})
|
|
143
167
|
require 'erb'
|
|
144
168
|
|
|
145
169
|
md_template = File.join(Danger.gem_path, "lib/danger/comment_generators/github.md.erb")
|
|
@@ -147,18 +171,64 @@ module Danger
|
|
|
147
171
|
# erb: http://www.rrn.dk/rubys-erb-templating-system
|
|
148
172
|
# for the extra args: http://stackoverflow.com/questions/4632879/erb-template-removing-the-trailing-line
|
|
149
173
|
@tables = [
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
174
|
+
table("Error", "no_entry_sign", errors, previous_violations),
|
|
175
|
+
table("Warning", "warning", warnings, previous_violations),
|
|
176
|
+
table("Message", "book", messages, previous_violations)
|
|
153
177
|
]
|
|
178
|
+
@markdowns = markdowns
|
|
179
|
+
|
|
154
180
|
return ERB.new(File.read(md_template), 0, "-").result(binding)
|
|
155
181
|
end
|
|
156
182
|
|
|
157
|
-
def
|
|
158
|
-
|
|
183
|
+
def table(name, emoji, violations, all_previous_violations)
|
|
184
|
+
content = violations.map { |v| process_markdown(v) }
|
|
185
|
+
kind = table_kind_from_title(name)
|
|
186
|
+
previous_violations = all_previous_violations[kind] || []
|
|
187
|
+
messages = content.map(&:message)
|
|
188
|
+
resolved_violations = previous_violations.reject { |s| messages.include? s }
|
|
189
|
+
count = content.count
|
|
190
|
+
{ name: name, emoji: emoji, content: content, resolved: resolved_violations, count: count }
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
def parse_comment(comment)
|
|
194
|
+
tables = parse_tables_from_comment(comment)
|
|
195
|
+
violations = {}
|
|
196
|
+
tables.each do |table|
|
|
197
|
+
next unless table =~ %r{<th width="100%"(.*?)</th>}im
|
|
198
|
+
title = Regexp.last_match(1)
|
|
199
|
+
kind = table_kind_from_title(title)
|
|
200
|
+
next unless kind
|
|
201
|
+
|
|
202
|
+
violations[kind] = violations_from_table(table)
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
violations.reject { |_, v| v.empty? }
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
def violations_from_table(table)
|
|
209
|
+
regex = %r{<td data-sticky="true">(?:<del>)?(.*?)(?:</del>)?\s*</td>}im
|
|
210
|
+
table.scan(regex).flatten.map(&:strip)
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
def table_kind_from_title(title)
|
|
214
|
+
if title =~ /error/i
|
|
215
|
+
:error
|
|
216
|
+
elsif title =~ /warning/i
|
|
217
|
+
:warning
|
|
218
|
+
elsif title =~ /message/i
|
|
219
|
+
:message
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
def parse_tables_from_comment(comment)
|
|
224
|
+
comment.split('</table>')
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
def process_markdown(violation)
|
|
228
|
+
html = markdown_parser.render(violation.message)
|
|
159
229
|
match = html.match(%r{^<p>(.*)</p>$})
|
|
160
|
-
|
|
161
|
-
|
|
230
|
+
message = match.nil? ? html : match.captures.first
|
|
231
|
+
Violation.new(message, violation.sticky)
|
|
162
232
|
end
|
|
163
233
|
end
|
|
164
234
|
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
module Danger
|
|
2
|
+
class FileList < Array
|
|
3
|
+
# Information about pattern: http://ruby-doc.org/core-2.2.0/File.html#method-c-fnmatch
|
|
4
|
+
# e.g. "**/something.*" for any file called something with any extension
|
|
5
|
+
def include?(pattern)
|
|
6
|
+
self.each do |current|
|
|
7
|
+
return true if File.fnmatch(pattern, current)
|
|
8
|
+
end
|
|
9
|
+
return false
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -1,38 +1,42 @@
|
|
|
1
1
|
# For more info see: https://github.com/schacon/ruby-git
|
|
2
2
|
|
|
3
|
-
require '
|
|
3
|
+
require 'git'
|
|
4
4
|
|
|
5
5
|
module Danger
|
|
6
6
|
class GitRepo
|
|
7
7
|
attr_accessor :diff
|
|
8
8
|
|
|
9
9
|
def diff_for_folder(folder, from: "master", to: 'HEAD')
|
|
10
|
-
repo =
|
|
10
|
+
repo = Git.open folder
|
|
11
11
|
self.diff = repo.diff(from, to)
|
|
12
12
|
end
|
|
13
13
|
|
|
14
|
-
def
|
|
15
|
-
|
|
14
|
+
def exec(string)
|
|
15
|
+
`git #{string}`.strip
|
|
16
16
|
end
|
|
17
17
|
|
|
18
|
-
def
|
|
19
|
-
@diff.select
|
|
18
|
+
def added_files
|
|
19
|
+
Danger::FileList.new(@diff.select { |diff| diff.type == "new" }.map(&:path))
|
|
20
20
|
end
|
|
21
21
|
|
|
22
|
-
def
|
|
23
|
-
@diff.
|
|
22
|
+
def deleted_files
|
|
23
|
+
Danger::FileList.new(@diff.select { |diff| diff.type == "deleted" }.map(&:path))
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def modified_files
|
|
27
|
+
Danger::FileList.new(@diff.stats[:files].keys)
|
|
24
28
|
end
|
|
25
29
|
|
|
26
30
|
def lines_of_code
|
|
27
|
-
@diff.
|
|
31
|
+
@diff.lines
|
|
28
32
|
end
|
|
29
33
|
|
|
30
34
|
def deletions
|
|
31
|
-
@diff.
|
|
35
|
+
@diff.deletions
|
|
32
36
|
end
|
|
33
37
|
|
|
34
38
|
def insertions
|
|
35
|
-
@diff.
|
|
39
|
+
@diff.insertions
|
|
36
40
|
end
|
|
37
41
|
end
|
|
38
42
|
end
|
data/lib/danger/version.rb
CHANGED
data/lib/danger.rb
CHANGED
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: 0.
|
|
4
|
+
version: 0.7.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: 2016-
|
|
12
|
+
date: 2016-04-07 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: claide
|
|
@@ -26,19 +26,19 @@ dependencies:
|
|
|
26
26
|
- !ruby/object:Gem::Version
|
|
27
27
|
version: '0'
|
|
28
28
|
- !ruby/object:Gem::Dependency
|
|
29
|
-
name:
|
|
29
|
+
name: git
|
|
30
30
|
requirement: !ruby/object:Gem::Requirement
|
|
31
31
|
requirements:
|
|
32
|
-
- -
|
|
32
|
+
- - ">="
|
|
33
33
|
- !ruby/object:Gem::Version
|
|
34
|
-
version:
|
|
34
|
+
version: '0'
|
|
35
35
|
type: :runtime
|
|
36
36
|
prerelease: false
|
|
37
37
|
version_requirements: !ruby/object:Gem::Requirement
|
|
38
38
|
requirements:
|
|
39
|
-
- -
|
|
39
|
+
- - ">="
|
|
40
40
|
- !ruby/object:Gem::Version
|
|
41
|
-
version:
|
|
41
|
+
version: '0'
|
|
42
42
|
- !ruby/object:Gem::Dependency
|
|
43
43
|
name: colored
|
|
44
44
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -185,14 +185,14 @@ dependencies:
|
|
|
185
185
|
requirements:
|
|
186
186
|
- - "~>"
|
|
187
187
|
- !ruby/object:Gem::Version
|
|
188
|
-
version: 0.
|
|
188
|
+
version: 0.38.0
|
|
189
189
|
type: :development
|
|
190
190
|
prerelease: false
|
|
191
191
|
version_requirements: !ruby/object:Gem::Requirement
|
|
192
192
|
requirements:
|
|
193
193
|
- - "~>"
|
|
194
194
|
- !ruby/object:Gem::Version
|
|
195
|
-
version: 0.
|
|
195
|
+
version: 0.38.0
|
|
196
196
|
description: Create a Dangerfile to introspect your pull request in CI, makes it easy
|
|
197
197
|
to enforce social conventions like changelogs and tests.
|
|
198
198
|
email:
|
|
@@ -207,6 +207,7 @@ files:
|
|
|
207
207
|
- README.md
|
|
208
208
|
- bin/danger
|
|
209
209
|
- lib/assets/DangerfileTemplate
|
|
210
|
+
- lib/assets/PluginTemplate.rb.template
|
|
210
211
|
- lib/danger.rb
|
|
211
212
|
- lib/danger/available_values.rb
|
|
212
213
|
- lib/danger/ci_source/buildkite.rb
|
|
@@ -219,16 +220,21 @@ files:
|
|
|
219
220
|
- lib/danger/commands/init.rb
|
|
220
221
|
- lib/danger/commands/init_helpers/interviewer.rb
|
|
221
222
|
- lib/danger/commands/local.rb
|
|
223
|
+
- lib/danger/commands/new_plugin.rb
|
|
222
224
|
- lib/danger/commands/runner.rb
|
|
223
225
|
- lib/danger/comment_generators/github.md.erb
|
|
226
|
+
- lib/danger/core_ext/string.rb
|
|
224
227
|
- lib/danger/dangerfile.rb
|
|
225
228
|
- lib/danger/dangerfile_dsl.rb
|
|
226
229
|
- lib/danger/environment_manager.rb
|
|
230
|
+
- lib/danger/plugins/plugin.rb
|
|
227
231
|
- lib/danger/plugins/protect_files.rb
|
|
228
232
|
- lib/danger/request_sources/github.rb
|
|
233
|
+
- lib/danger/scm_source/file_list.rb
|
|
229
234
|
- lib/danger/scm_source/git_repo.rb
|
|
230
235
|
- lib/danger/standard_error.rb
|
|
231
236
|
- lib/danger/version.rb
|
|
237
|
+
- lib/danger/violation.rb
|
|
232
238
|
homepage: http://github.com/danger/danger
|
|
233
239
|
licenses:
|
|
234
240
|
- MIT
|
|
@@ -249,9 +255,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
249
255
|
version: '0'
|
|
250
256
|
requirements: []
|
|
251
257
|
rubyforge_project:
|
|
252
|
-
rubygems_version: 2.
|
|
258
|
+
rubygems_version: 2.4.6
|
|
253
259
|
signing_key:
|
|
254
260
|
specification_version: 4
|
|
255
261
|
summary: Automate your PR etiquette.
|
|
256
262
|
test_files: []
|
|
257
|
-
has_rdoc:
|