danger 0.2.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml 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: []