danger 0.9.1 → 0.10.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: 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.