danger 0.3.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +51 -25
- data/lib/assets/DangerfileTemplate +11 -13
- data/lib/danger.rb +1 -0
- data/lib/danger/available_values.rb +1 -1
- data/lib/danger/ci_source/jenkins.rb +25 -0
- data/lib/danger/ci_source/local_git_repo.rb +24 -12
- data/lib/danger/commands/init.rb +253 -9
- data/lib/danger/commands/init_helpers/interviewer.rb +103 -0
- data/lib/danger/commands/local.rb +3 -2
- data/lib/danger/commands/runner.rb +3 -2
- data/lib/danger/comment_generators/github.md.erb +15 -5
- data/lib/danger/dangerfile.rb +28 -17
- data/lib/danger/request_sources/github.rb +15 -6
- data/lib/danger/scm_source/git_repo.rb +13 -13
- data/lib/danger/version.rb +1 -1
- metadata +47 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b830d9fd6b6ce7b6a2141b4cb7e5b801f44ae202
|
4
|
+
data.tar.gz: 9769485c2b763df4caa907614622913f70042921
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8948ed48eb28381972bec1dd6832281aae83ae2e87f57a43f8df5ba003d002424b1d472013d58637cf73041a362a2b7fc8499763cc7bc7fb225ec65fcb6ec3bb
|
7
|
+
data.tar.gz: afcd5b7b1e16111a4ec5760ade4987c6e540c191fbfa409225bfb3d9379c32f1123dbd58d00db00a4ea3a6cba06f0f5dabcb1e1c8b8b34446185ac765c4f1f45
|
data/README.md
CHANGED
@@ -5,9 +5,8 @@
|
|
5
5
|
|
6
6
|
Formalize your Pull Request etiquette.
|
7
7
|
|
8
|
-
*Note:* Not ready for public usage yet - unless you're willing to look inside the codebase. This is a Work in progress, though it is active use on [Artsy/Eigen](https://github.com/artsy/eigen/) and [fastlane/fastlane-core](https://github.com/fastlane/fastlane_core).
|
9
|
-
|
10
8
|
-------
|
9
|
+
|
11
10
|
<p align="center">
|
12
11
|
<a href="#installation">Installation</a> •
|
13
12
|
<a href="#usage">Usage</a> •
|
@@ -19,7 +18,7 @@ Formalize your Pull Request etiquette.
|
|
19
18
|
|
20
19
|
-------
|
21
20
|
|
22
|
-
##
|
21
|
+
## Getting Started
|
23
22
|
|
24
23
|
Add this line to your application's [Gemfile](https://guides.cocoapods.org/using/a-gemfile.html):
|
25
24
|
|
@@ -27,15 +26,15 @@ Add this line to your application's [Gemfile](https://guides.cocoapods.org/using
|
|
27
26
|
gem 'danger'
|
28
27
|
```
|
29
28
|
|
30
|
-
and then run the following
|
29
|
+
and then run the following, which will help walk you through getting set up: `bundle exec danger init`.
|
31
30
|
|
32
|
-
|
33
|
-
|
34
|
-
|
31
|
+
## Usage on CI
|
32
|
+
|
33
|
+
In CI run `bundle exec danger`. This will look at your `Dangerfile` and provide feedback. While you are setting up, you may want to use: `--verbose`.
|
35
34
|
|
36
|
-
##
|
35
|
+
## What happens?
|
37
36
|
|
38
|
-
|
37
|
+
Danger runs at the end of a CI build, she will execute a `Dangerfile`. This file is given some special variables based on the git diff and the Pull Request being running. You can use these variables in Ruby to provide messages, warnings and failures for your build. You set up Danger with a GitHub user account and she will post updates via comments on the Pull Request, and can fail your build too.
|
39
38
|
|
40
39
|
## DSL
|
41
40
|
|
@@ -50,28 +49,50 @@ In CI run `bundle exec danger`. This will look at your `Dangerfile` and provide
|
|
50
49
|
:busts_in_silhouette: | `pr_author` | The author who submitted the PR
|
51
50
|
:bookmark: | `pr_labels` | The labels added to the PR
|
52
51
|
|
53
|
-
|
52
|
+
The `Dangerfile` is a ruby file, so really, you can do anything. However, at this stage you might need selling on the idea a bit more, so lets take some real examples:
|
53
|
+
|
54
|
+
#### Dealing with WIP pull requests
|
54
55
|
|
55
56
|
``` ruby
|
56
|
-
#
|
57
|
+
# Sometimes its a README fix, or something like that - which isn't relevant for
|
58
|
+
# including in a CHANGELOG for example
|
59
|
+
declared_trivial = pr_title.include? "#trivial"
|
60
|
+
|
61
|
+
# Just to let people know
|
57
62
|
warn("PR is classed as Work in Progress") if pr_title.include? "[WIP]"
|
63
|
+
```
|
58
64
|
|
59
|
-
|
60
|
-
fail("No CHANGELOG changes made")
|
61
|
-
end
|
65
|
+
#### Being cautious around specific files
|
62
66
|
|
63
|
-
|
64
|
-
|
65
|
-
|
67
|
+
``` ruby
|
68
|
+
# Devs shouldn't ship changes to this file
|
69
|
+
fail("Developer Specific file shouldn't be changed") if files_modified.include?("Artsy/View_Controllers/App_Navigation/ARTopMenuViewController+DeveloperExtras.m")
|
70
|
+
|
71
|
+
# Did you make analytics changes? Well you should also include a change to our analytics spec
|
72
|
+
made_analytics_changes = files_modified.include?("/Artsy/App/ARAppDelegate+Analytics.m")
|
73
|
+
made_analytics_specs_changes = files_modified.include?("/Artsy_Tests/Analytics_Tests/ARAppAnalyticsSpec.m")
|
74
|
+
if made_analytics_changes
|
75
|
+
fail("Analytics changes should have reflected specs changes") if !made_analytics_specs_changes
|
76
|
+
|
77
|
+
# And pay extra attention anyway
|
78
|
+
message('Analytics dict changed, double check for ?: `@""` on new entries')
|
79
|
+
message('Also, double check the [Analytics Eigen schema](https://docs.google.com/spreadsheets/u/1/d/1bLbeOgVFaWzLSjxLOBDNOKs757-zBGoLSM1lIz3OPiI/edit#gid=497747862) if the changes are non-trivial.')
|
66
80
|
end
|
81
|
+
```
|
67
82
|
|
68
|
-
|
69
|
-
|
83
|
+
#### Pinging people when a specific file has changed
|
84
|
+
|
85
|
+
``` ruby
|
86
|
+
message("@orta something changed in elan!") if files_modified.include? "/components/lib/variables/colors.json"
|
70
87
|
```
|
71
88
|
|
72
|
-
|
89
|
+
#### Exposing aspects of CI logs into the PR discussion
|
73
90
|
|
74
|
-
|
91
|
+
``` ruby
|
92
|
+
build_log = File.read( File.join(ENV["CIRCLE_ARTIFACTS"], "xcode_test_raw.log") )
|
93
|
+
snapshots_url = build_log.match(%r{https://eigen-ci.s3.amazonaws.com/\d+/index.html})
|
94
|
+
fail("There were [snapshot errors](#{snapshots_url})") if snapshots_url
|
95
|
+
```
|
75
96
|
|
76
97
|
## Advanced
|
77
98
|
|
@@ -80,7 +101,7 @@ You can access more detailed information by accessing the following variables
|
|
80
101
|
| Danger :no_entry_sign:
|
81
102
|
------------- | ----
|
82
103
|
`env.request_source.pr_json` | The full JSON for the pull request
|
83
|
-
`env.scm.diff` | The full [
|
104
|
+
`env.scm.diff` | The full [Diff](https://github.com/mojombo/grit/blob/master/lib/grit/diff.rb) file for the diff.
|
84
105
|
`env.ci_source` | To get information like the repo slug or pull request ID
|
85
106
|
|
86
107
|
## Test locally with `danger local`
|
@@ -88,10 +109,15 @@ You can access more detailed information by accessing the following variables
|
|
88
109
|
Using `danger local` will look for the last merged pull request in your git history, and apply your current
|
89
110
|
`Dangerfile` against that Pull Request. Useful when editing.
|
90
111
|
|
91
|
-
## Useful bits of knowledge
|
112
|
+
## Useful bits of knowledge
|
92
113
|
|
93
|
-
* You can set the base branch in the command line arguments see: `bundle exec danger --help
|
114
|
+
* You can set the base branch in the command line arguments see: `bundle exec danger --help`, if you commonly merge into non-master branches.
|
115
|
+
* Appending `--verbose` to `bundle exec danger` will expose all of the variables that Danger provides, and their values in the shell.
|
94
116
|
|
95
|
-
## License
|
117
|
+
## License, Contributor's Guidelines and Code of Conduct
|
96
118
|
|
97
119
|
> 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.
|
120
|
+
|
121
|
+
> This project subscribes to the [Moya Contributors Guidelines](https://github.com/Moya/contributors) which TLDR: means we give out push access easily and often.
|
122
|
+
|
123
|
+
> Contributors subscribe to the [Contributor Code of Conduct](http://contributor-covenant.org/version/1/3/0/) based on the [Contributor Covenant](http://contributor-covenant.org) version 1.3.0.
|
@@ -1,15 +1,13 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
puts "Added"
|
5
|
-
puts files_added
|
6
|
-
puts "modified"
|
7
|
-
puts files_modified
|
1
|
+
# Sometimes it's a README fix, or something like that - which isn't relevant for
|
2
|
+
# including in a project's CHANGELOG for example
|
3
|
+
declared_trivial = pr_title.include? "#trivial"
|
8
4
|
|
9
|
-
|
10
|
-
|
11
|
-
puts ""
|
12
|
-
puts pr_title
|
5
|
+
# Make it more obvious that a PR is a work in progress and shouldn't be merged yet
|
6
|
+
warn("PR is classed as Work in Progress") if pr_title.include? "[WIP]"
|
13
7
|
|
14
|
-
|
15
|
-
|
8
|
+
# Warn when there is a big PR
|
9
|
+
warn("Big PR") if lines_of_code > 500
|
10
|
+
|
11
|
+
# Don't let testing shortcuts get into master by accident
|
12
|
+
fail("fdescribe left in tests") if `grep -r fdescribe specs/`.length > 1
|
13
|
+
fail("fit left in tests") if `grep -r "fit specs/ `.length > 1
|
data/lib/danger.rb
CHANGED
@@ -0,0 +1,25 @@
|
|
1
|
+
# https://wiki.jenkins-ci.org/display/JENKINS/Building+a+software+project#Buildingasoftwareproject-JenkinsSetEnvironmentVariables
|
2
|
+
# https://wiki.jenkins-ci.org/display/JENKINS/GitHub+pull+request+builder+plugin
|
3
|
+
|
4
|
+
module Danger
|
5
|
+
module CISource
|
6
|
+
class Jenkins < CI
|
7
|
+
def self.validates?(env)
|
8
|
+
return !env["ghprbPullId"].nil? && !env["GIT_URL"].nil?
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(env)
|
12
|
+
repo = env["GIT_URL"]
|
13
|
+
unless repo.nil?
|
14
|
+
repo_matches = repo.match(%r{([\/:])([^\/]+\/[^\/.]+)(?:.git)?$})
|
15
|
+
self.repo_slug = repo_matches[2] unless repo_matches.nil?
|
16
|
+
end
|
17
|
+
|
18
|
+
# from https://docs.travis-ci.com/user/pull-requests, as otherwise it's "false"
|
19
|
+
if env["ghprbPullId"].to_i > 0
|
20
|
+
self.pull_request_id = env["ghprbPullId"]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# For more info see: https://github.com/schacon/ruby-git
|
2
2
|
|
3
|
-
require '
|
3
|
+
require 'grit'
|
4
4
|
require 'uri'
|
5
5
|
|
6
6
|
module Danger
|
@@ -12,10 +12,20 @@ module Danger
|
|
12
12
|
return !env["DANGER_USE_LOCAL_GIT"].nil?
|
13
13
|
end
|
14
14
|
|
15
|
+
def git
|
16
|
+
@git ||= Grit::Git.new(".")
|
17
|
+
end
|
18
|
+
|
19
|
+
def run_git(command)
|
20
|
+
binary = Grit::Git.git_binary
|
21
|
+
git.sh "#{binary} #{command}"
|
22
|
+
end
|
23
|
+
|
15
24
|
def initialize(*)
|
16
|
-
|
17
|
-
|
18
|
-
|
25
|
+
# get the remote URL
|
26
|
+
remote = run_git "remote show origin -n | grep \"Fetch URL\" | cut -d ':' -f 2-"
|
27
|
+
if remote
|
28
|
+
url = remote[0].strip
|
19
29
|
# deal with https://
|
20
30
|
if url.start_with? "https://github.com/"
|
21
31
|
self.repo_slug = url.gsub("https://github.com/", "").gsub(".git", '')
|
@@ -23,18 +33,20 @@ module Danger
|
|
23
33
|
# deal with SSH origin
|
24
34
|
elsif url.start_with? "git@github.com:"
|
25
35
|
self.repo_slug = url.gsub("git@github.com:", "").gsub(".git", '')
|
36
|
+
else
|
37
|
+
puts "Danger local requires a repository hosted on github."
|
26
38
|
end
|
27
39
|
end
|
28
40
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
pr_merge = logs.detect { |log| (/Merge pull request #[0-9]* from/ =~ log.message) == 0 }
|
41
|
+
# get the most recent PR merge
|
42
|
+
logs = run_git "log --since='2 weeks ago' --merges --oneline | grep \"Merge pull request\" | head -n 1"
|
43
|
+
pr_merge = logs[0].strip
|
33
44
|
if pr_merge
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
self.
|
45
|
+
self.pull_request_id = pr_merge.match("#[0-9]*")[0].delete("#")
|
46
|
+
sha = pr_merge.split(" ")[0]
|
47
|
+
parents = run_git "rev-list --parents -n 1 #{sha}"
|
48
|
+
self.base_commit = parents[0].strip.split(" ")[0]
|
49
|
+
self.head_commit = parents[0].strip.split(" ")[1]
|
38
50
|
end
|
39
51
|
end
|
40
52
|
end
|
data/lib/danger/commands/init.rb
CHANGED
@@ -1,25 +1,269 @@
|
|
1
|
+
require 'danger/commands/init_helpers/interviewer'
|
2
|
+
require 'danger/ci_source/local_git_repo'
|
3
|
+
require 'yaml'
|
4
|
+
|
1
5
|
module Danger
|
2
6
|
class Init < Runner
|
3
|
-
self.
|
7
|
+
self.summary = 'Helps you set up Danger.'
|
4
8
|
self.command = 'init'
|
5
9
|
|
10
|
+
def self.options
|
11
|
+
[
|
12
|
+
['--impatient', "'I've not got all day here. Don't add any thematic delays please.'"],
|
13
|
+
['--mousey', "'Don't make me press return to continue the adventure.'"]
|
14
|
+
].concat(super)
|
15
|
+
end
|
16
|
+
|
6
17
|
def initialize(argv)
|
7
|
-
|
18
|
+
ui.no_delay = argv.flag?('impatient', false)
|
19
|
+
ui.no_waiting = argv.flag?('mousey', false)
|
20
|
+
@bot_name = File.basename(Dir.getwd).split(".").first.capitalize + "Bot"
|
8
21
|
super
|
9
22
|
end
|
10
23
|
|
11
|
-
def
|
12
|
-
|
13
|
-
|
14
|
-
|
24
|
+
def run
|
25
|
+
ui = Interviewer.new
|
26
|
+
ui.say "\nOK, thanks #{ENV['LOGNAME']}, grab a seat and we'll get you started.\n".yellow
|
27
|
+
ui.pause 1
|
28
|
+
|
29
|
+
show_todo_state
|
30
|
+
ui.pause 1.4
|
31
|
+
|
32
|
+
setup_dangerfile
|
33
|
+
setup_github_account
|
34
|
+
setup_access_token
|
35
|
+
setup_danger_ci
|
36
|
+
|
37
|
+
info
|
38
|
+
thanks
|
15
39
|
end
|
16
40
|
|
17
|
-
def
|
18
|
-
|
41
|
+
def ui
|
42
|
+
@ui ||= Interviewer.new
|
43
|
+
end
|
19
44
|
|
45
|
+
def show_todo_state
|
46
|
+
ui.say "We need to do the following steps:\n"
|
47
|
+
ui.pause 0.6
|
48
|
+
ui.say " - [ ] Create a Dangerfile and add a few simple rules."
|
49
|
+
ui.pause 0.6
|
50
|
+
ui.say " - [#{@account_created ? 'x' : ' '}] Create a GitHub account for Danger use for messaging."
|
51
|
+
ui.pause 0.6
|
52
|
+
ui.say " - [ ] Set up an access token for Danger."
|
53
|
+
ui.pause 0.6
|
54
|
+
ui.say " - [ ] Set up Danger to run on your CI.\n\n"
|
55
|
+
end
|
56
|
+
|
57
|
+
def setup_dangerfile
|
58
|
+
dir = Danger.gem_path
|
20
59
|
content = File.read(File.join(dir, "lib", "assets", "DangerfileTemplate"))
|
21
60
|
File.write("Dangerfile", content)
|
22
|
-
|
61
|
+
|
62
|
+
ui.header 'Step 1: Creating a starter Dangerfile'
|
63
|
+
ui.say "I've set up an example Dangerfile for you in this folder.\n"
|
64
|
+
ui.pause 1
|
65
|
+
|
66
|
+
ui.say "cat #{Dir.pwd}/Dangerfile\n".blue
|
67
|
+
content.lines.each do |l|
|
68
|
+
ui.say " " + l.chomp.green
|
69
|
+
end
|
70
|
+
ui.say ""
|
71
|
+
ui.pause 2
|
72
|
+
|
73
|
+
ui.say "There's a collection of small, simple ideas in here, but Danger is about being able to easily"
|
74
|
+
ui.say "iterate. The power comes from you have the ability to codify fixes to some of the problems"
|
75
|
+
ui.say "that come up in day to day programming. It can be difficult to try and see those from day 1."
|
76
|
+
|
77
|
+
ui.say "\nIf you'd like to investigate the file, and make some changes - I'll wait here,"
|
78
|
+
ui.say "press return when you're ready to move on…"
|
79
|
+
ui.wait_for_return
|
80
|
+
end
|
81
|
+
|
82
|
+
def setup_github_account
|
83
|
+
ui.header 'Step 2: Creating a GitHub account'
|
84
|
+
|
85
|
+
ui.say "In order to get the most out of Danger, I'd recommend given her the ability to post in"
|
86
|
+
ui.say "the code-review comment section.\n\n"
|
87
|
+
ui.pause 1
|
88
|
+
|
89
|
+
ui.say "IMO, it's best do this by using the private mode of your browser. Create an account like"
|
90
|
+
ui.say "#{@bot_name}, and don't forget a cool robot avatar.\n\n"
|
91
|
+
ui.pause 1
|
92
|
+
ui.say 'Here are great resources for creative commons images of robots:'
|
93
|
+
ui.link 'https://www.flickr.com/search/?text=robot&license=2%2C3%2C4%2C5%2C6%2C9'
|
94
|
+
ui.link 'https://www.google.com/search?q=robot&tbs=sur:fmc&tbm=isch&tbo=u&source=univ&sa=X&ved=0ahUKEwjgy8-f95jLAhWI7hoKHV_UD00QsAQIMQ&biw=1265&bih=1359'
|
95
|
+
|
96
|
+
ui.say ""
|
97
|
+
note_about_clicking_links
|
98
|
+
ui.pause 1
|
99
|
+
ui.say "\nCool, please press return when you have your account ready (and you've verified the email…)"
|
100
|
+
ui.wait_for_return
|
101
|
+
end
|
102
|
+
|
103
|
+
def setup_access_token
|
104
|
+
ui.header 'Step 3: Configuring a GitHub Personal Access Token'
|
105
|
+
|
106
|
+
ui.say "Here's the link, you should open this in your private session with the new GitHub account"
|
107
|
+
ui.link "https://github.com/settings/tokens/new"
|
108
|
+
ui.pause 1
|
109
|
+
|
110
|
+
@is_open_source = ui.ask_with_answers("For token access rights, I need to know if this is for an Open Source or Closed Source project\n", ["Open", "Closed"])
|
111
|
+
|
112
|
+
if considered_an_oss_repo?
|
113
|
+
ui.say "For Open Source projects, I'd recommend giving the token the smallest scope possible."
|
114
|
+
ui.say "This means only providing access to " + "public_info".yellow + " in the token.\n\n"
|
115
|
+
ui.pause 1
|
116
|
+
ui.say "This token limits Danger's abilities to just to writing comments on OSS projects. I recommend"
|
117
|
+
ui.say "this because the token can be quite easily be extracted from the environment via pull requests."
|
118
|
+
ui.say "#{@bot_name} does not need admin access to your repo. So it's ability to cause chaos is minimalized.\n"
|
119
|
+
|
120
|
+
elsif @is_open_source == "closed"
|
121
|
+
ui.say "For Closed Source projects, I'd recommend giving the token access to the whole repo scope."
|
122
|
+
ui.say "This means only providing access to " + "repo".yellow + ", and it's children in the token.\n\n"
|
123
|
+
ui.pause 1
|
124
|
+
ui.say "It's worth noting that you " + "should not".bold.white + " re-use this token for OSS repos. Make a new one for those repos with just " + "public_info".yellow + "."
|
125
|
+
end
|
126
|
+
|
127
|
+
ui.say "\n👍, please press return when you have your token set up…"
|
128
|
+
ui.wait_for_return
|
129
|
+
end
|
130
|
+
|
131
|
+
def considered_an_oss_repo?
|
132
|
+
@is_open_source == "open"
|
133
|
+
end
|
134
|
+
|
135
|
+
def current_repo_slug
|
136
|
+
@repo ||= Danger::CISource::LocalGitRepo.new
|
137
|
+
@repo.repo_slug || "[Your/Repo]"
|
138
|
+
end
|
139
|
+
|
140
|
+
def setup_danger_ci
|
141
|
+
ui.header 'Step 4: Add Danger for your CI'
|
142
|
+
|
143
|
+
uses_travis if File.exist? ".travis.yml"
|
144
|
+
uses_circle if File.exist? "circle.yml"
|
145
|
+
unsure_ci unless File.exist?(".travis.yml") || File.exist?(".circle.yml")
|
146
|
+
|
147
|
+
ui.say "\nOK, I'll give you a moment to do this…"
|
148
|
+
ui.wait_for_return
|
149
|
+
|
150
|
+
ui.say "Final step: exposing the GitHub token as a environment build variable."
|
151
|
+
ui.pause 0.4
|
152
|
+
if considered_an_oss_repo?
|
153
|
+
ui.say "As you have an Open Source repo, this token should be considered public, otherwise you cannot"
|
154
|
+
ui.say "run Danger on pull requests from forks, limiting it's use.\n"
|
155
|
+
ui.pause 1
|
156
|
+
end
|
157
|
+
|
158
|
+
travis_token if File.exist? ".travis.yml"
|
159
|
+
circle_token if File.exist? "circle.yml"
|
160
|
+
unsure_token unless File.exist?(".travis.yml") || File.exist?(".circle.yml")
|
161
|
+
|
162
|
+
ui.pause 0.6
|
163
|
+
ui.say "This is the last step, I can give you a second…"
|
164
|
+
ui.wait_for_return
|
165
|
+
end
|
166
|
+
|
167
|
+
def uses_travis
|
168
|
+
danger = "bundle exec danger".yellow
|
169
|
+
config = YAML.load(File.read(".travis.yml"))
|
170
|
+
if config["script"]
|
171
|
+
ui.say "Add " + "- ".yellow + danger + " as a new step in the " + "script".yellow + " section of your .travis.yml file."
|
172
|
+
else
|
173
|
+
ui.say "I'd recommend adding " + "script: ".yellow + danger + " to the script section of your .travis.yml file."
|
174
|
+
end
|
175
|
+
|
176
|
+
ui.pause 1
|
177
|
+
ui.say "You shouldn't use " + "after_success, after_failure, after_script".red + " as they cannot fail your builds."
|
178
|
+
end
|
179
|
+
|
180
|
+
def uses_circle
|
181
|
+
danger = "bundle exec danger".yellow
|
182
|
+
config = YAML.load(File.read("circle.yml"))
|
183
|
+
|
184
|
+
if config["test"]
|
185
|
+
if config["test"]["post"]
|
186
|
+
ui.say "Add " + danger + " as a new step in the " + "test:post:".yellow + " section of your circle.yml file."
|
187
|
+
else
|
188
|
+
ui.say "Add " + danger + " as a new step in the " + "test:override:".yellow + " section of your circle.yml file."
|
189
|
+
end
|
190
|
+
else
|
191
|
+
ui.say "Add this to the bottom of your circle.yml file:"
|
192
|
+
ui.say "test:".green
|
193
|
+
ui.say " post:".green
|
194
|
+
ui.say " - bundle exec danger".green
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
def unsure_ci
|
199
|
+
danger = "bundle exec danger".yellow
|
200
|
+
ui.say "As I'm not sure what CI you want to run Danger on base on the files in your repo, I'll just offer some generic"
|
201
|
+
ui.say "advice. You want to run " + danger + " after your tests have finished running, it should be during the testing"
|
202
|
+
ui.say "process so the build can fail."
|
203
|
+
end
|
204
|
+
|
205
|
+
def travis_token
|
206
|
+
# https://travis-ci.org/artsy/eigen/settings
|
207
|
+
ui.say "In order to add an environment variable, go to:"
|
208
|
+
ui.link "https://travis-ci.org/#{current_repo_slug}/settings"
|
209
|
+
ui.say "\nThe name is " + "DANGER_GITHUB_API_TOKEN".yellow + " and the value is the GitHub Personal Acess Token."
|
210
|
+
if @is_open_source
|
211
|
+
ui.say "Make sure to have \"Display value in build log\" enabled."
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
def circle_token
|
216
|
+
# https://circleci.com/gh/artsy/eigen/edit#env-vars
|
217
|
+
if considered_an_oss_repo?
|
218
|
+
ui.say "Before we start, it's important to be up-front. Circle CI only really has one option to support running Danger"
|
219
|
+
ui.say "for forks on OSS repos. It is quite a drastic option, and I want to let you know the best place to understand"
|
220
|
+
ui.say "the ramnifications for turning on a setting I'm about to advise.\n"
|
221
|
+
ui.link "https://circleci.com/docs/fork-pr-builds"
|
222
|
+
ui.say "TLDR: If you have anything other than Danger config settings in CircleCI, then you should not turn on the setting."
|
223
|
+
ui.say "I'll give you a minute to read it…"
|
224
|
+
ui.wait_for_return
|
225
|
+
|
226
|
+
ui.say "On Danger/Danger we turn on " + "Permissive building of fork pull requests".yellow + " this exposes the token to Danger"
|
227
|
+
ui.say "You can find this setting at:"
|
228
|
+
ui.link "https://circleci.com/gh/#{current_repo_slug}/edit#experimental\n"
|
229
|
+
ui.say "I'll hold…"
|
230
|
+
ui.wait_for_return
|
231
|
+
end
|
232
|
+
|
233
|
+
ui.say "In order to expose an environment variable, go to:"
|
234
|
+
ui.link "https://circleci.com/gh/#{repo_slug}/edit#env-vars"
|
235
|
+
ui.say "The name is " + "DANGER_GITHUB_API_TOKEN".yellow + " and the value is the GitHub Personal Acess Token."
|
236
|
+
end
|
237
|
+
|
238
|
+
def unsure_token
|
239
|
+
ui.say "You need to expose a token called " + "DANGER_GITHUB_API_TOKEN".yellow + " and the value is the GitHub Personal Acess Token."
|
240
|
+
ui.say "Depending on the CI system, this may need to be done on the machine ( in the " + "~/.bashprofile".yellow + ") or in a web UI somewhere."
|
241
|
+
end
|
242
|
+
|
243
|
+
def note_about_clicking_links
|
244
|
+
ui.say "Note: Holding cmd ( ⌘ ) and #{ENV['ITERM_SESSION_ID'] ? '' : 'double '}clicking a link will open it in your browser."
|
245
|
+
end
|
246
|
+
|
247
|
+
def info
|
248
|
+
ui.header "Useful info"
|
249
|
+
ui.say "- One of the best ways to test out new rules locally is via " + "bundle exec danger local".yellow + "."
|
250
|
+
ui.pause 0.6
|
251
|
+
ui.say "- You can have Danger output all of it's variables to the console via the " + "--verbose".yellow + "option."
|
252
|
+
ui.pause 0.6
|
253
|
+
ui.say "- You can look at the following Dangerfiles to get some more ideas:"
|
254
|
+
ui.pause 0.6
|
255
|
+
ui.link "https://github.com/danger/danger/blob/master/Dangerfile"
|
256
|
+
ui.link "https://github.com/artsy/eigen/blob/master/Dangerfile"
|
257
|
+
ui.pause 1
|
258
|
+
end
|
259
|
+
|
260
|
+
def thanks
|
261
|
+
ui.say "\n\n🎉"
|
262
|
+
ui.pause 0.6
|
263
|
+
|
264
|
+
ui.say "And you're set. Danger is a collaboration between Orta Therox, Gem 'Danger' McShane and Felix Krause."
|
265
|
+
ui.say "If you like it, let others know. If you want to know more, follow " + "@orta".yellow + " and " + "@krausefx".yellow + " on twitter."
|
266
|
+
ui.say "If you don't like it, help us improve it! xxx"
|
23
267
|
end
|
24
268
|
end
|
25
269
|
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
module Danger
|
2
|
+
class Interviewer
|
3
|
+
attr_accessor :no_delay, :no_waiting
|
4
|
+
|
5
|
+
def show_prompt
|
6
|
+
print "> ".bold.green
|
7
|
+
end
|
8
|
+
|
9
|
+
def yellow_bang
|
10
|
+
"! ".yellow
|
11
|
+
end
|
12
|
+
|
13
|
+
def green_bang
|
14
|
+
"! ".green
|
15
|
+
end
|
16
|
+
|
17
|
+
def red_bang
|
18
|
+
"! ".red
|
19
|
+
end
|
20
|
+
|
21
|
+
def say(output)
|
22
|
+
puts output
|
23
|
+
end
|
24
|
+
|
25
|
+
def header(title)
|
26
|
+
say title.yellow
|
27
|
+
say ''
|
28
|
+
pause 0.6
|
29
|
+
end
|
30
|
+
|
31
|
+
def link(url)
|
32
|
+
say " -> " + url.underline + "\n"
|
33
|
+
end
|
34
|
+
|
35
|
+
def pause(time)
|
36
|
+
sleep(time) unless @no_waiting
|
37
|
+
end
|
38
|
+
|
39
|
+
def wait_for_return
|
40
|
+
STDOUT.flush
|
41
|
+
STDIN.gets unless @no_delay
|
42
|
+
puts ""
|
43
|
+
end
|
44
|
+
|
45
|
+
def run_command(command, output_command = nil)
|
46
|
+
output_command ||= command
|
47
|
+
puts " " + output_command.magenta
|
48
|
+
system command
|
49
|
+
end
|
50
|
+
|
51
|
+
def ask(question)
|
52
|
+
answer = ""
|
53
|
+
loop do
|
54
|
+
puts "\n#{question}?"
|
55
|
+
|
56
|
+
show_prompt
|
57
|
+
answer = STDIN.gets.chomp
|
58
|
+
|
59
|
+
break if answer.length > 0
|
60
|
+
|
61
|
+
print "\nYou need to provide an answer."
|
62
|
+
end
|
63
|
+
answer
|
64
|
+
end
|
65
|
+
|
66
|
+
def ask_with_answers(question, possible_answers)
|
67
|
+
print "\n#{question}? ["
|
68
|
+
|
69
|
+
print_info = proc do
|
70
|
+
possible_answers.each_with_index do |answer, i|
|
71
|
+
the_answer = (i == 0) ? answer.underline : answer
|
72
|
+
print " " + the_answer
|
73
|
+
print(" /") if i != possible_answers.length - 1
|
74
|
+
end
|
75
|
+
print " ]\n"
|
76
|
+
end
|
77
|
+
print_info.call
|
78
|
+
|
79
|
+
answer = ""
|
80
|
+
|
81
|
+
loop do
|
82
|
+
show_prompt
|
83
|
+
answer = @no_waiting ? possible_answers[0].downcase : STDIN.gets.downcase.chomp
|
84
|
+
|
85
|
+
answer = "yes" if answer == "y"
|
86
|
+
answer = "no" if answer == "n"
|
87
|
+
|
88
|
+
# default to first answer
|
89
|
+
if answer == ""
|
90
|
+
answer = possible_answers[0].downcase
|
91
|
+
puts "Using: " + answer.yellow
|
92
|
+
end
|
93
|
+
|
94
|
+
break if possible_answers.map(&:downcase).include? answer
|
95
|
+
|
96
|
+
print "\nPossible answers are ["
|
97
|
+
print_info.call
|
98
|
+
end
|
99
|
+
|
100
|
+
answer
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module Danger
|
2
2
|
class Local < Runner
|
3
|
-
self.
|
3
|
+
self.summary = 'Run the Dangerfile locally.'
|
4
4
|
self.command = 'local'
|
5
5
|
|
6
6
|
def initialize(argv)
|
@@ -45,7 +45,8 @@ module Danger
|
|
45
45
|
dm.env.request_source = gh
|
46
46
|
|
47
47
|
dm.env.scm = GitRepo.new
|
48
|
-
|
48
|
+
|
49
|
+
dm.env.scm.diff_for_folder(".", from: dm.env.ci_source.base_commit, to: dm.env.ci_source.head_commit)
|
49
50
|
dm.parse Pathname.new(@dangerfile_path)
|
50
51
|
end
|
51
52
|
end
|
@@ -3,7 +3,7 @@ module Danger
|
|
3
3
|
require 'danger/commands/init'
|
4
4
|
require 'danger/commands/local'
|
5
5
|
|
6
|
-
self.
|
6
|
+
self.summary = 'Run the Dangerfile.'
|
7
7
|
self.command = 'danger'
|
8
8
|
|
9
9
|
def initialize(argv)
|
@@ -39,7 +39,8 @@ module Danger
|
|
39
39
|
ci_base = @base || gh.base_commit
|
40
40
|
ci_head = @head || gh.head_commit
|
41
41
|
|
42
|
-
dm.env.scm.diff_for_folder(".", ci_base, ci_head)
|
42
|
+
dm.env.scm.diff_for_folder(".", from: ci_base, to: ci_head)
|
43
|
+
|
43
44
|
dm.parse Pathname.new(@dangerfile_path)
|
44
45
|
|
45
46
|
post_results(dm)
|
@@ -1,14 +1,24 @@
|
|
1
1
|
<% @tables.each do |table| %>
|
2
2
|
<% if table[:content].any? %>
|
3
|
-
|
4
|
-
|
3
|
+
<table>
|
4
|
+
<thead>
|
5
|
+
<tr>
|
6
|
+
<th width="50"></th>
|
7
|
+
<th width="100%"><%= table[:content].count %> <%= table[:name] %><%= "s" unless table[:content].count == 1 %></th>
|
8
|
+
</tr>
|
9
|
+
</thead>
|
10
|
+
<tbody>
|
5
11
|
<% table[:content].each do |message| -%>
|
6
|
-
|
12
|
+
<tr>
|
13
|
+
<td>:<%= table[:emoji] %>:</td>
|
14
|
+
<td><%= message %></td>
|
15
|
+
</tr>
|
7
16
|
<% end %>
|
8
|
-
|
17
|
+
</tbody>
|
18
|
+
</table>
|
9
19
|
<% end %>
|
10
20
|
<% end %>
|
11
21
|
|
12
22
|
<p align="right" data-meta="generated_by_danger" data-base-commit="<%= @base_commit %>" data-head-commit="<%= @head_commit %>" >
|
13
|
-
Generated by :no_entry_sign: <a href="https://github.com/
|
23
|
+
Generated by :no_entry_sign: <a href="https://github.com/danger/danger/">danger</a>
|
14
24
|
</p>
|
data/lib/danger/dangerfile.rb
CHANGED
@@ -23,24 +23,35 @@ module Danger
|
|
23
23
|
|
24
24
|
# Iterates through the DSL's attributes, and table's the output
|
25
25
|
def print_known_info
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
26
|
+
rows = []
|
27
|
+
|
28
|
+
AvailableValues.all.each do |key|
|
29
|
+
next if key == :pr_body
|
30
|
+
value = self.send(key)
|
31
|
+
|
32
|
+
# So that we either have one value per row
|
33
|
+
# or we have [] for an empty array
|
34
|
+
value = value.join("\n") if value.kind_of?(Array) && value.count > 0
|
35
|
+
|
36
|
+
rows << [key.to_s, value]
|
33
37
|
end
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
38
|
+
|
39
|
+
rows << ["---", "---"]
|
40
|
+
rows << ["SCM", env.scm.class]
|
41
|
+
rows << ["Source", env.ci_source.class]
|
42
|
+
rows << ["Requests", env.request_source.class]
|
43
|
+
rows << ["Base Commit", env.request_source.base_commit]
|
44
|
+
rows << ["Head Commit", env.request_source.head_commit]
|
45
|
+
|
46
|
+
params = {}
|
47
|
+
params[:rows] = rows.each { |current| current[0] = current[0].yellow }
|
48
|
+
params[:title] = "Danger v#{Danger::VERSION}\nDSL Attributes".green
|
49
|
+
|
50
|
+
puts ""
|
51
|
+
puts Terminal::Table.new(params)
|
52
|
+
puts "PR Body:"
|
53
|
+
puts self.pr_body.cyan
|
54
|
+
puts ""
|
44
55
|
end
|
45
56
|
|
46
57
|
# Parses the file at a path, optionally takes the content of the file for DI
|
@@ -1,8 +1,6 @@
|
|
1
1
|
# coding: utf-8
|
2
|
-
require 'rest'
|
3
|
-
require 'json'
|
4
|
-
require 'base64'
|
5
2
|
require 'octokit'
|
3
|
+
require 'redcarpet'
|
6
4
|
|
7
5
|
module Danger
|
8
6
|
class GitHub
|
@@ -25,6 +23,10 @@ module Danger
|
|
25
23
|
)
|
26
24
|
end
|
27
25
|
|
26
|
+
def markdown_parser
|
27
|
+
@markdown_parser ||= Redcarpet::Markdown.new(Redcarpet::Render::HTML)
|
28
|
+
end
|
29
|
+
|
28
30
|
def fetch_details
|
29
31
|
self.pr_json = client.pull_request(ci_source.repo_slug, ci_source.pull_request_id)
|
30
32
|
fetch_issue_details(self.pr_json)
|
@@ -138,11 +140,18 @@ module Danger
|
|
138
140
|
# erb: http://www.rrn.dk/rubys-erb-templating-system
|
139
141
|
# for the extra args: http://stackoverflow.com/questions/4632879/erb-template-removing-the-trailing-line
|
140
142
|
@tables = [
|
141
|
-
{ name: "Error", emoji: "no_entry_sign", content: errors },
|
142
|
-
{ name: "Warning", emoji: "warning", content: warnings },
|
143
|
-
{ name: "Message", emoji: "book", content: messages }
|
143
|
+
{ name: "Error", emoji: "no_entry_sign", content: errors.map { |s| process_markdown(s) } },
|
144
|
+
{ name: "Warning", emoji: "warning", content: warnings.map { |s| process_markdown(s) } },
|
145
|
+
{ name: "Message", emoji: "book", content: messages.map { |s| process_markdown(s) } }
|
144
146
|
]
|
145
147
|
return ERB.new(File.read(md_template), 0, "-").result(binding)
|
146
148
|
end
|
149
|
+
|
150
|
+
def process_markdown(string)
|
151
|
+
html = markdown_parser.render(string)
|
152
|
+
match = html.match(%r{^<p>(.*)</p>$})
|
153
|
+
return match.captures.first unless match.nil?
|
154
|
+
html
|
155
|
+
end
|
147
156
|
end
|
148
157
|
end
|
@@ -1,38 +1,38 @@
|
|
1
1
|
# For more info see: https://github.com/schacon/ruby-git
|
2
2
|
|
3
|
-
require '
|
3
|
+
require 'grit'
|
4
4
|
|
5
5
|
module Danger
|
6
6
|
class GitRepo
|
7
7
|
attr_accessor :diff
|
8
8
|
|
9
|
-
def diff_for_folder(folder, from
|
10
|
-
|
11
|
-
self.diff =
|
9
|
+
def diff_for_folder(folder, from: "master", to: 'HEAD')
|
10
|
+
repo = Grit::Repo.new folder
|
11
|
+
self.diff = repo.diff(from, to)
|
12
12
|
end
|
13
13
|
|
14
|
-
def
|
15
|
-
@diff.
|
14
|
+
def files_added
|
15
|
+
@diff.select(&:new_file).map(&:b_path)
|
16
16
|
end
|
17
17
|
|
18
|
-
def
|
19
|
-
@diff.
|
18
|
+
def files_deleted
|
19
|
+
@diff.select(&:deleted_file).map(&:a_path)
|
20
20
|
end
|
21
21
|
|
22
|
-
def
|
23
|
-
@diff.
|
22
|
+
def files_modified
|
23
|
+
@diff.reject(&:deleted_file).reject(&:new_file).map(&:a_path)
|
24
24
|
end
|
25
25
|
|
26
26
|
def lines_of_code
|
27
|
-
@diff.lines
|
27
|
+
@diff.map(&:diff).map(&:lines).flatten.count { |l| l.start_with?("+") || l.start_with?("-") }
|
28
28
|
end
|
29
29
|
|
30
30
|
def deletions
|
31
|
-
@diff.
|
31
|
+
@diff.map(&:diff).map(&:lines).flatten.count { |l| l.start_with?("-") }
|
32
32
|
end
|
33
33
|
|
34
34
|
def insertions
|
35
|
-
@diff.
|
35
|
+
@diff.map(&:diff).map(&:lines).flatten.count { |l| l.start_with?("+") }
|
36
36
|
end
|
37
37
|
end
|
38
38
|
end
|
data/lib/danger/version.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.5.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-02-
|
12
|
+
date: 2016-02-28 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: claide
|
@@ -26,35 +26,35 @@ dependencies:
|
|
26
26
|
- !ruby/object:Gem::Version
|
27
27
|
version: '0'
|
28
28
|
- !ruby/object:Gem::Dependency
|
29
|
-
name:
|
29
|
+
name: grit
|
30
30
|
requirement: !ruby/object:Gem::Requirement
|
31
31
|
requirements:
|
32
|
-
- -
|
32
|
+
- - '='
|
33
33
|
- !ruby/object:Gem::Version
|
34
|
-
version:
|
34
|
+
version: 2.5.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: 2.5.0
|
42
42
|
- !ruby/object:Gem::Dependency
|
43
43
|
name: colored
|
44
44
|
requirement: !ruby/object:Gem::Requirement
|
45
45
|
requirements:
|
46
|
-
- - "
|
46
|
+
- - "~>"
|
47
47
|
- !ruby/object:Gem::Version
|
48
|
-
version: '
|
48
|
+
version: '1.2'
|
49
49
|
type: :runtime
|
50
50
|
prerelease: false
|
51
51
|
version_requirements: !ruby/object:Gem::Requirement
|
52
52
|
requirements:
|
53
|
-
- - "
|
53
|
+
- - "~>"
|
54
54
|
- !ruby/object:Gem::Version
|
55
|
-
version: '
|
55
|
+
version: '1.2'
|
56
56
|
- !ruby/object:Gem::Dependency
|
57
|
-
name:
|
57
|
+
name: faraday
|
58
58
|
requirement: !ruby/object:Gem::Requirement
|
59
59
|
requirements:
|
60
60
|
- - ">="
|
@@ -71,16 +71,44 @@ dependencies:
|
|
71
71
|
name: octokit
|
72
72
|
requirement: !ruby/object:Gem::Requirement
|
73
73
|
requirements:
|
74
|
-
- - "
|
74
|
+
- - "~>"
|
75
75
|
- !ruby/object:Gem::Version
|
76
|
-
version: '
|
76
|
+
version: '4.2'
|
77
77
|
type: :runtime
|
78
78
|
prerelease: false
|
79
79
|
version_requirements: !ruby/object:Gem::Requirement
|
80
80
|
requirements:
|
81
|
-
- - "
|
81
|
+
- - "~>"
|
82
82
|
- !ruby/object:Gem::Version
|
83
|
-
version: '
|
83
|
+
version: '4.2'
|
84
|
+
- !ruby/object:Gem::Dependency
|
85
|
+
name: redcarpet
|
86
|
+
requirement: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - "~>"
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '3.3'
|
91
|
+
type: :runtime
|
92
|
+
prerelease: false
|
93
|
+
version_requirements: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - "~>"
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '3.3'
|
98
|
+
- !ruby/object:Gem::Dependency
|
99
|
+
name: terminal-table
|
100
|
+
requirement: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - "~>"
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '1'
|
105
|
+
type: :runtime
|
106
|
+
prerelease: false
|
107
|
+
version_requirements: !ruby/object:Gem::Requirement
|
108
|
+
requirements:
|
109
|
+
- - "~>"
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '1'
|
84
112
|
- !ruby/object:Gem::Dependency
|
85
113
|
name: bundler
|
86
114
|
requirement: !ruby/object:Gem::Requirement
|
@@ -184,10 +212,12 @@ files:
|
|
184
212
|
- lib/danger/ci_source/buildkite.rb
|
185
213
|
- lib/danger/ci_source/ci_source.rb
|
186
214
|
- lib/danger/ci_source/circle.rb
|
215
|
+
- lib/danger/ci_source/jenkins.rb
|
187
216
|
- lib/danger/ci_source/local_git_repo.rb
|
188
217
|
- lib/danger/ci_source/travis.rb
|
189
218
|
- lib/danger/circle_api.rb
|
190
219
|
- lib/danger/commands/init.rb
|
220
|
+
- lib/danger/commands/init_helpers/interviewer.rb
|
191
221
|
- lib/danger/commands/local.rb
|
192
222
|
- lib/danger/commands/runner.rb
|
193
223
|
- lib/danger/comment_generators/github.md.erb
|
@@ -198,7 +228,7 @@ files:
|
|
198
228
|
- lib/danger/scm_source/git_repo.rb
|
199
229
|
- lib/danger/standard_error.rb
|
200
230
|
- lib/danger/version.rb
|
201
|
-
homepage: http://github.com/
|
231
|
+
homepage: http://github.com/danger/danger
|
202
232
|
licenses:
|
203
233
|
- MIT
|
204
234
|
metadata: {}
|