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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 00d92eed49b5e7fc0093a196fead65e3e9f6eaa8
4
- data.tar.gz: bd6ed16e33d9127c511018c3b55d4cf68db67524
3
+ metadata.gz: b830d9fd6b6ce7b6a2141b4cb7e5b801f44ae202
4
+ data.tar.gz: 9769485c2b763df4caa907614622913f70042921
5
5
  SHA512:
6
- metadata.gz: d10ab63bf1fd7f244187c854b2ae092b8dbb20f73ba61d8041375476dfd2b5d8cf80c5a778fe9d20b41a8b8539c62c2b83a2400eb79f5cebb1042d6cb1aab358
7
- data.tar.gz: 3a94d29282e62e9396508fd8ad9563202c160d3e81cdc201d45567f40af465c07d6a774c0812ee899fde63ddf79f9d55408449685a84ffbcaff0884a9ab1d678
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> &bull;
13
12
  <a href="#usage">Usage</a> &bull;
@@ -19,7 +18,7 @@ Formalize your Pull Request etiquette.
19
18
 
20
19
  -------
21
20
 
22
- ## Installation
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 to set up `danger` for your repository
29
+ and then run the following, which will help walk you through getting set up: `bundle exec danger init`.
31
30
 
32
- ```
33
- danger init
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
- ## Usage
35
+ ## What happens?
37
36
 
38
- In CI run `bundle exec danger`. This will look at your `Dangerfile` and provide some feedback based on that.
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
- You can then create a `Dangerfile` like the following:
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
- # Easy checks
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
- if lines_of_code > 50 && files_modified.include?("CHANGELOG.yml") == false
60
- fail("No CHANGELOG changes made")
61
- end
65
+ #### Being cautious around specific files
62
66
 
63
- # Stop skipping some manual testing
64
- if lines_of_code > 50 && pr_title.include?("📱") == false
65
- fail("Needs testing on a Phone if change is non-trivial")
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
- message("This pull request adds #{lines_of_code} new lines")
69
- warn("Author @#{pr_author} is not a contributor") unless ["KrauseFx", "orta"].include?(pr_author)
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
- ## Constraints
89
+ #### Exposing aspects of CI logs into the PR discussion
73
90
 
74
- * **GitHub** - Built with same-repo PRs in mind
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
  &nbsp; | 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 [GitDiff](https://github.com/schacon/ruby-git/blob/master/lib/git/diff.rb) file for the diff.
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 ATM
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
- puts "OK"
2
- puts "Lines"
3
- puts lines_of_code
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
- puts ""
10
- puts pr_body
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
- warn("Some random warning")
15
- fail("Orta is not really orta")
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
@@ -7,6 +7,7 @@ require "danger/available_values"
7
7
  require "claide"
8
8
  require "colored"
9
9
  require "pathname"
10
+ require "terminal-table"
10
11
 
11
12
  # Import all the Sources (CI, Request and SCM)
12
13
  Dir[File.expand_path('danger/*source/*.rb', File.dirname(__FILE__))].each do |file|
@@ -9,7 +9,7 @@ module Danger
9
9
  [
10
10
  :lines_of_code,
11
11
  :files_modified,
12
- :files_removed,
12
+ :files_deleted,
13
13
  :files_added,
14
14
  :deletions,
15
15
  :insertions
@@ -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 'git'
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
- git = Git.open(".")
17
- if git.remote("origin")
18
- url = git.remote("origin").url
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
- logs = git.log.since('2 weeks ago')
30
- # Look for something like
31
- # "Merge pull request #38 from KrauseFx/funky_circles\n\nAdd support for GitHub compare URLs that don't conform
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
- # then pull out the 38, to_i
35
- self.pull_request_id = pr_merge.message.gsub("Merge pull request #", "").to_i
36
- self.base_commit = pr_merge.parents[0].sha
37
- self.head_commit = pr_merge.parents[1].sha
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
@@ -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.description = 'Creates a Dangerfile.'
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
- @dangerfile_path = "Dangerfile" if File.exist? "Dangerfile"
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 validate!
12
- if @dangerfile_path
13
- help! "Found an existing Dangerfile."
14
- end
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 run
18
- dir = Danger.gem_path
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
- puts "Successfully created 'Dangerfile'"
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.description = 'Run the Dangerfile locally.'
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
- dm.env.scm.diff_for_folder(".", dm.env.ci_source.base_commit, dm.env.ci_source.head_commit)
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.description = 'Run the Dangerfile.'
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
- &nbsp; | <%= table[:content].count %> <%= table[:name] %><%= "s" unless table[:content].count == 1 %>
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
- :<%= table[:emoji] %>: | <%= message %>
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/KrauseFx/danger/">danger</a>
23
+ Generated by :no_entry_sign: <a href="https://github.com/danger/danger/">danger</a>
14
24
  </p>
@@ -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
- puts "Danger v#{Danger::VERSION}"
27
- width = AvailableValues.all.map(&:to_s).map(&:length).max
28
- puts "DSL Attributes:"
29
- puts "-" * (width + 4)
30
- AvailableValues.all.each do |value|
31
- spaces = (width - value.to_s.length)
32
- puts "| #{value.to_s.blue}#{' ' * spaces} | #{self.send(value)}"
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
- puts "-" * (width + 4)
35
-
36
- puts "Metadata:"
37
- puts "#{'SCM'.blue} : #{env.scm.class}"
38
- puts "#{'Source'.blue} : #{env.ci_source.class}"
39
- puts "#{'Requests'.blue} : #{env.request_source.class}"
40
- puts " #{'Base commit'.blue} : #{env.request_source.base_commit}"
41
- puts " #{'HEAD commit'.blue} : #{env.request_source.head_commit}"
42
- puts " git diff #{env.request_source.base_commit} #{env.request_source.head_commit}".yellow
43
- puts "\n\n"
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 'git'
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 = "master", to = 'HEAD')
10
- g = Git.open(folder)
11
- self.diff = g.diff(from, to)
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 files_modified
15
- @diff.to_a.map(&:path)
14
+ def files_added
15
+ @diff.select(&:new_file).map(&:b_path)
16
16
  end
17
17
 
18
- def files_removed
19
- @diff.to_a.select { |d| d.type == "deleted" }.map(&:path)
18
+ def files_deleted
19
+ @diff.select(&:deleted_file).map(&:a_path)
20
20
  end
21
21
 
22
- def files_added
23
- @diff.to_a.select { |d| d.type == "new" }.map(&:path)
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.deletions
31
+ @diff.map(&:diff).map(&:lines).flatten.count { |l| l.start_with?("-") }
32
32
  end
33
33
 
34
34
  def insertions
35
- @diff.insertions
35
+ @diff.map(&:diff).map(&:lines).flatten.count { |l| l.start_with?("+") }
36
36
  end
37
37
  end
38
38
  end
@@ -1,4 +1,4 @@
1
1
  module Danger
2
- VERSION = "0.3.0"
2
+ VERSION = "0.5.0"
3
3
  DESCRIPTION = "Automate your PR etiquette."
4
4
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: danger
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.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 00:00:00.000000000 Z
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: git
29
+ name: grit
30
30
  requirement: !ruby/object:Gem::Requirement
31
31
  requirements:
32
- - - "~>"
32
+ - - '='
33
33
  - !ruby/object:Gem::Version
34
- version: 1.2.9
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: 1.2.9
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: '0'
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: '0'
55
+ version: '1.2'
56
56
  - !ruby/object:Gem::Dependency
57
- name: nap
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: '0'
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: '0'
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/orta/danger
231
+ homepage: http://github.com/danger/danger
202
232
  licenses:
203
233
  - MIT
204
234
  metadata: {}