danger 8.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (121) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +22 -0
  3. data/README.md +94 -0
  4. data/bin/danger +5 -0
  5. data/lib/assets/DangerfileTemplate +13 -0
  6. data/lib/danger.rb +44 -0
  7. data/lib/danger/ci_source/appcenter.rb +55 -0
  8. data/lib/danger/ci_source/appveyor.rb +60 -0
  9. data/lib/danger/ci_source/azure_pipelines.rb +44 -0
  10. data/lib/danger/ci_source/bamboo.rb +41 -0
  11. data/lib/danger/ci_source/bitbucket_pipelines.rb +37 -0
  12. data/lib/danger/ci_source/bitrise.rb +65 -0
  13. data/lib/danger/ci_source/buddybuild.rb +62 -0
  14. data/lib/danger/ci_source/buildkite.rb +51 -0
  15. data/lib/danger/ci_source/ci_source.rb +37 -0
  16. data/lib/danger/ci_source/circle.rb +94 -0
  17. data/lib/danger/ci_source/circle_api.rb +51 -0
  18. data/lib/danger/ci_source/cirrus.rb +31 -0
  19. data/lib/danger/ci_source/code_build.rb +57 -0
  20. data/lib/danger/ci_source/codefresh.rb +53 -0
  21. data/lib/danger/ci_source/codeship.rb +44 -0
  22. data/lib/danger/ci_source/dotci.rb +52 -0
  23. data/lib/danger/ci_source/drone.rb +71 -0
  24. data/lib/danger/ci_source/github_actions.rb +43 -0
  25. data/lib/danger/ci_source/gitlab_ci.rb +86 -0
  26. data/lib/danger/ci_source/jenkins.rb +149 -0
  27. data/lib/danger/ci_source/local_git_repo.rb +119 -0
  28. data/lib/danger/ci_source/local_only_git_repo.rb +47 -0
  29. data/lib/danger/ci_source/screwdriver.rb +47 -0
  30. data/lib/danger/ci_source/semaphore.rb +37 -0
  31. data/lib/danger/ci_source/support/commits.rb +17 -0
  32. data/lib/danger/ci_source/support/find_repo_info_from_logs.rb +35 -0
  33. data/lib/danger/ci_source/support/find_repo_info_from_url.rb +42 -0
  34. data/lib/danger/ci_source/support/local_pull_request.rb +14 -0
  35. data/lib/danger/ci_source/support/no_pull_request.rb +7 -0
  36. data/lib/danger/ci_source/support/no_repo_info.rb +5 -0
  37. data/lib/danger/ci_source/support/pull_request_finder.rb +179 -0
  38. data/lib/danger/ci_source/support/remote_pull_request.rb +15 -0
  39. data/lib/danger/ci_source/support/repo_info.rb +10 -0
  40. data/lib/danger/ci_source/surf.rb +37 -0
  41. data/lib/danger/ci_source/teamcity.rb +159 -0
  42. data/lib/danger/ci_source/travis.rb +51 -0
  43. data/lib/danger/ci_source/vsts.rb +73 -0
  44. data/lib/danger/ci_source/xcode_server.rb +48 -0
  45. data/lib/danger/clients/rubygems_client.rb +14 -0
  46. data/lib/danger/commands/dangerfile/gem.rb +43 -0
  47. data/lib/danger/commands/dangerfile/init.rb +30 -0
  48. data/lib/danger/commands/dry_run.rb +54 -0
  49. data/lib/danger/commands/init.rb +297 -0
  50. data/lib/danger/commands/init_helpers/interviewer.rb +92 -0
  51. data/lib/danger/commands/local.rb +83 -0
  52. data/lib/danger/commands/local_helpers/http_cache.rb +36 -0
  53. data/lib/danger/commands/local_helpers/local_setup.rb +46 -0
  54. data/lib/danger/commands/local_helpers/pry_setup.rb +31 -0
  55. data/lib/danger/commands/plugins/plugin_json.rb +46 -0
  56. data/lib/danger/commands/plugins/plugin_lint.rb +54 -0
  57. data/lib/danger/commands/plugins/plugin_readme.rb +45 -0
  58. data/lib/danger/commands/pr.rb +92 -0
  59. data/lib/danger/commands/runner.rb +94 -0
  60. data/lib/danger/commands/staging.rb +53 -0
  61. data/lib/danger/commands/systems.rb +43 -0
  62. data/lib/danger/comment_generators/bitbucket_server.md.erb +20 -0
  63. data/lib/danger/comment_generators/bitbucket_server_inline.md.erb +15 -0
  64. data/lib/danger/comment_generators/bitbucket_server_message_group.md.erb +12 -0
  65. data/lib/danger/comment_generators/github.md.erb +55 -0
  66. data/lib/danger/comment_generators/github_inline.md.erb +26 -0
  67. data/lib/danger/comment_generators/gitlab.md.erb +40 -0
  68. data/lib/danger/comment_generators/gitlab_inline.md.erb +26 -0
  69. data/lib/danger/comment_generators/vsts.md.erb +20 -0
  70. data/lib/danger/core_ext/file_list.rb +18 -0
  71. data/lib/danger/core_ext/string.rb +20 -0
  72. data/lib/danger/danger_core/dangerfile.rb +341 -0
  73. data/lib/danger/danger_core/dangerfile_dsl.rb +29 -0
  74. data/lib/danger/danger_core/dangerfile_generator.rb +11 -0
  75. data/lib/danger/danger_core/environment_manager.rb +123 -0
  76. data/lib/danger/danger_core/executor.rb +92 -0
  77. data/lib/danger/danger_core/message_aggregator.rb +49 -0
  78. data/lib/danger/danger_core/message_group.rb +68 -0
  79. data/lib/danger/danger_core/messages/base.rb +56 -0
  80. data/lib/danger/danger_core/messages/markdown.rb +42 -0
  81. data/lib/danger/danger_core/messages/violation.rb +54 -0
  82. data/lib/danger/danger_core/plugins/dangerfile_bitbucket_cloud_plugin.rb +144 -0
  83. data/lib/danger/danger_core/plugins/dangerfile_bitbucket_server_plugin.rb +211 -0
  84. data/lib/danger/danger_core/plugins/dangerfile_danger_plugin.rb +248 -0
  85. data/lib/danger/danger_core/plugins/dangerfile_git_plugin.rb +158 -0
  86. data/lib/danger/danger_core/plugins/dangerfile_github_plugin.rb +254 -0
  87. data/lib/danger/danger_core/plugins/dangerfile_gitlab_plugin.rb +240 -0
  88. data/lib/danger/danger_core/plugins/dangerfile_local_only_plugin.rb +42 -0
  89. data/lib/danger/danger_core/plugins/dangerfile_messaging_plugin.rb +218 -0
  90. data/lib/danger/danger_core/plugins/dangerfile_vsts_plugin.rb +191 -0
  91. data/lib/danger/danger_core/standard_error.rb +143 -0
  92. data/lib/danger/helpers/array_subclass.rb +61 -0
  93. data/lib/danger/helpers/comment.rb +32 -0
  94. data/lib/danger/helpers/comments_helper.rb +178 -0
  95. data/lib/danger/helpers/comments_parsing_helper.rb +70 -0
  96. data/lib/danger/helpers/emoji_mapper.rb +41 -0
  97. data/lib/danger/helpers/find_max_num_violations.rb +31 -0
  98. data/lib/danger/helpers/message_groups_array_helper.rb +31 -0
  99. data/lib/danger/plugin_support/gems_resolver.rb +77 -0
  100. data/lib/danger/plugin_support/plugin.rb +49 -0
  101. data/lib/danger/plugin_support/plugin_file_resolver.rb +30 -0
  102. data/lib/danger/plugin_support/plugin_linter.rb +161 -0
  103. data/lib/danger/plugin_support/plugin_parser.rb +199 -0
  104. data/lib/danger/plugin_support/templates/readme_table.html.erb +26 -0
  105. data/lib/danger/request_sources/bitbucket_cloud.rb +171 -0
  106. data/lib/danger/request_sources/bitbucket_cloud_api.rb +181 -0
  107. data/lib/danger/request_sources/bitbucket_server.rb +105 -0
  108. data/lib/danger/request_sources/bitbucket_server_api.rb +117 -0
  109. data/lib/danger/request_sources/github/github.rb +530 -0
  110. data/lib/danger/request_sources/github/github_review.rb +126 -0
  111. data/lib/danger/request_sources/github/github_review_resolver.rb +19 -0
  112. data/lib/danger/request_sources/github/github_review_unsupported.rb +25 -0
  113. data/lib/danger/request_sources/gitlab.rb +525 -0
  114. data/lib/danger/request_sources/local_only.rb +53 -0
  115. data/lib/danger/request_sources/request_source.rb +85 -0
  116. data/lib/danger/request_sources/support/get_ignored_violation.rb +17 -0
  117. data/lib/danger/request_sources/vsts.rb +118 -0
  118. data/lib/danger/request_sources/vsts_api.rb +138 -0
  119. data/lib/danger/scm_source/git_repo.rb +181 -0
  120. data/lib/danger/version.rb +4 -0
  121. metadata +339 -0
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "danger/danger_core/messages/base"
4
+
5
+ module Danger
6
+ class Violation < BaseMessage
7
+ VALID_TYPES = %I[error warning message].freeze
8
+ attr_accessor :sticky
9
+
10
+ def initialize(message, sticky, file = nil, line = nil, type: :warning)
11
+ raise ArgumentError unless VALID_TYPES.include?(type)
12
+
13
+ super(type: type, message: message, file: file, line: line)
14
+ self.sticky = sticky
15
+ end
16
+
17
+ def ==(other)
18
+ return false if other.nil?
19
+ return false unless other.kind_of? self.class
20
+
21
+ other.message == message &&
22
+ other.sticky == sticky &&
23
+ other.file == file &&
24
+ other.line == line
25
+ end
26
+
27
+ def hash
28
+ h = 1
29
+ h = h * 31 + message.hash
30
+ h = h * 13 + sticky.hash
31
+ h = h * 17 + file.hash
32
+ h = h * 17 + line.hash
33
+ h
34
+ end
35
+
36
+ def <=>(other)
37
+ types = VALID_TYPES + [:markdown]
38
+ order = types.index(type) <=> types.index(other.type)
39
+ return order unless order.zero?
40
+
41
+ compare_by_file_and_line(other)
42
+ end
43
+
44
+ def to_s
45
+ extra = []
46
+ extra << "sticky: #{sticky}"
47
+ extra << "file: #{file}" if file
48
+ extra << "line: #{line}" if line
49
+ extra << "type: #{type}"
50
+
51
+ "Violation #{message} { #{extra.join ', '} }"
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,144 @@
1
+ # coding: utf-8
2
+
3
+ require "danger/plugin_support/plugin"
4
+
5
+ module Danger
6
+ # Handles interacting with Bitbucket Cloud inside a Dangerfile. Provides a few functions which wrap `pr_json` and also
7
+ # through a few standard functions to simplify your code.
8
+ #
9
+ # @example Warn when a PR is classed as work in progress
10
+ #
11
+ # warn "PR is classed as Work in Progress" if bitbucket_cloud.pr_title.include? "[WIP]"
12
+ #
13
+ # @example Declare a PR to be simple to avoid specific Danger rules
14
+ #
15
+ # declared_trivial = (bitbucket_cloud.pr_title + bitbucket_cloud.pr_body).include?("#trivial")
16
+ #
17
+ # @example Ensure that labels have been used on the PR
18
+ #
19
+ # failure "Please add labels to this PR" if bitbucket_cloud.pr_labels.empty?
20
+ #
21
+ # @example Ensure there is a summary for a PR
22
+ #
23
+ # failure "Please provide a summary in the Pull Request description" if bitbucket_cloud.pr_body.length < 5
24
+ #
25
+ # @example Only accept PRs to the develop branch
26
+ #
27
+ # failure "Please re-submit this PR to develop, we may have already fixed your issue." if bitbucket_cloud.branch_for_base != "develop"
28
+ #
29
+ # @example Highlight when a celebrity makes a pull request
30
+ #
31
+ # message "Welcome, Danger." if bitbucket_cloud.pr_author == "dangermcshane"
32
+ #
33
+ # @example Ensure that all PRs have an assignee
34
+ #
35
+ # warn "This PR does not have any assignees yet." if bitbucket_cloud.pr_json[:reviewers].length == 0
36
+ #
37
+ # @example Send a message with links to a collection of specific files
38
+ #
39
+ # if git.modified_files.include? "config/*.js"
40
+ # config_files = git.modified_files.select { |path| path.include? "config/" }
41
+ # message "This PR changes #{ bitbucket_cloud.html_link(config_files) }"
42
+ # end
43
+ #
44
+ # @example Highlight with a clickable link if a Package.json is changed
45
+ #
46
+ # warn "#{bitbucket_cloud.html_link("Package.json")} was edited." if git.modified_files.include? "Package.json"
47
+ #
48
+ # @see danger/danger
49
+ # @tags core, bitbucket_cloud
50
+ #
51
+ class DangerfileBitbucketCloudPlugin < Plugin
52
+ # So that this init can fail.
53
+ def self.new(dangerfile)
54
+ return nil if dangerfile.env.request_source.class != Danger::RequestSources::BitbucketCloud
55
+ super
56
+ end
57
+
58
+ # The instance name used in the Dangerfile
59
+ # @return [String]
60
+ #
61
+ def self.instance_name
62
+ "bitbucket_cloud"
63
+ end
64
+
65
+ def initialize(dangerfile)
66
+ super(dangerfile)
67
+ @bs = dangerfile.env.request_source
68
+ end
69
+
70
+ # @!group Bitbucket Cloud Misc
71
+ # The hash that represents the PR's JSON. For an example of what this looks like
72
+ # see the [Danger Fixture'd one](https://raw.githubusercontent.com/danger/danger/master/spec/fixtures/bitbucket_cloud_api/pr_response.json).
73
+ # @return [Hash]
74
+ def pr_json
75
+ @bs.pr_json
76
+ end
77
+
78
+ # @!group PR Metadata
79
+ # The title of the Pull Request.
80
+ # @return [String]
81
+ #
82
+ def pr_title
83
+ @bs.pr_json[:title].to_s
84
+ end
85
+
86
+ # @!group PR Metadata
87
+ # The body text of the Pull Request.
88
+ # @return [String]
89
+ #
90
+ def pr_description
91
+ @bs.pr_json[:description].to_s
92
+ end
93
+ alias pr_body pr_description
94
+
95
+ # @!group PR Metadata
96
+ # The username of the author of the Pull Request.
97
+ # @return [String]
98
+ #
99
+ def pr_author
100
+ @bs.pr_json[:author][:username]
101
+ end
102
+
103
+ # @!group PR Commit Metadata
104
+ # The branch to which the PR is going to be merged into.
105
+ # @return [String]
106
+ #
107
+ def branch_for_base
108
+ @bs.pr_json[:destination][:branch][:name]
109
+ end
110
+
111
+ # @!group PR Commit Metadata
112
+ # A href that represents the current PR
113
+ # @return [String]
114
+ #
115
+ def pr_link
116
+ @bs.pr_json[:links][:self][:href]
117
+ end
118
+
119
+ # @!group PR Commit Metadata
120
+ # The branch to which the PR is going to be merged from.
121
+ # @return [String]
122
+ #
123
+ def branch_for_head
124
+ @bs.pr_json[:source][:branch][:name]
125
+ end
126
+
127
+ # @!group PR Commit Metadata
128
+ # The base commit to which the PR is going to be merged as a parent.
129
+ # @return [String]
130
+ #
131
+ def base_commit
132
+ @bs.pr_json[:destination][:commit][:hash]
133
+ end
134
+
135
+ # @!group PR Commit Metadata
136
+ # The head commit to which the PR is requesting to be merged from.
137
+ # @return [String]
138
+ #
139
+ def head_commit
140
+ @bs.pr_json[:source][:commit][:hash]
141
+ end
142
+
143
+ end
144
+ end
@@ -0,0 +1,211 @@
1
+ # coding: utf-8
2
+
3
+ require "danger/plugin_support/plugin"
4
+
5
+ module Danger
6
+ # Handles interacting with Bitbucket Server inside a Dangerfile. Provides a few functions which wrap `pr_json` and also
7
+ # through a few standard functions to simplify your code.
8
+ #
9
+ # @example Warn when a PR is classed as work in progress
10
+ #
11
+ # warn "PR is classed as Work in Progress" if bitbucket_server.pr_title.include? "[WIP]"
12
+ #
13
+ # @example Declare a PR to be simple to avoid specific Danger rules
14
+ #
15
+ # declared_trivial = (bitbucket_server.pr_title + bitbucket_server.pr_body).include?("#trivial")
16
+ #
17
+ # @example Ensure that labels have been used on the PR
18
+ #
19
+ # failure "Please add labels to this PR" if bitbucket_server.pr_labels.empty?
20
+ #
21
+ # @example Ensure there is a summary for a PR
22
+ #
23
+ # failure "Please provide a summary in the Pull Request description" if bitbucket_server.pr_body.length < 5
24
+ #
25
+ # @example Only accept PRs to the develop branch
26
+ #
27
+ # failure "Please re-submit this PR to develop, we may have already fixed your issue." if bitbucket_server.branch_for_base != "develop"
28
+ #
29
+ # @example Highlight when a celebrity makes a pull request
30
+ #
31
+ # message "Welcome, Danger." if bitbucket_server.pr_author == "dangermcshane"
32
+ #
33
+ # @example Ensure that all PRs have an assignee
34
+ #
35
+ # warn "This PR does not have any assignees yet." if bitbucket_server.pr_json[:reviewers].length == 0
36
+ #
37
+ # @example Send a message with links to a collection of specific files
38
+ #
39
+ # if git.modified_files.include? "config/*.js"
40
+ # config_files = git.modified_files.select { |path| path.include? "config/" }
41
+ # message "This PR changes #{ bitbucket_server.html_link(config_files) }"
42
+ # end
43
+ #
44
+ # @example Highlight with a clickable link if a Package.json is changed
45
+ #
46
+ # warn "#{bitbucket_server.html_link("Package.json")} was edited." if git.modified_files.include? "Package.json"
47
+ #
48
+ # @see danger/danger
49
+ # @tags core, bitbucket_server
50
+ #
51
+ class DangerfileBitbucketServerPlugin < Plugin
52
+ # So that this init can fail.
53
+ def self.new(dangerfile)
54
+ return nil if dangerfile.env.request_source.class != Danger::RequestSources::BitbucketServer
55
+ super
56
+ end
57
+
58
+ # The instance name used in the Dangerfile
59
+ # @return [String]
60
+ #
61
+ def self.instance_name
62
+ "bitbucket_server"
63
+ end
64
+
65
+ def initialize(dangerfile)
66
+ super(dangerfile)
67
+ @bs = dangerfile.env.request_source
68
+ end
69
+
70
+ # @!group Bitbucket Server Misc
71
+ # The hash that represents the PR's JSON. For an example of what this looks like
72
+ # see the [Danger Fixture'd one](https://raw.githubusercontent.com/danger/danger/master/spec/fixtures/bitbucket_server_api/pr_response.json).
73
+ # @return [Hash]
74
+ def pr_json
75
+ @bs.pr_json
76
+ end
77
+
78
+ # @!group PR Metadata
79
+ # The title of the Pull Request.
80
+ # @return [String]
81
+ #
82
+ def pr_title
83
+ @bs.pr_json[:title].to_s
84
+ end
85
+
86
+ # @!group PR Metadata
87
+ # The body text of the Pull Request.
88
+ # @return [String]
89
+ #
90
+ def pr_description
91
+ @bs.pr_json[:description].to_s
92
+ end
93
+ alias pr_body pr_description
94
+
95
+ # @!group PR Metadata
96
+ # The username of the author of the Pull Request.
97
+ # @return [String]
98
+ #
99
+ def pr_author
100
+ @bs.pr_json[:author][:user][:slug].to_s
101
+ end
102
+
103
+ # @!group PR Commit Metadata
104
+ # The branch to which the PR is going to be merged into.
105
+ # @return [String]
106
+ #
107
+ def branch_for_base
108
+ @bs.pr_json[:toRef][:displayId].to_s
109
+ end
110
+
111
+ # @!group PR Commit Metadata
112
+ # A href that represents the current PR
113
+ # @return [String]
114
+ #
115
+ def pr_link
116
+ @bs.pr_json[:links][:self].flat_map { |l| l[:href] }.first.to_s
117
+ end
118
+
119
+ # @!group PR Commit Metadata
120
+ # The branch to which the PR is going to be merged from.
121
+ # @return [String]
122
+ #
123
+ def branch_for_head
124
+ @bs.pr_json[:fromRef][:displayId].to_s
125
+ end
126
+
127
+ # @!group PR Commit Metadata
128
+ # The base commit to which the PR is going to be merged as a parent.
129
+ # @return [String]
130
+ #
131
+ def base_commit
132
+ @bs.pr_json[:toRef][:latestCommit].to_s
133
+ end
134
+
135
+ # @!group PR Commit Metadata
136
+ # The head commit to which the PR is requesting to be merged from.
137
+ # @return [String]
138
+ #
139
+ def head_commit
140
+ @bs.pr_json[:fromRef][:latestCommit].to_s
141
+ end
142
+
143
+ # @!group Bitbucket Server Misc
144
+ # Returns a list of Markdown links for a file, or files in the head repository.
145
+ # It returns a string of multiple anchors if passed an array.
146
+ # @note Atlassian [disabled inline HTML support](https://jira.atlassian.com/browse/BSERV-7147).
147
+ # This method method left for backward compatibility.
148
+ # @param [String or Array<String>] paths
149
+ # A list of strings to convert to github anchors
150
+ # @param [Bool] full_path
151
+ # Shows the full path as the link's text, defaults to `true`.
152
+ #
153
+ # @return [String]
154
+ #
155
+ def html_link(paths, full_path: true)
156
+ markdown_link(paths, full_path: full_path)
157
+ end
158
+
159
+ # @!group Bitbucket Server Misc
160
+ # Returns a list of Markdown links for a file, or files in the head repository.
161
+ # It returns a string of multiple links if passed an array.
162
+ # @param [String or Array<String>] paths
163
+ # A list of strings to convert to Markdown links
164
+ # @param [Bool] full_path
165
+ # Shows the full path as the link's text, defaults to `true`.
166
+ #
167
+ # @return [String]
168
+ #
169
+ def markdown_link(paths, full_path: true)
170
+ create_link(paths, full_path) { |href, text| create_markdown_link(href, text) }
171
+ end
172
+
173
+ # @!group Bitbucket Server Misc
174
+ # Updates the PR with build status and build server job link.
175
+ # @param [String] status
176
+ # SUCCESSFUL, FAILED and INPROGRESS
177
+ # @param [String] build_job_link
178
+ # Build server job link
179
+ # @param [String] description
180
+ # Build status description
181
+ # @return [String]
182
+ #
183
+ def update_pr_build_status(status, build_job_link, description)
184
+ @bs.update_pr_build_status(status, build_job_link, description)
185
+ end
186
+
187
+ private
188
+
189
+ def create_link(paths, full_path)
190
+ paths = [paths] unless paths.kind_of?(Array)
191
+ commit = head_commit
192
+ repo = pr_json[:fromRef][:repository][:links][:self].flat_map { |l| l[:href] }.first
193
+
194
+ paths = paths.map do |path|
195
+ path, line = path.split("#")
196
+ url_path = path.start_with?("/") ? path : "/#{path}"
197
+ text = full_path ? path : File.basename(path)
198
+ url_path.gsub!(" ", "%20")
199
+ line_ref = line ? "##{line}" : ""
200
+ yield("#{repo}#{url_path}?at=#{commit}#{line_ref}", text)
201
+ end
202
+
203
+ return paths.first if paths.count < 2
204
+ paths.first(paths.count - 1).join(", ") + " & " + paths.last
205
+ end
206
+
207
+ def create_markdown_link(href, text)
208
+ "[#{text}](#{href})"
209
+ end
210
+ end
211
+ end
@@ -0,0 +1,248 @@
1
+ require "danger/plugin_support/plugin"
2
+
3
+ module Danger
4
+ # A way to interact with Danger herself. Offering APIs to import plugins,
5
+ # and Dangerfiles from multiple sources.
6
+ #
7
+ # @example Import a plugin available over HTTP
8
+ #
9
+ # device_grid = "https://raw.githubusercontent.com/fastlane/fastlane/master/danger-device_grid/lib/device_grid/plugin.rb"
10
+ # danger.import_plugin(device_grid)
11
+ #
12
+ # @example Import from a local file reference
13
+ #
14
+ # danger.import_plugin("danger/plugins/watch_plugin.rb")
15
+ #
16
+ # @example Import all files inside a folder
17
+ #
18
+ # danger.import_plugin("danger/plugins/*.rb")
19
+ #
20
+ # @example Run a Dangerfile from inside a sub-folder
21
+ #
22
+ # danger.import_dangerfile(path: "path/to/Dangerfile")
23
+ #
24
+ # @example Run a Dangerfile from inside a gem
25
+ #
26
+ # danger.import_dangerfile(gem: "ruby-grape-danger")
27
+ #
28
+ # @example Run a Dangerfile from inside a repo
29
+ #
30
+ # danger.import_dangerfile(gitlab_project_id: 1345)
31
+ #
32
+ # @example Run a Dangerfile from inside a repo branch and path
33
+ #
34
+ # danger.import_dangerfile(github: "ruby-grape/danger", branch: "custom", path: "path/to/Dangerfile")
35
+ #
36
+ # @see danger/danger
37
+ # @tags core, plugins
38
+
39
+ class DangerfileDangerPlugin < Plugin
40
+ # The instance name used in the Dangerfile
41
+ # @return [String]
42
+ #
43
+ def self.instance_name
44
+ "danger"
45
+ end
46
+
47
+ # @!group Danger
48
+ # Download a local or remote plugin and make it usable inside the Dangerfile.
49
+ #
50
+ # @param [String] path_or_url
51
+ # a local path or a https URL to the Ruby file to import
52
+ # a danger plugin from.
53
+ # @return [void]
54
+ #
55
+ def import_plugin(path_or_url)
56
+ raise "`import_plugin` requires a string" unless path_or_url.kind_of?(String)
57
+
58
+ if path_or_url.start_with?("http")
59
+ import_url(path_or_url)
60
+ else
61
+ import_local(path_or_url)
62
+ end
63
+ end
64
+
65
+ # @!group Danger
66
+ # Import a Dangerfile.
67
+ #
68
+ # @param [Hash] opts
69
+ # @option opts [String] :github GitHub repo
70
+ # @option opts [String] :gitlab GitLab repo
71
+ # @option opts [String] :gem Gem name
72
+ # @option opts [String] :path Path to Dangerfile
73
+ # @return [void]
74
+ def import_dangerfile(opts)
75
+ if opts.kind_of?(String)
76
+ warn "Use `import_dangerfile(github: '#{opts}')` instead of `import_dangerfile '#{opts}'`."
77
+ import_dangerfile_from_github(opts)
78
+ elsif opts.kind_of?(Hash)
79
+ if opts.key?(:github)
80
+ import_dangerfile_from_github(opts[:github], opts[:branch], opts[:path])
81
+ elsif opts.key?(:gitlab)
82
+ import_dangerfile_from_gitlab(opts[:gitlab], opts[:branch], opts[:path])
83
+ elsif opts.key?(:path)
84
+ import_dangerfile_from_path(opts[:path])
85
+ elsif opts.key?(:gem)
86
+ import_dangerfile_from_gem(opts[:gem])
87
+ else
88
+ raise "`import` requires a Hash with either :github, :gitlab, :gem, or :path"
89
+ end
90
+ else
91
+ raise "`import` requires a Hash"
92
+ end
93
+ end
94
+
95
+ # @!group Danger
96
+ # Returns the name of the current SCM Provider being used.
97
+ # @return [Symbol] The name of the SCM Provider used for the active repository.
98
+ def scm_provider
99
+ return :unknown unless env.request_source
100
+
101
+ case env.request_source
102
+ when Danger::RequestSources::GitHub
103
+ :github
104
+ when Danger::RequestSources::GitLab
105
+ :gitlab
106
+ when Danger::RequestSources::BitbucketServer
107
+ :bitbucket_server
108
+ when Danger::RequestSources::BitbucketCloud
109
+ :bitbucket_cloud
110
+ when Danger::RequestSources::VSTS
111
+ :vsts
112
+ else
113
+ :unknown
114
+ end
115
+ end
116
+
117
+ private
118
+
119
+ # @!group Danger
120
+ # Read and execute a local Dangerfile.
121
+ #
122
+ # @param [String] path
123
+ # A path to a Dangerfile.
124
+ # @return [void]
125
+ #
126
+ def import_dangerfile_from_path(path)
127
+ raise "`import_dangerfile_from_path` requires a string" unless path.kind_of?(String)
128
+ local_path = File.join(path, "Dangerfile")
129
+ @dangerfile.parse(Pathname.new(local_path))
130
+ end
131
+
132
+ # @!group Danger
133
+ # Read and execute a Dangerfile from a gem.
134
+ #
135
+ # @param [String] name
136
+ # The name of the gem that contains a Dangerfile.
137
+ # @return [void]
138
+ #
139
+ def import_dangerfile_from_gem(name)
140
+ raise "`import_dangerfile_from_gem` requires a string" unless name.kind_of?(String)
141
+ spec = Gem::Specification.find_by_name(name)
142
+ import_dangerfile_from_path(spec.gem_dir)
143
+ rescue Gem::MissingSpecError
144
+ raise "`import_dangerfile_from_gem` tried to load `#{name}` and failed, did you forget to include it in your Gemfile?"
145
+ end
146
+
147
+ # @!group Danger
148
+ # Download and execute a remote Dangerfile.
149
+ #
150
+ # @param [String] slug
151
+ # A slug that represents the repo where the Dangerfile is.
152
+ # @param [String] branch
153
+ # A branch from repo where the Dangerfile is.
154
+ # @param [String] path
155
+ # The path at the repo where Dangerfile is.
156
+ # @return [void]
157
+ #
158
+ def import_dangerfile_from_github(slug, branch = nil, path = nil)
159
+ raise "`import_dangerfile_from_github` requires a string" unless slug.kind_of?(String)
160
+ org, repo = slug.split("/")
161
+ download_url = env.request_source.file_url(organisation: org, repository: repo, branch: branch, path: path || "Dangerfile")
162
+ local_path = download(download_url)
163
+ @dangerfile.parse(Pathname.new(local_path))
164
+ end
165
+
166
+ # @!group Danger
167
+ # Download and execute a remote Dangerfile.
168
+ #
169
+ # @param [Int] slug_or_project_id
170
+ # The slug or id of the repo where the Dangerfile is.
171
+ # @param [String] branch
172
+ # A branch from repo where the Dangerfile is.
173
+ # @param [String] path
174
+ # The path at the repo where Dangerfile is.
175
+ # @return [void]
176
+ #
177
+ def import_dangerfile_from_gitlab(slug_or_project_id, branch = nil, path = nil)
178
+ download_url = env.request_source.file_url(repository: slug_or_project_id, branch: branch, path: path || "Dangerfile")
179
+ local_path = download(download_url)
180
+ @dangerfile.parse(Pathname.new(local_path))
181
+ end
182
+
183
+ # @!group Plugins
184
+ # Download a local or remote plugin or Dangerfile.
185
+ # This method will not import the file for you, use plugin.import instead
186
+ #
187
+ # @param [String] path_or_url
188
+ # a local path or a https URL to the Ruby file to import
189
+ # a danger plugin from.
190
+ # @return [String] The path to the downloaded Ruby file
191
+ #
192
+ def download(path_or_url)
193
+ raise "`download` requires a string" unless path_or_url.kind_of?(String)
194
+ raise "URL is not https, for security reasons `danger` only supports encrypted requests" if URI.parse(path_or_url).scheme != "https"
195
+
196
+ require "tmpdir"
197
+ require "faraday"
198
+
199
+ @http_client ||= Faraday.new do |b|
200
+ b.adapter :net_http
201
+ end
202
+ content = @http_client.get(path_or_url)
203
+
204
+ path = File.join(Dir.mktmpdir, "temporary_danger.rb")
205
+ File.write(path, content.body)
206
+ return path
207
+ end
208
+
209
+ # @!group Plugins
210
+ # Download a remote plugin and use it locally.
211
+ #
212
+ # @param [String] url
213
+ # https URL to the Ruby file to use
214
+ # @return [void]
215
+ def import_url(url)
216
+ path = download(url)
217
+ import_local(path)
218
+ end
219
+
220
+ # @!group Plugins
221
+ # Import one or more local plugins.
222
+ #
223
+ # @param [String] path
224
+ # The path to the file to import
225
+ # Can also be a pattern (./**/*plugin.rb)
226
+ # @return [void]
227
+ def import_local(path)
228
+ Dir[path].each do |file|
229
+ validate_file_contains_plugin!(file) do
230
+ # Without the expand_path it would fail if the path doesn't start with ./
231
+ require File.expand_path(file)
232
+ end
233
+
234
+ refresh_plugins
235
+ end
236
+ end
237
+
238
+ # Raises an error when the given block does not register a plugin.
239
+ def validate_file_contains_plugin!(file)
240
+ plugin_count_was = Danger::Plugin.all_plugins.length
241
+ yield
242
+
243
+ if Danger::Plugin.all_plugins.length == plugin_count_was
244
+ raise("#{file} doesn't contain any valid danger plugins.")
245
+ end
246
+ end
247
+ end
248
+ end