danger 0.2.1 → 0.3.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: 2b3337b2e55d499b082ba5f7aed4f5216e95349c
4
- data.tar.gz: c1bfe7f5a5de81631266d4afa0d82ca8d8f8b31d
3
+ metadata.gz: 00d92eed49b5e7fc0093a196fead65e3e9f6eaa8
4
+ data.tar.gz: bd6ed16e33d9127c511018c3b55d4cf68db67524
5
5
  SHA512:
6
- metadata.gz: 5ab6e3ef7b0db9db6032a2dbaea15d41ea56c7fdbc552677298cbd9c6587bb99346ad022b494f07917059a024252d785eff6ed0a821412c480f47bd715fb7c32
7
- data.tar.gz: 714c8816a1fe0c8965460266f129589a8064b57dd0c601ed8b91f312a92e0e6bde6d522aa14f135efc2cc33e96047201aa1e36d2115f4a7bb34a77679c3424d0
6
+ metadata.gz: d10ab63bf1fd7f244187c854b2ae092b8dbb20f73ba61d8041375476dfd2b5d8cf80c5a778fe9d20b41a8b8539c62c2b83a2400eb79f5cebb1042d6cb1aab358
7
+ data.tar.gz: 3a94d29282e62e9396508fd8ad9563202c160d3e81cdc201d45567f40af465c07d6a774c0812ee899fde63ddf79f9d55408449685a84ffbcaff0884a9ab1d678
data/README.md CHANGED
@@ -5,15 +5,15 @@
5
5
 
6
6
  Formalize your Pull Request etiquette.
7
7
 
8
- *Note:* Not ready for public usage yet. Work in progress
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
9
 
10
10
  -------
11
11
  <p align="center">
12
- <a href="#installation">Installation</a> &bull;
13
- <a href="#usage">Usage</a> &bull;
14
- <a href="#dsl">DSL</a> &bull;
15
- <a href="#constraints">Constraints</a> &bull;
16
- <a href="#advanced">Advanced</a> &bull;
12
+ <a href="#installation">Installation</a> &bull;
13
+ <a href="#usage">Usage</a> &bull;
14
+ <a href="#dsl">DSL</a> &bull;
15
+ <a href="#constraints">Constraints</a> &bull;
16
+ <a href="#advanced">Advanced</a> &bull;
17
17
  <a href="#contributing">Contributing</a>
18
18
  </p>
19
19
 
@@ -48,6 +48,7 @@ In CI run `bundle exec danger`. This will look at your `Dangerfile` and provide
48
48
  :abc: | `pr_title` | The title of the PR
49
49
  :book: | `pr_body` | The body of the PR
50
50
  :busts_in_silhouette: | `pr_author` | The author who submitted the PR
51
+ :bookmark: | `pr_labels` | The labels added to the PR
51
52
 
52
53
  You can then create a `Dangerfile` like the following:
53
54
 
@@ -71,7 +72,6 @@ warn("Author @#{pr_author} is not a contributor") unless ["KrauseFx", "orta"].in
71
72
  ## Constraints
72
73
 
73
74
  * **GitHub** - Built with same-repo PRs in mind
74
- * **Git** - Built with master as the merge branch
75
75
 
76
76
  ## Advanced
77
77
 
@@ -83,10 +83,15 @@ You can access more detailed information by accessing the following variables
83
83
  `env.scm.diff` | The full [GitDiff](https://github.com/schacon/ruby-git/blob/master/lib/git/diff.rb) file for the diff.
84
84
  `env.ci_source` | To get information like the repo slug or pull request ID
85
85
 
86
- ## Special Thanks
86
+ ## Test locally with `danger local`
87
87
 
88
- Thanks [@orta](https://twitter.com/orta) for starting this project
88
+ Using `danger local` will look for the last merged pull request in your git history, and apply your current
89
+ `Dangerfile` against that Pull Request. Useful when editing.
90
+
91
+ ## Useful bits of knowledge ATM
92
+
93
+ * You can set the base branch in the command line arguments see: `bundle exec danger --help`.
89
94
 
90
95
  ## License
91
96
 
92
- > 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.
97
+ > 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.
@@ -20,7 +20,8 @@ module Danger
20
20
  [
21
21
  :pr_title,
22
22
  :pr_body,
23
- :pr_author
23
+ :pr_author,
24
+ :pr_labels
24
25
  ]
25
26
  end
26
27
  end
@@ -1,20 +1,47 @@
1
1
  # https://circleci.com/docs/environment-variables
2
2
  require 'uri'
3
+ require 'danger/circle_api'
3
4
 
4
5
  module Danger
5
6
  module CISource
6
7
  class CircleCI < CI
7
8
  def self.validates?(env)
8
- return !env["CIRCLE_BUILD_NUM"].nil? &&
9
- !env["CI_PULL_REQUEST"].nil? &&
10
- URI.parse(env["CI_PULL_REQUEST"]).path.split("/").count == 5
9
+ return false if env["CIRCLE_BUILD_NUM"].nil?
10
+ return true unless env["CI_PULL_REQUEST"].nil?
11
+
12
+ return !env["CIRCLE_PROJECT_USERNAME"].nil? && !env["CIRCLE_PROJECT_REPONAME"].nil?
13
+ end
14
+
15
+ def client
16
+ @client ||= CircleAPI.new(@circle_token)
17
+ end
18
+
19
+ def fetch_pull_request_url(repo_slug, build_number)
20
+ build_json = client.fetch_build(repo_slug, build_number)
21
+ build_json[:pull_request_urls].first
22
+ end
23
+
24
+ def pull_request_url(env)
25
+ url = env["CI_PULL_REQUEST"]
26
+
27
+ if url.nil? && !env["CIRCLE_PROJECT_USERNAME"].nil? && !env["CIRCLE_PROJECT_REPONAME"].nil?
28
+ repo_slug = env["CIRCLE_PROJECT_USERNAME"] + "/" + env["CIRCLE_PROJECT_REPONAME"]
29
+ url = fetch_pull_request_url(repo_slug, env["CIRCLE_BUILD_NUM"])
30
+ end
31
+
32
+ url
11
33
  end
12
34
 
13
35
  def initialize(env)
14
- paths = URI.parse(env["CI_PULL_REQUEST"]).path.split("/")
15
- # The first one is an extra slash, ignore it
16
- self.repo_slug = paths[1] + "/" + paths[2]
17
- self.pull_request_id = paths[4]
36
+ @circle_token = env["CIRCLE_CI_API_TOKEN"]
37
+ url = pull_request_url(env)
38
+
39
+ if URI.parse(url).path.split("/").count == 5
40
+ paths = URI.parse(url).path.split("/")
41
+ # The first one is an extra slash, ignore it
42
+ self.repo_slug = paths[1] + "/" + paths[2]
43
+ self.pull_request_id = paths[4]
44
+ end
18
45
  end
19
46
  end
20
47
  end
@@ -0,0 +1,42 @@
1
+ # For more info see: https://github.com/schacon/ruby-git
2
+
3
+ require 'git'
4
+ require 'uri'
5
+
6
+ module Danger
7
+ module CISource
8
+ class LocalGitRepo < CI
9
+ attr_accessor :base_commit, :head_commit
10
+
11
+ def self.validates?(env)
12
+ return !env["DANGER_USE_LOCAL_GIT"].nil?
13
+ end
14
+
15
+ def initialize(*)
16
+ git = Git.open(".")
17
+ if git.remote("origin")
18
+ url = git.remote("origin").url
19
+ # deal with https://
20
+ if url.start_with? "https://github.com/"
21
+ self.repo_slug = url.gsub("https://github.com/", "").gsub(".git", '')
22
+
23
+ # deal with SSH origin
24
+ elsif url.start_with? "git@github.com:"
25
+ self.repo_slug = url.gsub("git@github.com:", "").gsub(".git", '')
26
+ end
27
+ end
28
+
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 }
33
+ 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
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,23 @@
1
+ require 'faraday'
2
+
3
+ module Danger
4
+ class CircleAPI
5
+ attr_accessor :circle_token
6
+
7
+ def initialize(circle_token = nil)
8
+ self.circle_token = circle_token
9
+ end
10
+
11
+ def client
12
+ @client ||= Faraday.new(url: 'https://circleci.com/api/v1')
13
+ end
14
+
15
+ def fetch_build(repo_slug, build_number)
16
+ url = "project/#{repo_slug}/#{build_number}"
17
+ params = { :'circle-token' => circle_token }
18
+ response = client.get url, params, accept: 'application/json'
19
+ json = JSON.parse(response.body, symbolize_names: true)
20
+ json
21
+ end
22
+ end
23
+ end
@@ -1,5 +1,5 @@
1
1
  module Danger
2
- class Init < Danger::Runner
2
+ class Init < Runner
3
3
  self.description = 'Creates a Dangerfile.'
4
4
  self.command = 'init'
5
5
 
@@ -0,0 +1,52 @@
1
+ module Danger
2
+ class Local < Runner
3
+ self.description = 'Run the Dangerfile locally.'
4
+ self.command = 'local'
5
+
6
+ def initialize(argv)
7
+ @dangerfile_path = "Dangerfile" if File.exist? "Dangerfile"
8
+ super
9
+ end
10
+
11
+ def validate!
12
+ super
13
+ unless @dangerfile_path
14
+ help! "Could not find a Dangerfile."
15
+ end
16
+ end
17
+
18
+ def run
19
+ ENV["DANGER_USE_LOCAL_GIT"] = "YES"
20
+
21
+ dm = Dangerfile.new
22
+ dm.env = EnvironmentManager.new(ENV)
23
+
24
+ source = dm.env.ci_source
25
+ unless source.repo_slug
26
+ puts "danger local".red " failed because it only works with GitHub projects at the moment. Sorry."
27
+ exit 0
28
+ end
29
+
30
+ puts "Running your Dangerfile against this PR - https://github.com/#{source.repo_slug}/pulls/#{source.pull_request_id}"
31
+
32
+ if verbose != true
33
+ puts "Turning on --verbose"
34
+ dm.verbose = true
35
+ end
36
+
37
+ puts ""
38
+
39
+ gh = GitHub.new(dm.env.ci_source, ENV)
40
+ # We can use tokenless here, as it's running on someone's computer
41
+ # and is IP locked, as opposed to on the CI.
42
+ gh.support_tokenless_auth = true
43
+ gh.fetch_details
44
+
45
+ dm.env.request_source = gh
46
+
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)
49
+ dm.parse Pathname.new(@dangerfile_path)
50
+ end
51
+ end
52
+ end
@@ -1,10 +1,15 @@
1
1
  module Danger
2
2
  class Runner < CLAide::Command
3
+ require 'danger/commands/init'
4
+ require 'danger/commands/local'
5
+
3
6
  self.description = 'Run the Dangerfile.'
4
7
  self.command = 'danger'
5
8
 
6
9
  def initialize(argv)
7
10
  @dangerfile_path = "Dangerfile" if File.exist? "Dangerfile"
11
+ @base = argv.option('base')
12
+ @head = argv.option('head')
8
13
  super
9
14
  end
10
15
 
@@ -15,13 +20,26 @@ module Danger
15
20
  end
16
21
  end
17
22
 
23
+ def self.options
24
+ [
25
+ ['--base=[master|dev|stable]', 'A branch/tag/commit to use as the base of the diff'],
26
+ ['--head=[master|dev|stable]', 'A branch/tag/commit to use as the head']
27
+ ].concat(super)
28
+ end
29
+
18
30
  def run
19
31
  # The order of the following commands is *really* important
20
32
  dm = Dangerfile.new
33
+ dm.verbose = verbose
21
34
  dm.env = EnvironmentManager.new(ENV)
22
35
  return unless dm.env.ci_source # if it's not a PR
23
36
  dm.env.fill_environment_vars
24
- dm.env.scm.diff_for_folder(".")
37
+
38
+ gh = dm.env.request_source
39
+ ci_base = @base || gh.base_commit
40
+ ci_head = @head || gh.head_commit
41
+
42
+ dm.env.scm.diff_for_folder(".", ci_base, ci_head)
25
43
  dm.parse Pathname.new(@dangerfile_path)
26
44
 
27
45
  post_results(dm)
@@ -9,6 +9,6 @@
9
9
  <% end %>
10
10
  <% end %>
11
11
 
12
- <p align="right" meta="generated_by_danger">
12
+ <p align="right" data-meta="generated_by_danger" data-base-commit="<%= @base_commit %>" data-head-commit="<%= @head_commit %>" >
13
13
  Generated by :no_entry_sign: <a href="https://github.com/KrauseFx/danger/">danger</a>
14
14
  </p>
@@ -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
10
+ attr_accessor :env, :warnings, :errors, :messages, :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.
@@ -21,9 +21,33 @@ module Danger
21
21
  'Dangerfile'
22
22
  end
23
23
 
24
+ # Iterates through the DSL's attributes, and table's the output
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)}"
33
+ 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"
44
+ end
45
+
24
46
  # Parses the file at a path, optionally takes the content of the file for DI
25
47
  #
26
48
  def parse(path, contents = nil)
49
+ print_known_info if verbose
50
+
27
51
  contents ||= File.open(path, 'r:utf-8', &:read)
28
52
 
29
53
  # Work around for Rubinius incomplete encoding in 1.9 mode
@@ -42,6 +42,9 @@ module Danger
42
42
  puts "Printing message '#{message}'"
43
43
  end
44
44
 
45
+ # When an undefined method is called, we check to see if it's something
46
+ # that either the `scm` or the `request_source` can handle.
47
+ # This opens us up to letting those object extend themselves naturally.
45
48
  def method_missing(method_sym, *_arguments, &_block)
46
49
  unless AvailableValues.all.include?(method_sym)
47
50
  raise "Unknown method '#{method_sym}', please check out the documentation for available variables".red
@@ -6,16 +6,19 @@ require 'octokit'
6
6
 
7
7
  module Danger
8
8
  class GitHub
9
- attr_accessor :ci_source, :pr_json, :environment
9
+ attr_accessor :ci_source, :pr_json, :issue_json, :environment, :base_commit, :head_commit, :support_tokenless_auth
10
10
 
11
11
  def initialize(ci_source, environment)
12
12
  self.ci_source = ci_source
13
13
  self.environment = environment
14
+ self.support_tokenless_auth = false
15
+
16
+ Octokit.auto_paginate = true
14
17
  end
15
18
 
16
19
  def client
17
20
  token = @environment["DANGER_GITHUB_API_TOKEN"]
18
- raise "No API given, please provide one using `DANGER_GITHUB_API_TOKEN`" unless token
21
+ raise "No API given, please provide one using `DANGER_GITHUB_API_TOKEN`" if !token && !support_tokenless_auth
19
22
 
20
23
  @client ||= Octokit::Client.new(
21
24
  access_token: token
@@ -24,9 +27,19 @@ module Danger
24
27
 
25
28
  def fetch_details
26
29
  self.pr_json = client.pull_request(ci_source.repo_slug, ci_source.pull_request_id)
30
+ fetch_issue_details(self.pr_json)
31
+ end
32
+
33
+ def fetch_issue_details(pr_json)
34
+ href = pr_json[:_links][:issue][:href]
35
+ self.issue_json = client.get(href)
27
36
  end
28
37
 
29
- def latest_pr_commit_ref
38
+ def base_commit
39
+ self.pr_json[:base][:sha]
40
+ end
41
+
42
+ def head_commit
30
43
  self.pr_json[:head][:sha]
31
44
  end
32
45
 
@@ -42,6 +55,10 @@ module Danger
42
55
  self.pr_json[:user][:login]
43
56
  end
44
57
 
58
+ def pr_labels
59
+ self.issue_json[:labels].map { |l| l[:name] }
60
+ end
61
+
45
62
  # Sending data to GitHub
46
63
  def update_pull_request!(warnings: nil, errors: nil, messages: nil)
47
64
  comment_result = {}
@@ -1,4 +1,4 @@
1
- # https://github.com/schacon/ruby-git
1
+ # For more info see: https://github.com/schacon/ruby-git
2
2
 
3
3
  require 'git'
4
4
 
@@ -6,9 +6,9 @@ module Danger
6
6
  class GitRepo
7
7
  attr_accessor :diff
8
8
 
9
- def diff_for_folder(folder, from = "HEAD", to = 'master')
9
+ def diff_for_folder(folder, from = "master", to = 'HEAD')
10
10
  g = Git.open(folder)
11
- self.diff = g.diff(to, from)
11
+ self.diff = g.diff(from, to)
12
12
  end
13
13
 
14
14
  def files_modified
@@ -1,4 +1,4 @@
1
1
  module Danger
2
- VERSION = "0.2.1"
3
- DESCRIPTION = "Ensure your pull request is up to standard with a nice DSL"
2
+ VERSION = "0.3.0"
3
+ DESCRIPTION = "Automate your PR etiquette."
4
4
  end
data/lib/danger.rb CHANGED
@@ -1,8 +1,7 @@
1
1
  require "danger/version"
2
2
  require "danger/dangerfile"
3
3
  require "danger/environment_manager"
4
- require "danger/runner"
5
- require "danger/init"
4
+ require "danger/commands/runner"
6
5
  require "danger/available_values"
7
6
 
8
7
  require "claide"
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.2.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Orta Therox
@@ -9,22 +9,22 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2016-01-14 00:00:00.000000000 Z
12
+ date: 2016-02-12 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: claide
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  requirements:
18
- - - "~>"
18
+ - - ">="
19
19
  - !ruby/object:Gem::Version
20
- version: '0.8'
20
+ version: '0'
21
21
  type: :runtime
22
22
  prerelease: false
23
23
  version_requirements: !ruby/object:Gem::Requirement
24
24
  requirements:
25
- - - "~>"
25
+ - - ">="
26
26
  - !ruby/object:Gem::Version
27
- version: '0.8'
27
+ version: '0'
28
28
  - !ruby/object:Gem::Dependency
29
29
  name: git
30
30
  requirement: !ruby/object:Gem::Requirement
@@ -155,16 +155,16 @@ dependencies:
155
155
  name: rubocop
156
156
  requirement: !ruby/object:Gem::Requirement
157
157
  requirements:
158
- - - ">="
158
+ - - "~>"
159
159
  - !ruby/object:Gem::Version
160
- version: '0'
160
+ version: 0.35.1
161
161
  type: :development
162
162
  prerelease: false
163
163
  version_requirements: !ruby/object:Gem::Requirement
164
164
  requirements:
165
- - - ">="
165
+ - - "~>"
166
166
  - !ruby/object:Gem::Version
167
- version: '0'
167
+ version: 0.35.1
168
168
  description: Create a Dangerfile to introspect your pull request in CI, makes it easy
169
169
  to enforce social conventions like changelogs and tests.
170
170
  email:
@@ -184,14 +184,17 @@ files:
184
184
  - lib/danger/ci_source/buildkite.rb
185
185
  - lib/danger/ci_source/ci_source.rb
186
186
  - lib/danger/ci_source/circle.rb
187
+ - lib/danger/ci_source/local_git_repo.rb
187
188
  - lib/danger/ci_source/travis.rb
189
+ - lib/danger/circle_api.rb
190
+ - lib/danger/commands/init.rb
191
+ - lib/danger/commands/local.rb
192
+ - lib/danger/commands/runner.rb
188
193
  - lib/danger/comment_generators/github.md.erb
189
194
  - lib/danger/dangerfile.rb
190
195
  - lib/danger/dangerfile_dsl.rb
191
196
  - lib/danger/environment_manager.rb
192
- - lib/danger/init.rb
193
197
  - lib/danger/request_sources/github.rb
194
- - lib/danger/runner.rb
195
198
  - lib/danger/scm_source/git_repo.rb
196
199
  - lib/danger/standard_error.rb
197
200
  - lib/danger/version.rb
@@ -215,8 +218,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
215
218
  version: '0'
216
219
  requirements: []
217
220
  rubyforge_project:
218
- rubygems_version: 2.4.6
221
+ rubygems_version: 2.4.8
219
222
  signing_key:
220
223
  specification_version: 4
221
- summary: Ensure your pull request is up to standard with a nice DSL
224
+ summary: Automate your PR etiquette.
222
225
  test_files: []