danger 0.9.1 → 0.10.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: e02bc78c88ffbdd9d2c7c7b4abd87939c2a76837
4
- data.tar.gz: 173e0a2993c408b5b6e53c379239e97228839bc3
3
+ metadata.gz: 7b697f1591c4b33509e536da0cf20d7acaa61e8c
4
+ data.tar.gz: 0a9d995a79188ae53f543230fbd9a7007c1641b8
5
5
  SHA512:
6
- metadata.gz: 001cd98d2bd528920fd6aafffea0aca00b41672e32e52588ba30f1eb2e9614cd246bf066f7ced68bbe6ec289f90e0c03774ea8e6d075de1ced383f20909a8854
7
- data.tar.gz: 65669c564bcae4590b3bc384b5d3a96c16b74404e48d4489eaef4cc6d17a8a53270db8e5cfa3969579c3bac5176b47187de777f31012b92dcc52b660a5b59591
6
+ metadata.gz: 0a1350d0ce5fbfe8c22c27c04848243a589b07e39e6805ae15343259891153145f2aacc6bee0505101cc53052d35c44b83efb3e3e05733469f9eddb6d8850bd4
7
+ data.tar.gz: 0bcc00b71b54a8b4d23ac457feab9793d742c110fa55ee5997a584b7719adad5591fe4faa9f27804cff7c9253759aab6c0a63e63763825e7ea7ff0af56e19019
data/README.md CHANGED
@@ -201,6 +201,16 @@ Danger will update the comment to cross it out. If you don't want this behavior,
201
201
  fail("PR needs labels", sticky: false) if pr_labels.empty?
202
202
  ```
203
203
 
204
+ ## Org-Wide Dangerfile
205
+
206
+ To have consistent rules across the repos in your organisation, you can use a shared `Dangerfile`:
207
+
208
+ 1. create a repo on your GitHub organization called `danger` (or `Danger`)
209
+ 1. Add a `Dangerfile` to the root of that repo
210
+ 1. The new `Dangerfile` is ran after the current repo's `Dangerfile`
211
+
212
+ The org `Dangerfile` will have access to all of the same plugins, and metadata. For an example, see [themoji/danger](https://github.com/Themoji/danger).
213
+
204
214
  ## Multiple Dangers
205
215
 
206
216
  If one Danger is not enough for you, you can run several ones on the same PR. Just use the `danger_id` param. For example:
@@ -4,6 +4,7 @@ require "danger/danger_core/environment_manager"
4
4
  require "danger/commands/runner"
5
5
  require "danger/plugin_support/plugin"
6
6
  require "danger/core_ext/string"
7
+ require "danger/danger_core/executor"
7
8
 
8
9
  require "claide"
9
10
  require "colored"
@@ -3,6 +3,7 @@
3
3
 
4
4
  module Danger
5
5
  module CISource
6
+ # https://buildkite.com
6
7
  class Buildkite < CI
7
8
  def self.validates?(env)
8
9
  return false unless env["BUILDKITE"]
@@ -4,6 +4,7 @@ require "danger/ci_source/circle_api"
4
4
 
5
5
  module Danger
6
6
  module CISource
7
+ # https://circleci.com
7
8
  class CircleCI < CI
8
9
  def self.validates?(env)
9
10
  return false unless env["CIRCLE_BUILD_NUM"]
@@ -2,6 +2,7 @@
2
2
 
3
3
  module Danger
4
4
  module CISource
5
+ # https://drone.io
5
6
  class Drone < CI
6
7
  def self.validates?(env)
7
8
  return false unless env["DRONE"]
@@ -3,6 +3,7 @@
3
3
 
4
4
  module Danger
5
5
  module CISource
6
+ # https://jenkins-ci.org
6
7
  class Jenkins < CI
7
8
  def self.validates?(env)
8
9
  return false unless env["ghprbPullId"].to_i > 0
@@ -5,6 +5,7 @@ require "uri"
5
5
 
6
6
  module Danger
7
7
  module CISource
8
+ # ignore
8
9
  class LocalGitRepo < CI
9
10
  attr_accessor :base_commit, :head_commit
10
11
 
@@ -2,6 +2,7 @@
2
2
 
3
3
  module Danger
4
4
  module CISource
5
+ # https://semaphoreci.com
5
6
  class Semaphore < CI
6
7
  def self.validates?(env)
7
8
  return false unless env["SEMAPHORE"]
@@ -2,6 +2,7 @@
2
2
 
3
3
  module Danger
4
4
  module CISource
5
+ # http://github.com/surf-build/surf
5
6
  class Surf < CI
6
7
  def self.validates?(env)
7
8
  return ["SURF_REPO", "SURF_NWO"].all? { |x| env[x] }
@@ -1,5 +1,6 @@
1
1
  module Danger
2
2
  module CISource
3
+ # https://www.jetbrains.com/teamcity/
3
4
  class TeamCity < CI
4
5
  def self.validates?(env)
5
6
  env.key? "TEAMCITY_VERSION"
@@ -3,6 +3,7 @@
3
3
 
4
4
  module Danger
5
5
  module CISource
6
+ # https://travis-ci.com
6
7
  class Travis < CI
7
8
  def self.validates?(env)
8
9
  return false unless env["HAS_JOSH_K_SEAL_OF_APPROVAL"]
@@ -2,6 +2,7 @@
2
2
 
3
3
  module Danger
4
4
  module CISource
5
+ # https://github.com/czechboy0/Buildasaur
5
6
  class XcodeServer < CI
6
7
  def self.validates?(env)
7
8
  return false unless env["XCS_BOT_NAME"]
@@ -1,3 +1,8 @@
1
+ require "danger/commands/local_helpers/http_cache"
2
+ require "faraday/http_cache"
3
+ require "octokit"
4
+ require "tmpdir"
5
+
1
6
  module Danger
2
7
  class Local < Runner
3
8
  self.summary = "Run the Dangerfile locally."
@@ -6,12 +11,14 @@ module Danger
6
11
  def initialize(argv)
7
12
  @dangerfile_path = "Dangerfile" if File.exist? "Dangerfile"
8
13
  @pr_num = argv.option("use-merged-pr")
14
+ @clear_http_cache = argv.flag?("clear-http-cache", false)
9
15
  super
10
16
  end
11
17
 
12
18
  def self.options
13
19
  [
14
- ["--use-merged-pr=[#id]", "The ID of an already merged PR inside your history to use as a reference for the local run."]
20
+ ["--use-merged-pr=[#id]", "The ID of an already merged PR inside your history to use as a reference for the local run."],
21
+ ["--clear-http-cache", "Clear the local http cache before running Danger locally."]
15
22
  ].concat(super)
16
23
  end
17
24
 
@@ -26,6 +33,15 @@ module Danger
26
33
  ENV["DANGER_USE_LOCAL_GIT"] = "YES"
27
34
  ENV["LOCAL_GIT_PR_ID"] = @pr_num if @pr_num
28
35
 
36
+ # setup caching for Github calls to hitting the API rate limit too quickly
37
+ cache_file = File.join(ENV["DANGER_TMPDIR"] || Dir.tmpdir, "danger_local_cache")
38
+ cache = HTTPCache.new(cache_file, clear_cache: @clear_http_cache)
39
+ Octokit.middleware = Faraday::Builder.new do |builder|
40
+ builder.use Faraday::HttpCache, store: cache, serializer: Marshal, shared_cache: false
41
+ builder.use Octokit::Response::RaiseError
42
+ builder.adapter Faraday.default_adapter
43
+ end
44
+
29
45
  env = EnvironmentManager.new(ENV)
30
46
  dm = Dangerfile.new(env, cork)
31
47
  dm.init_plugins
@@ -64,11 +80,23 @@ module Danger
64
80
  dm.env.fill_environment_vars
65
81
  dm.env.ensure_danger_branches_are_setup
66
82
  dm.env.scm.diff_for_folder(".", from: Danger::EnvironmentManager.danger_base_branch, to: Danger::EnvironmentManager.danger_head_branch)
83
+
67
84
  dm.parse(Pathname.new(@dangerfile_path))
85
+ check_and_run_org_dangerfile(dm)
86
+
68
87
  dm.print_results
69
88
  ensure
70
89
  dm.env.clean_up
71
90
  end
72
91
  end
92
+
93
+ # Check to see if there's a Dangerfile in the organisation, and run it if so
94
+ def check_and_run_org_dangerfile(dm)
95
+ if dm.env.request_source.organisation && !dm.env.request_source.danger_repo? && (danger_repo = dm.env.request_source.fetch_danger_repo)
96
+ url = dm.env.request_source.file_url(repository: danger_repo.name, path: "Dangerfile")
97
+ path = dm.plugin.download(url)
98
+ dm.parse(Pathname.new(path))
99
+ end
100
+ end
73
101
  end
74
102
  end
@@ -0,0 +1,36 @@
1
+ require "pstore"
2
+
3
+ module Danger
4
+ class HTTPCache
5
+ attr_reader :expires_in
6
+ def initialize(cache_file = nil, options = {})
7
+ File.delete(cache_file) if options[:clear_cache]
8
+ @store = PStore.new(cache_file)
9
+ @expires_in = options[:expires_in] || 300 # 5 minutes
10
+ end
11
+
12
+ def read(key)
13
+ @store.transaction do
14
+ entry = @store[key]
15
+ return nil unless entry
16
+ return entry[:value] unless entry_has_expired(entry, @expires_in)
17
+ @store.delete key
18
+ return nil
19
+ end
20
+ end
21
+
22
+ def delete(key)
23
+ @store.transaction { @store.delete key }
24
+ end
25
+
26
+ def write(key, value)
27
+ @store.transaction do
28
+ @store[key] = { updated_at: Time.now.to_i, value: value }
29
+ end
30
+ end
31
+
32
+ def entry_has_expired(entry, ttl)
33
+ Time.now.to_i > entry[:updated_at].to_i + ttl.to_i
34
+ end
35
+ end
36
+ end
@@ -32,7 +32,7 @@ module Danger
32
32
  file_resolver = PluginFileResolver.new(@refs)
33
33
  paths = file_resolver.resolve_to_paths
34
34
 
35
- parser = PluginParser.new(paths)
35
+ parser = PluginParser.new(paths, verbose: true)
36
36
  parser.parse
37
37
  json = parser.to_json
38
38
 
@@ -16,14 +16,14 @@ module Danger
16
16
  require "danger/commands/plugins/plugin_json"
17
17
  require "danger/commands/plugins/plugin_readme"
18
18
 
19
+ attr_accessor :cork
20
+
19
21
  self.summary = "Run the Dangerfile."
20
22
  self.command = "danger"
21
23
  self.version = Danger::VERSION
22
24
 
23
25
  self.plugin_prefixes = %w(claide danger)
24
26
 
25
- attr_accessor :cork
26
-
27
27
  def initialize(argv)
28
28
  dangerfile = argv.option("dangerfile", "Dangerfile")
29
29
  @dangerfile_path = dangerfile if File.exist? dangerfile
@@ -52,53 +52,10 @@ module Danger
52
52
  end
53
53
 
54
54
  def run
55
- env = EnvironmentManager.new(ENV)
56
- dm = Dangerfile.new(env, cork)
57
-
58
- if dm.env.pr?
59
- dm.verbose = verbose
60
- dm.init_plugins
61
-
62
- dm.env.fill_environment_vars
63
-
64
- begin
65
- dm.env.ensure_danger_branches_are_setup
66
-
67
- # Offer the chance for a user to specify a branch through the command line
68
- ci_base = @base || EnvironmentManager.danger_base_branch
69
- ci_head = @head || EnvironmentManager.danger_head_branch
70
- dm.env.scm.diff_for_folder(".", from: ci_base, to: ci_head)
71
-
72
- dm.parse Pathname.new(@dangerfile_path)
73
-
74
- post_results dm
75
- dm.print_results
76
- ensure
77
- dm.env.clean_up
78
- end
79
- else
80
- cork.puts "Not a Pull Request - skipping `danger` run"
81
- end
82
- end
83
-
84
- def post_results(dm)
85
- gh = dm.env.request_source
86
- violations = dm.violation_report
87
- status = dm.status_report
88
-
89
- gh.update_pull_request!(warnings: violations[:warnings], errors: violations[:errors], messages: violations[:messages], markdowns: status[:markdowns], danger_id: @danger_id)
90
- end
91
-
92
- def self.report_error(exception)
93
- raise exception if exception.kind_of?(SystemExit)
94
- message = "#{exception.message.red} (#{exception.class.to_s.yellow})"
95
- if exception.backtrace
96
- danger_lib = File.expand_path("../../..", __FILE__)
97
- message << "\n\t" << exception.backtrace.reverse_each.
98
- drop_while { |bt| !bt.start_with?(danger_lib) }.reverse.
99
- join("\n\t")
100
- end
101
- abort(message)
55
+ Executor.new.run(base: @base,
56
+ head: @head,
57
+ dangerfile_path: @dangerfile_path,
58
+ danger_id: @danger_id)
102
59
  end
103
60
  end
104
61
  end
@@ -0,0 +1,55 @@
1
+ module Danger
2
+ class Executor
3
+ def run(env: nil,
4
+ dm: nil,
5
+ cork: nil,
6
+ base: nil,
7
+ head: nil,
8
+ dangerfile_path: nil,
9
+ danger_id: nil)
10
+
11
+ cork ||= Cork::Board.new(silent: false,
12
+ verbose: false)
13
+ env ||= EnvironmentManager.new(ENV)
14
+ dm ||= Dangerfile.new(env, cork)
15
+
16
+ if dm.env.pr?
17
+ dm.init_plugins
18
+
19
+ dm.env.fill_environment_vars
20
+
21
+ begin
22
+ dm.env.ensure_danger_branches_are_setup
23
+
24
+ # Offer the chance for a user to specify a branch through the command line
25
+ ci_base = base || EnvironmentManager.danger_base_branch
26
+ ci_head = head || EnvironmentManager.danger_head_branch
27
+ dm.env.scm.diff_for_folder(".", from: ci_base, to: ci_head)
28
+
29
+ dm.parse(Pathname.new(dangerfile_path))
30
+
31
+ if dm.env.request_source.organisation && !dm.env.request_source.danger_repo? && (danger_repo = dm.env.request_source.fetch_danger_repo)
32
+ url = dm.env.request_source.file_url(repository: danger_repo.name, path: "Dangerfile")
33
+ path = dm.plugin.download(url)
34
+ dm.parse(Pathname.new(path))
35
+ end
36
+
37
+ post_results(dm, danger_id)
38
+ dm.print_results
39
+ ensure
40
+ dm.env.clean_up
41
+ end
42
+ else
43
+ cork.puts "Not a Pull Request - skipping `danger` run"
44
+ end
45
+ end
46
+
47
+ def post_results(dm, danger_id)
48
+ gh = dm.env.request_source
49
+ violations = dm.violation_report
50
+ status = dm.status_report
51
+
52
+ gh.update_pull_request!(warnings: violations[:warnings], errors: violations[:errors], messages: violations[:messages], markdowns: status[:markdowns], danger_id: danger_id)
53
+ end
54
+ end
55
+ end
@@ -1,6 +1,7 @@
1
1
  require "danger/plugin_support/plugin"
2
2
  require "danger/core_ext/file_list"
3
3
 
4
+ # Danger
4
5
  module Danger
5
6
  # Handles interacting with git inside a Dangerfile. Providing access to files that have changed, and useful statistics. Also provides
6
7
  # access to the commits in the form of [Git::Log](https://github.com/schacon/ruby-git/blob/master/lib/git/log.rb) objects.
@@ -30,6 +31,9 @@ module Danger
30
31
  # @tags core, git
31
32
 
32
33
  class DangerfileGitPlugin < Plugin
34
+ # The instance name used in the Dangerfile
35
+ # @return [String]
36
+ #
33
37
  def self.instance_name
34
38
  "git"
35
39
  end
@@ -33,6 +33,9 @@ module Danger
33
33
  @github = dangerfile.env.request_source
34
34
  end
35
35
 
36
+ # The instance name used in the Dangerfile
37
+ # @return [String]
38
+ #
36
39
  def self.instance_name
37
40
  "github"
38
41
  end
@@ -87,7 +90,7 @@ module Danger
87
90
 
88
91
  # @!group PR Commit Metadata
89
92
  # The base commit to which the PR is going to be merged as a parent.
90
- # @return String
93
+ # @return [String]
91
94
  #
92
95
  def base_commit
93
96
  pr_json[:base][:sha]
@@ -24,6 +24,9 @@ module Danger
24
24
  # @tags core, plugins
25
25
 
26
26
  class DangerfileImportPlugin < Plugin
27
+ # The instance name used in the Dangerfile
28
+ # @return [String]
29
+ #
27
30
  def self.instance_name
28
31
  "plugin"
29
32
  end
@@ -31,32 +34,33 @@ module Danger
31
34
  # @!group Plugins
32
35
  # Download a local or remote plugin and use it inside the Dangerfile.
33
36
  #
34
- # @param [String] path
37
+ # @param [String] path_or_url
35
38
  # a local path or a https URL to the Ruby file to import
36
39
  # a danger plugin from.
37
- # @return [void]
38
-
39
- def import(path)
40
- raise "`import` requires a string" unless path.kind_of?(String)
41
- path += ".rb" unless path.end_with?(".rb")
40
+ # @return [void]
41
+ #
42
+ def import(path_or_url)
43
+ raise "`import` requires a string" unless path_or_url.kind_of?(String)
42
44
 
43
- if path.start_with?("http")
44
- import_url(path)
45
+ if path_or_url.start_with?("http")
46
+ import_url(path_or_url)
45
47
  else
46
- import_local(path)
48
+ import_local(path_or_url)
47
49
  end
48
50
  end
49
51
 
50
- private
51
-
52
52
  # @!group Plugins
53
- # Download a remote plugin and use it locally.
53
+ # Download a local or remote plugin or Dangerfile
54
+ # This method will not import the file for you, use plugin.import instead
54
55
  #
55
- # @param [String] url
56
- # https URL to the Ruby file to use
57
- # @return [void]
58
- def import_url(url)
59
- raise "URL is not https, for security reasons `danger` only supports encrypted requests" unless url.start_with?("https://")
56
+ # @param [String] path_or_url
57
+ # a local path or a https URL to the Ruby file to import
58
+ # a danger plugin from.
59
+ # @return [String] The path to the downloaded Ruby file
60
+ #
61
+ def download(path_or_url)
62
+ raise "`download` requires a string" unless path_or_url.kind_of?(String)
63
+ raise "URL is not https, for security reasons `danger` only supports encrypted requests" if URI.parse(path_or_url).scheme != "https"
60
64
 
61
65
  require "tmpdir"
62
66
  require "faraday"
@@ -64,13 +68,24 @@ module Danger
64
68
  @http_client ||= Faraday.new do |b|
65
69
  b.adapter :net_http
66
70
  end
67
- content = @http_client.get(url)
71
+ content = @http_client.get(path_or_url)
68
72
 
69
- Dir.mktmpdir do |dir|
70
- path = File.join(dir, "temporary_remote_action.rb")
71
- File.write(path, content.body)
72
- import_local(path)
73
- end
73
+ path = File.join(Dir.mktmpdir, "temporary_danger.rb")
74
+ File.write(path, content.body)
75
+ return path
76
+ end
77
+
78
+ private
79
+
80
+ # @!group Plugins
81
+ # Download a remote plugin and use it locally.
82
+ #
83
+ # @param [String] url
84
+ # https URL to the Ruby file to use
85
+ # @return [void]
86
+ def import_url(url)
87
+ path = download(url)
88
+ import_local(path)
74
89
  end
75
90
 
76
91
  # @!group Plugins
@@ -53,6 +53,9 @@ module Danger
53
53
  @markdowns = []
54
54
  end
55
55
 
56
+ # The instance name used in the Dangerfile
57
+ # @return [String]
58
+ #
56
59
  def self.instance_name
57
60
  "messaging"
58
61
  end
@@ -62,6 +65,8 @@ module Danger
62
65
  #
63
66
  # @param [String] message
64
67
  # The markdown based message to be printed below the table
68
+ # @return [void]
69
+ #
65
70
  def markdown(message)
66
71
  @markdowns << message
67
72
  end
@@ -69,10 +74,13 @@ module Danger
69
74
  # @!group Core
70
75
  # Print out a generate message on the PR
71
76
  #
72
- # @param [String] message The message to present to the user
77
+ # @param [String] message
78
+ # The message to present to the user
73
79
  # @param [Boolean] sticky
74
80
  # Whether the message should be kept after it was fixed,
75
81
  # defaults to `true`.
82
+ # @return [void]
83
+ #
76
84
  def message(message, sticky: true)
77
85
  @messages << Violation.new(message, sticky)
78
86
  end
@@ -80,10 +88,13 @@ module Danger
80
88
  # @!group Core
81
89
  # Specifies a problem, but not critical
82
90
  #
83
- # @param [String] message The message to present to the user
91
+ # @param [String] message
92
+ # The message to present to the user
84
93
  # @param [Boolean] sticky
85
94
  # Whether the message should be kept after it was fixed,
86
95
  # defaults to `true`.
96
+ # @return [void]
97
+ #
87
98
  def warn(message, sticky: true)
88
99
  return if should_ignore_violation(message)
89
100
  @warnings << Violation.new(message, sticky)
@@ -97,6 +108,8 @@ module Danger
97
108
  # @param [Boolean] sticky
98
109
  # Whether the message should be kept after it was fixed,
99
110
  # defaults to `true`.
111
+ # @return [void]
112
+ #
100
113
  def fail(message, sticky: true)
101
114
  return if should_ignore_violation(message)
102
115
  @errors << Violation.new(message, sticky)
@@ -106,7 +119,8 @@ module Danger
106
119
  # A list of all messages passed to Danger, including
107
120
  # the markdowns.
108
121
  #
109
- # @return Hash
122
+ # @visibility hidden
123
+ # @return [Hash]
110
124
  def status_report
111
125
  {
112
126
  errors: @errors.map(&:message).clone.freeze,
@@ -121,7 +135,7 @@ module Danger
121
135
  # anticipate users of Danger needing to use this.
122
136
  #
123
137
  # @visibility hidden
124
- # @return Hash
138
+ # @return [Hash]
125
139
  def violation_report
126
140
  {
127
141
  errors: @errors.clone.freeze,
@@ -51,7 +51,7 @@ module Danger
51
51
  # Did the linter pass/fail?
52
52
  #
53
53
  def failed?
54
- errors.empty? == false
54
+ errors.count > 0
55
55
  end
56
56
 
57
57
  # Prints a summary of the errors and warnings.
@@ -59,15 +59,16 @@ module Danger
59
59
  def print_summary(ui)
60
60
  # Print whether it passed/failed at the top
61
61
  if failed?
62
- ui.notice "Passed\n"
63
- else
64
62
  ui.puts "\n[!] Failed\n".red
63
+ else
64
+ ui.notice "Passed"
65
65
  end
66
66
 
67
67
  # A generic proc to handle the similarities between
68
68
  # erros and warnings.
69
69
  do_rules = proc do |name, rules|
70
70
  unless rules.empty?
71
+ ui.puts ""
71
72
  ui.section(name.bold) do
72
73
  rules.each do |rule|
73
74
  title = rule.title.bold + " - #{rule.object_applied_to}"
@@ -111,7 +112,7 @@ module Danger
111
112
  Rule.new(:error, 40..41, "Description", "You should include a description for your method.", proc do |json|
112
113
  json[:body_md] && json[:body_md].empty?
113
114
  end),
114
- Rule.new(:warning, 43..45, "Params", "If the function has no useful return value, use ` @return [void]`.", proc do |json|
115
+ Rule.new(:warning, 43..45, "Params", "You should give a 'type' for the param, yes, ruby is duck-typey but it's useful for newbies to the language, use `@param [Type] name`.", proc do |json|
115
116
  json[:param_couplets] && json[:param_couplets].flat_map(&:values).include?(nil)
116
117
  end),
117
118
  Rule.new(:warning, 46, "Return Type", "If the function has no useful return value, use ` @return [void]` - this will be ignored by documentation generators.", proc do |json|
@@ -34,9 +34,11 @@ module Danger
34
34
  class PluginParser
35
35
  attr_accessor :registry
36
36
 
37
- def initialize(paths)
37
+ def initialize(paths, verbose = false)
38
38
  raise "Path cannot be empty" if paths.empty?
39
39
 
40
+ setup_yard(verbose)
41
+
40
42
  if paths.kind_of? String
41
43
  @paths = [File.expand_path(paths)]
42
44
  else
@@ -44,12 +46,20 @@ module Danger
44
46
  end
45
47
  end
46
48
 
47
- def parse
49
+ def setup_yard(verbose)
48
50
  require 'yard'
49
- # could this go in a singleton-y place instead?
50
- # like class initialize?
51
+
52
+ # Unless specifically asked, don't output anything.
53
+ unless verbose
54
+ YARD::Logger.instance.level = YARD::Logger::FATAL
55
+ end
56
+
57
+ # Add some of our custom tags
51
58
  YARD::Tags::Library.define_tag('tags', :tags)
52
59
  YARD::Tags::Library.define_tag('availablity', :availablity)
60
+ end
61
+
62
+ def parse
53
63
  files = ["lib/danger/plugin_support/plugin.rb"] + @paths
54
64
 
55
65
  # This turns on YARD debugging
@@ -153,7 +163,7 @@ module Danger
153
163
  attribute_meths = klass.attributes[:instance].values.map(&:values).flatten
154
164
 
155
165
  methods = klass.meths - klass.inherited_meths - attribute_meths
156
- usable_methods = methods.select { |m| m.visibility == :public }.reject { |m| m.name == :initialize || m.name == :insance_name }
166
+ usable_methods = methods.select { |m| m.visibility == :public }.reject { |m| m.name == :initialize || m.name == :instance_name }
157
167
 
158
168
  {
159
169
  name: klass.name.to_s,
@@ -128,7 +128,12 @@ module Danger
128
128
  # use a read-only GitHub account
129
129
  if errors.count > 0
130
130
  # We need to fail the actual build here
131
- abort("\nDanger has failed this build. \nFound #{'error'.danger_pluralize(errors.count)} and I don't have write access to the PR set a PR status.")
131
+ is_private = pr_json[:base][:repo][:private]
132
+ if is_private
133
+ abort("\nDanger has failed this build. \nFound #{'error'.danger_pluralize(errors.count)} and I don't have write access to the PR set a PR status.")
134
+ else
135
+ abort("\nDanger has failed this build. \nFound #{'error'.danger_pluralize(errors.count)}.")
136
+ end
132
137
  else
133
138
  puts message
134
139
  end
@@ -222,14 +227,56 @@ module Danger
222
227
  end
223
228
 
224
229
  def parse_tables_from_comment(comment)
225
- comment.split('</table>')
230
+ comment.split("</table>")
226
231
  end
227
232
 
228
233
  def process_markdown(violation)
229
234
  html = markdown_parser.render(violation.message)
230
- match = html.match(%r{^<p>(.*)</p>$})
231
- message = match.nil? ? html : match.captures.first
232
- Violation.new(message, violation.sticky)
235
+ # Remove the outer `<p>`, the -5 represents a newline + `</p>`
236
+ html = html[3...-5] if html.start_with? "<p>"
237
+ Violation.new(html, violation.sticky)
238
+ end
239
+
240
+ # @return [String] The organisation name, is nil if it can't be detected
241
+ def organisation
242
+ matched = self.issue_json[:repository_url].match(%r{repos\/(.*)\/})
243
+ return matched[1] if matched && matched[1]
244
+ rescue
245
+ nil
246
+ end
247
+
248
+ # @return [Hash] with the information about the repo
249
+ # returns nil if the repo is not available
250
+ def fetch_repository(organisation: nil, repository: nil)
251
+ organisation ||= self.organisation
252
+ repository ||= self.ci_source.repo_slug.split("/").last
253
+ self.client.repo("#{organisation}/#{repository}")
254
+ rescue Octokit::NotFound
255
+ nil # repo doesn't exist
256
+ end
257
+
258
+ # @return [Hash] with the information about the repo.
259
+ # This will automatically detect if the repo is capitalised
260
+ # returns nil if there is no danger repo
261
+ def fetch_danger_repo(organisation: nil)
262
+ data = nil
263
+ data ||= fetch_repository(organisation: organisation, repository: DANGER_REPO_NAME.downcase)
264
+ data ||= fetch_repository(organisation: organisation, repository: DANGER_REPO_NAME.capitalize)
265
+ data
266
+ end
267
+
268
+ # @return [Bool] is this repo the danger repo of the org?
269
+ def danger_repo?(organisation: nil, repository: nil)
270
+ repo = fetch_repository(organisation: organisation, repository: repository)
271
+ repo[:name].casecmp(DANGER_REPO_NAME).zero?
272
+ rescue
273
+ false
274
+ end
275
+
276
+ # @return [String] A URL to the specific file, ready to be downloaded
277
+ def file_url(organisation: nil, repository: nil, branch: 'master', path: nil)
278
+ organisation ||= self.organisation
279
+ "https://raw.githubusercontent.com/#{organisation}/#{repository}/#{branch}/#{path}"
233
280
  end
234
281
  end
235
282
  end
@@ -1,6 +1,8 @@
1
1
  module Danger
2
2
  module RequestSources
3
3
  class RequestSource
4
+ DANGER_REPO_NAME = "danger".freeze
5
+
4
6
  attr_accessor :ci_source, :environment, :scm, :host, :ignored_violations
5
7
 
6
8
  def self.inherited(child_class)
@@ -43,6 +45,26 @@ module Danger
43
45
  def fetch_details
44
46
  raise "Subclass and overwrite initialize"
45
47
  end
48
+
49
+ def organisation
50
+ raise "Subclass and overwrite organisation"
51
+ end
52
+
53
+ def fetch_repository(_organisation: nil, _repository: nil)
54
+ raise "Subclass and overwrite fetch_repository"
55
+ end
56
+
57
+ def fetch_danger_repo(_organisation: nil)
58
+ raise "Subclass and overwrite fetch_danger_repo"
59
+ end
60
+
61
+ def danger_repo?(_organisation: nil, _repository: nil)
62
+ raise "Subclass and overwrite danger_repo?"
63
+ end
64
+
65
+ def file_url(_organisation: nil, _repository: nil, _branch: "master", _path: nil)
66
+ raise "Subclass and overwrite file_url"
67
+ end
46
68
  end
47
69
  end
48
70
  end
@@ -1,4 +1,4 @@
1
1
  module Danger
2
- VERSION = "0.9.1".freeze
2
+ VERSION = "0.10.0".freeze
3
3
  DESCRIPTION = "Automate your PR etiquette.".freeze
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.9.1
4
+ version: 0.10.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-07-14 00:00:00.000000000 Z
12
+ date: 2016-07-18 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: claide
@@ -81,6 +81,20 @@ dependencies:
81
81
  - - "~>"
82
82
  - !ruby/object:Gem::Version
83
83
  version: '0'
84
+ - !ruby/object:Gem::Dependency
85
+ name: faraday-http-cache
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - "~>"
89
+ - !ruby/object:Gem::Version
90
+ version: '1.0'
91
+ type: :runtime
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - "~>"
96
+ - !ruby/object:Gem::Version
97
+ version: '1.0'
84
98
  - !ruby/object:Gem::Dependency
85
99
  name: octokit
86
100
  requirement: !ruby/object:Gem::Requirement
@@ -322,6 +336,7 @@ files:
322
336
  - lib/danger/commands/init.rb
323
337
  - lib/danger/commands/init_helpers/interviewer.rb
324
338
  - lib/danger/commands/local.rb
339
+ - lib/danger/commands/local_helpers/http_cache.rb
325
340
  - lib/danger/commands/plugins/plugin_json.rb
326
341
  - lib/danger/commands/plugins/plugin_lint.rb
327
342
  - lib/danger/commands/plugins/plugin_readme.rb
@@ -332,6 +347,7 @@ files:
332
347
  - lib/danger/danger_core/dangerfile.rb
333
348
  - lib/danger/danger_core/dangerfile_dsl.rb
334
349
  - lib/danger/danger_core/environment_manager.rb
350
+ - lib/danger/danger_core/executor.rb
335
351
  - lib/danger/danger_core/plugins/dangerfile_git_plugin.rb
336
352
  - lib/danger/danger_core/plugins/dangerfile_github_plugin.rb
337
353
  - lib/danger/danger_core/plugins/dangerfile_import_plugin.rb
@@ -367,7 +383,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
367
383
  version: '0'
368
384
  requirements: []
369
385
  rubyforge_project:
370
- rubygems_version: 2.4.8
386
+ rubygems_version: 2.2.2
371
387
  signing_key:
372
388
  specification_version: 4
373
389
  summary: Automate your PR etiquette.