danger 8.0.4
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 +7 -0
- data/LICENSE +22 -0
- data/README.md +94 -0
- data/bin/danger +5 -0
- data/lib/assets/DangerfileTemplate +13 -0
- data/lib/danger.rb +44 -0
- data/lib/danger/ci_source/appcenter.rb +55 -0
- data/lib/danger/ci_source/appveyor.rb +60 -0
- data/lib/danger/ci_source/azure_pipelines.rb +44 -0
- data/lib/danger/ci_source/bamboo.rb +41 -0
- data/lib/danger/ci_source/bitbucket_pipelines.rb +37 -0
- data/lib/danger/ci_source/bitrise.rb +65 -0
- data/lib/danger/ci_source/buddybuild.rb +62 -0
- data/lib/danger/ci_source/buildkite.rb +51 -0
- data/lib/danger/ci_source/ci_source.rb +37 -0
- data/lib/danger/ci_source/circle.rb +94 -0
- data/lib/danger/ci_source/circle_api.rb +51 -0
- data/lib/danger/ci_source/cirrus.rb +31 -0
- data/lib/danger/ci_source/code_build.rb +57 -0
- data/lib/danger/ci_source/codefresh.rb +53 -0
- data/lib/danger/ci_source/codeship.rb +44 -0
- data/lib/danger/ci_source/dotci.rb +52 -0
- data/lib/danger/ci_source/drone.rb +71 -0
- data/lib/danger/ci_source/github_actions.rb +43 -0
- data/lib/danger/ci_source/gitlab_ci.rb +86 -0
- data/lib/danger/ci_source/jenkins.rb +149 -0
- data/lib/danger/ci_source/local_git_repo.rb +119 -0
- data/lib/danger/ci_source/local_only_git_repo.rb +47 -0
- data/lib/danger/ci_source/screwdriver.rb +47 -0
- data/lib/danger/ci_source/semaphore.rb +37 -0
- data/lib/danger/ci_source/support/commits.rb +17 -0
- data/lib/danger/ci_source/support/find_repo_info_from_logs.rb +35 -0
- data/lib/danger/ci_source/support/find_repo_info_from_url.rb +42 -0
- data/lib/danger/ci_source/support/local_pull_request.rb +14 -0
- data/lib/danger/ci_source/support/no_pull_request.rb +7 -0
- data/lib/danger/ci_source/support/no_repo_info.rb +5 -0
- data/lib/danger/ci_source/support/pull_request_finder.rb +179 -0
- data/lib/danger/ci_source/support/remote_pull_request.rb +15 -0
- data/lib/danger/ci_source/support/repo_info.rb +10 -0
- data/lib/danger/ci_source/surf.rb +37 -0
- data/lib/danger/ci_source/teamcity.rb +161 -0
- data/lib/danger/ci_source/travis.rb +51 -0
- data/lib/danger/ci_source/vsts.rb +73 -0
- data/lib/danger/ci_source/xcode_server.rb +48 -0
- data/lib/danger/clients/rubygems_client.rb +14 -0
- data/lib/danger/commands/dangerfile/gem.rb +43 -0
- data/lib/danger/commands/dangerfile/init.rb +30 -0
- data/lib/danger/commands/dry_run.rb +54 -0
- data/lib/danger/commands/init.rb +297 -0
- data/lib/danger/commands/init_helpers/interviewer.rb +92 -0
- data/lib/danger/commands/local.rb +83 -0
- data/lib/danger/commands/local_helpers/http_cache.rb +36 -0
- data/lib/danger/commands/local_helpers/local_setup.rb +46 -0
- data/lib/danger/commands/local_helpers/pry_setup.rb +31 -0
- data/lib/danger/commands/plugins/plugin_json.rb +46 -0
- data/lib/danger/commands/plugins/plugin_lint.rb +54 -0
- data/lib/danger/commands/plugins/plugin_readme.rb +45 -0
- data/lib/danger/commands/pr.rb +92 -0
- data/lib/danger/commands/runner.rb +94 -0
- data/lib/danger/commands/staging.rb +53 -0
- data/lib/danger/commands/systems.rb +43 -0
- data/lib/danger/comment_generators/bitbucket_server.md.erb +20 -0
- data/lib/danger/comment_generators/bitbucket_server_inline.md.erb +15 -0
- data/lib/danger/comment_generators/bitbucket_server_message_group.md.erb +12 -0
- data/lib/danger/comment_generators/github.md.erb +55 -0
- data/lib/danger/comment_generators/github_inline.md.erb +26 -0
- data/lib/danger/comment_generators/gitlab.md.erb +40 -0
- data/lib/danger/comment_generators/gitlab_inline.md.erb +26 -0
- data/lib/danger/comment_generators/vsts.md.erb +20 -0
- data/lib/danger/core_ext/file_list.rb +18 -0
- data/lib/danger/core_ext/string.rb +20 -0
- data/lib/danger/danger_core/dangerfile.rb +341 -0
- data/lib/danger/danger_core/dangerfile_dsl.rb +29 -0
- data/lib/danger/danger_core/dangerfile_generator.rb +11 -0
- data/lib/danger/danger_core/environment_manager.rb +123 -0
- data/lib/danger/danger_core/executor.rb +92 -0
- data/lib/danger/danger_core/message_aggregator.rb +49 -0
- data/lib/danger/danger_core/message_group.rb +68 -0
- data/lib/danger/danger_core/messages/base.rb +56 -0
- data/lib/danger/danger_core/messages/markdown.rb +42 -0
- data/lib/danger/danger_core/messages/violation.rb +54 -0
- data/lib/danger/danger_core/plugins/dangerfile_bitbucket_cloud_plugin.rb +144 -0
- data/lib/danger/danger_core/plugins/dangerfile_bitbucket_server_plugin.rb +211 -0
- data/lib/danger/danger_core/plugins/dangerfile_danger_plugin.rb +248 -0
- data/lib/danger/danger_core/plugins/dangerfile_git_plugin.rb +158 -0
- data/lib/danger/danger_core/plugins/dangerfile_github_plugin.rb +254 -0
- data/lib/danger/danger_core/plugins/dangerfile_gitlab_plugin.rb +240 -0
- data/lib/danger/danger_core/plugins/dangerfile_local_only_plugin.rb +42 -0
- data/lib/danger/danger_core/plugins/dangerfile_messaging_plugin.rb +218 -0
- data/lib/danger/danger_core/plugins/dangerfile_vsts_plugin.rb +191 -0
- data/lib/danger/danger_core/standard_error.rb +143 -0
- data/lib/danger/helpers/array_subclass.rb +61 -0
- data/lib/danger/helpers/comment.rb +32 -0
- data/lib/danger/helpers/comments_helper.rb +178 -0
- data/lib/danger/helpers/comments_parsing_helper.rb +70 -0
- data/lib/danger/helpers/emoji_mapper.rb +41 -0
- data/lib/danger/helpers/find_max_num_violations.rb +31 -0
- data/lib/danger/helpers/message_groups_array_helper.rb +31 -0
- data/lib/danger/plugin_support/gems_resolver.rb +77 -0
- data/lib/danger/plugin_support/plugin.rb +49 -0
- data/lib/danger/plugin_support/plugin_file_resolver.rb +30 -0
- data/lib/danger/plugin_support/plugin_linter.rb +161 -0
- data/lib/danger/plugin_support/plugin_parser.rb +199 -0
- data/lib/danger/plugin_support/templates/readme_table.html.erb +26 -0
- data/lib/danger/request_sources/bitbucket_cloud.rb +171 -0
- data/lib/danger/request_sources/bitbucket_cloud_api.rb +181 -0
- data/lib/danger/request_sources/bitbucket_server.rb +105 -0
- data/lib/danger/request_sources/bitbucket_server_api.rb +117 -0
- data/lib/danger/request_sources/github/github.rb +530 -0
- data/lib/danger/request_sources/github/github_review.rb +126 -0
- data/lib/danger/request_sources/github/github_review_resolver.rb +19 -0
- data/lib/danger/request_sources/github/github_review_unsupported.rb +25 -0
- data/lib/danger/request_sources/gitlab.rb +525 -0
- data/lib/danger/request_sources/local_only.rb +53 -0
- data/lib/danger/request_sources/request_source.rb +85 -0
- data/lib/danger/request_sources/support/get_ignored_violation.rb +17 -0
- data/lib/danger/request_sources/vsts.rb +118 -0
- data/lib/danger/request_sources/vsts_api.rb +138 -0
- data/lib/danger/scm_source/git_repo.rb +181 -0
- data/lib/danger/version.rb +4 -0
- metadata +339 -0
@@ -0,0 +1,158 @@
|
|
1
|
+
require "danger/plugin_support/plugin"
|
2
|
+
require "danger/core_ext/file_list"
|
3
|
+
|
4
|
+
# Danger
|
5
|
+
module Danger
|
6
|
+
# Handles interacting with git inside a Dangerfile. Providing access to files that have changed, and useful statistics. Also provides
|
7
|
+
# access to the commits in the form of [Git::Log](https://github.com/schacon/ruby-git/blob/master/lib/git/log.rb) objects.
|
8
|
+
#
|
9
|
+
# @example Do something to all new and edited markdown files
|
10
|
+
#
|
11
|
+
# markdowns = (git.added_files + git.modified_files)
|
12
|
+
# do_something markdowns.select{ |file| file.end_with? "md" }
|
13
|
+
#
|
14
|
+
# @example Don't allow a file to be deleted
|
15
|
+
#
|
16
|
+
# deleted = git.deleted_files.include? "my/favourite.file"
|
17
|
+
# failure "Don't delete my precious" if deleted
|
18
|
+
#
|
19
|
+
# @example Fail really big diffs
|
20
|
+
#
|
21
|
+
# failure "We cannot handle the scale of this PR" if git.lines_of_code > 50_000
|
22
|
+
#
|
23
|
+
# @example Warn when there are merge commits in the diff
|
24
|
+
#
|
25
|
+
# if git.commits.any? { |c| c.message =~ /^Merge branch 'master'/ }
|
26
|
+
# warn 'Please rebase to get rid of the merge commits in this PR'
|
27
|
+
# end
|
28
|
+
#
|
29
|
+
# @example Warn when somebody tries to add nokogiri to the project
|
30
|
+
#
|
31
|
+
# diff = git.diff_for_file("Gemfile.lock")
|
32
|
+
# if diff && diff.patch =~ "nokogiri"
|
33
|
+
# warn 'Please do not add nokogiri to the project. Thank you.'
|
34
|
+
# end
|
35
|
+
#
|
36
|
+
# @see danger/danger
|
37
|
+
# @tags core, git
|
38
|
+
|
39
|
+
class DangerfileGitPlugin < Plugin
|
40
|
+
# The instance name used in the Dangerfile
|
41
|
+
# @return [String]
|
42
|
+
#
|
43
|
+
def self.instance_name
|
44
|
+
"git"
|
45
|
+
end
|
46
|
+
|
47
|
+
def initialize(dangerfile)
|
48
|
+
super(dangerfile)
|
49
|
+
raise unless dangerfile.env.scm.class == Danger::GitRepo
|
50
|
+
|
51
|
+
@git = dangerfile.env.scm
|
52
|
+
end
|
53
|
+
|
54
|
+
# @!group Git Files
|
55
|
+
# Paths for files that were added during the diff
|
56
|
+
# @return [FileList<String>] an [Array] subclass
|
57
|
+
#
|
58
|
+
def added_files
|
59
|
+
Danger::FileList.new(@git.diff.select { |diff| diff.type == "new" }.map(&:path))
|
60
|
+
end
|
61
|
+
|
62
|
+
# @!group Git Files
|
63
|
+
# Paths for files that were removed during the diff
|
64
|
+
# @return [FileList<String>] an [Array] subclass
|
65
|
+
#
|
66
|
+
def deleted_files
|
67
|
+
Danger::FileList.new(@git.diff.select { |diff| diff.type == "deleted" }.map(&:path))
|
68
|
+
end
|
69
|
+
|
70
|
+
# @!group Git Files
|
71
|
+
# Paths for files that changed during the diff
|
72
|
+
# @return [FileList<String>] an [Array] subclass
|
73
|
+
#
|
74
|
+
def modified_files
|
75
|
+
Danger::FileList.new(@git.diff.select { |diff| diff.type == "modified" }.map(&:path))
|
76
|
+
end
|
77
|
+
|
78
|
+
# @!group Git Metadata
|
79
|
+
# List of renamed files
|
80
|
+
# @return [Array<Hash>] with keys `:before` and `:after`
|
81
|
+
#
|
82
|
+
def renamed_files
|
83
|
+
@git.renamed_files
|
84
|
+
end
|
85
|
+
|
86
|
+
# @!group Git Metadata
|
87
|
+
# Whole diff
|
88
|
+
# @return [Git::Diff] from the gem `git`
|
89
|
+
#
|
90
|
+
def diff
|
91
|
+
@git.diff
|
92
|
+
end
|
93
|
+
|
94
|
+
# @!group Git Metadata
|
95
|
+
# The overall lines of code added/removed in the diff
|
96
|
+
# @return [Fixnum]
|
97
|
+
#
|
98
|
+
def lines_of_code
|
99
|
+
@git.diff.lines
|
100
|
+
end
|
101
|
+
|
102
|
+
# @!group Git Metadata
|
103
|
+
# The overall lines of code removed in the diff
|
104
|
+
# @return [Fixnum]
|
105
|
+
#
|
106
|
+
def deletions
|
107
|
+
@git.diff.deletions
|
108
|
+
end
|
109
|
+
|
110
|
+
# @!group Git Metadata
|
111
|
+
# The overall lines of code added in the diff
|
112
|
+
# @return [Fixnum]
|
113
|
+
#
|
114
|
+
def insertions
|
115
|
+
@git.diff.insertions
|
116
|
+
end
|
117
|
+
|
118
|
+
# @!group Git Metadata
|
119
|
+
# The log of commits inside the diff
|
120
|
+
# @return [Git::Log] from the gem `git`
|
121
|
+
#
|
122
|
+
def commits
|
123
|
+
@git.log.to_a
|
124
|
+
end
|
125
|
+
|
126
|
+
# @!group Git Metadata
|
127
|
+
# Details for a specific file in this diff
|
128
|
+
# @return [Git::Diff::DiffFile] from the gem `git`
|
129
|
+
#
|
130
|
+
def diff_for_file(file)
|
131
|
+
(added_files + modified_files).include?(file) ? @git.diff[file] : nil
|
132
|
+
end
|
133
|
+
|
134
|
+
# @!group Git Metadata
|
135
|
+
# Statistics for a specific file in this diff
|
136
|
+
# @return [Hash] with keys `:insertions`, `:deletions` giving line counts, and `:before`, `:after` giving file contents, or nil if the file has no changes or does not exist
|
137
|
+
#
|
138
|
+
def info_for_file(file)
|
139
|
+
return nil unless modified_files.include?(file) || added_files.include?(file) || deleted_files.include?(file)
|
140
|
+
stats = @git.diff.stats[:files][file]
|
141
|
+
diff = @git.diff[file]
|
142
|
+
{
|
143
|
+
insertions: stats[:insertions],
|
144
|
+
deletions: stats[:deletions],
|
145
|
+
before: added_files.include?(file) || deleted_files.include?(file) ? nil : diff.blob(:src).contents,
|
146
|
+
after: added_files.include?(file) || deleted_files.include?(file) ? nil : diff.blob(:dst).contents
|
147
|
+
}
|
148
|
+
end
|
149
|
+
|
150
|
+
# @!group Git Metadata
|
151
|
+
# List of remote tags
|
152
|
+
# @return [String]
|
153
|
+
#
|
154
|
+
def tags
|
155
|
+
@git.tags.each_line
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
@@ -0,0 +1,254 @@
|
|
1
|
+
require "danger/plugin_support/plugin"
|
2
|
+
|
3
|
+
module Danger
|
4
|
+
# Handles interacting with GitHub inside a Dangerfile. Provides a few functions which wrap `pr_json` and also
|
5
|
+
# through a few standard functions to simplify your code.
|
6
|
+
#
|
7
|
+
# @example Warn when a PR is classed as work in progress
|
8
|
+
#
|
9
|
+
# warn "PR is classed as Work in Progress" if github.pr_title.include? "[WIP]"
|
10
|
+
#
|
11
|
+
# @example Declare a PR to be simple to avoid specific Danger rules
|
12
|
+
#
|
13
|
+
# declared_trivial = (github.pr_title + github.pr_body).include?("#trivial")
|
14
|
+
#
|
15
|
+
# @example Ensure that labels have been used on the PR
|
16
|
+
#
|
17
|
+
# failure "Please add labels to this PR" if github.pr_labels.empty?
|
18
|
+
#
|
19
|
+
# @example Check if a user is in a specific GitHub org, and message them if so
|
20
|
+
#
|
21
|
+
# unless github.api.organization_member?('danger', github.pr_author)
|
22
|
+
# message "@#{github.pr_author} is not a contributor yet, would you like to join the Danger org?"
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
# @example Ensure there is a summary for a PR
|
26
|
+
#
|
27
|
+
# failure "Please provide a summary in the Pull Request description" if github.pr_body.length < 5
|
28
|
+
#
|
29
|
+
# @example Only accept PRs to the develop branch
|
30
|
+
#
|
31
|
+
# failure "Please re-submit this PR to develop, we may have already fixed your issue." if github.branch_for_base != "develop"
|
32
|
+
#
|
33
|
+
# @example Note when PRs don't reference a milestone, which goes away when it does
|
34
|
+
#
|
35
|
+
# has_milestone = github.pr_json["milestone"] != nil
|
36
|
+
# warn("This PR does not refer to an existing milestone", sticky: false) unless has_milestone
|
37
|
+
#
|
38
|
+
# @example Note when a PR cannot be manually merged, which goes away when you can
|
39
|
+
#
|
40
|
+
# can_merge = github.pr_json["mergeable"]
|
41
|
+
# warn("This PR cannot be merged yet.", sticky: false) unless can_merge
|
42
|
+
#
|
43
|
+
# @example Highlight when a celebrity makes a pull request
|
44
|
+
#
|
45
|
+
# message "Welcome, Danger." if github.pr_author == "dangermcshane"
|
46
|
+
#
|
47
|
+
# @example Ensure that all PRs have an assignee
|
48
|
+
#
|
49
|
+
# warn "This PR does not have any assignees yet." unless github.pr_json["assignee"]
|
50
|
+
#
|
51
|
+
# @example Send a message with links to a collection of specific files
|
52
|
+
#
|
53
|
+
# if git.modified_files.include? "config/*.js"
|
54
|
+
# config_files = git.modified_files.select { |path| path.include? "config/" }
|
55
|
+
# message "This PR changes #{ github.html_link(config_files) }"
|
56
|
+
# end
|
57
|
+
#
|
58
|
+
# @example Highlight with a clickable link if a Package.json is changed
|
59
|
+
#
|
60
|
+
# warn "#{github.html_link("Package.json")} was edited." if git.modified_files.include? "Package.json"
|
61
|
+
#
|
62
|
+
# @example Note an issue with a particular line on a file using the #L[num] syntax, e.g. `#L23`
|
63
|
+
#
|
64
|
+
# linter_json = `my_linter lint "file"`
|
65
|
+
# results = JSON.parse linter_json
|
66
|
+
# unless results.empty?
|
67
|
+
# file, line, warning = result.first
|
68
|
+
# warn "#{github.html_link("#{file}#L#{line}")} has linter issue: #{warning}."
|
69
|
+
# end
|
70
|
+
#
|
71
|
+
#
|
72
|
+
# @see danger/danger
|
73
|
+
# @tags core, github
|
74
|
+
#
|
75
|
+
class DangerfileGitHubPlugin < Plugin
|
76
|
+
# So that this init can fail.
|
77
|
+
def self.new(dangerfile)
|
78
|
+
return nil if dangerfile.env.request_source.class != Danger::RequestSources::GitHub
|
79
|
+
super
|
80
|
+
end
|
81
|
+
|
82
|
+
def initialize(dangerfile)
|
83
|
+
super(dangerfile)
|
84
|
+
|
85
|
+
@github = dangerfile.env.request_source
|
86
|
+
end
|
87
|
+
|
88
|
+
# The instance name used in the Dangerfile
|
89
|
+
# @return [String]
|
90
|
+
#
|
91
|
+
def self.instance_name
|
92
|
+
"github"
|
93
|
+
end
|
94
|
+
|
95
|
+
# @!group PR Review
|
96
|
+
#
|
97
|
+
# In Beta. Provides access to creating a GitHub Review instead of a typical GitHub comment.
|
98
|
+
#
|
99
|
+
# To use you announce the start of your review, and the end via the `start` and `submit` functions,
|
100
|
+
# for example:
|
101
|
+
#
|
102
|
+
# github.review.start
|
103
|
+
# github.review.fail(message)
|
104
|
+
# github.review.warn(message)
|
105
|
+
# github.review.message(message)
|
106
|
+
# github.review.markdown(message)
|
107
|
+
# github.review.submit
|
108
|
+
#
|
109
|
+
# @return [ReviewDSL]
|
110
|
+
def review
|
111
|
+
@github.review
|
112
|
+
end
|
113
|
+
|
114
|
+
# @!group PR Metadata
|
115
|
+
# The title of the Pull Request.
|
116
|
+
# @return [String]
|
117
|
+
#
|
118
|
+
def pr_title
|
119
|
+
@github.pr_json["title"].to_s
|
120
|
+
end
|
121
|
+
|
122
|
+
# @!group PR Metadata
|
123
|
+
# The body text of the Pull Request.
|
124
|
+
# @return [String]
|
125
|
+
#
|
126
|
+
def pr_body
|
127
|
+
pr_json["body"].to_s
|
128
|
+
end
|
129
|
+
|
130
|
+
# @!group PR Metadata
|
131
|
+
# The username of the author of the Pull Request.
|
132
|
+
# @return [String]
|
133
|
+
#
|
134
|
+
def pr_author
|
135
|
+
pr_json["user"]["login"].to_s
|
136
|
+
end
|
137
|
+
|
138
|
+
# @!group PR Metadata
|
139
|
+
# The labels assigned to the Pull Request.
|
140
|
+
# @return [String]
|
141
|
+
#
|
142
|
+
def pr_labels
|
143
|
+
@github.issue_json["labels"].map { |l| l[:name] }
|
144
|
+
end
|
145
|
+
|
146
|
+
# @!group PR Commit Metadata
|
147
|
+
# The branch to which the PR is going to be merged into.
|
148
|
+
# @return [String]
|
149
|
+
#
|
150
|
+
def branch_for_base
|
151
|
+
pr_json["base"]["ref"]
|
152
|
+
end
|
153
|
+
|
154
|
+
# @!group PR Commit Metadata
|
155
|
+
# The branch to which the PR is going to be merged from.
|
156
|
+
# @return [String]
|
157
|
+
#
|
158
|
+
def branch_for_head
|
159
|
+
pr_json["head"]["ref"]
|
160
|
+
end
|
161
|
+
|
162
|
+
# @!group PR Commit Metadata
|
163
|
+
# The base commit to which the PR is going to be merged as a parent.
|
164
|
+
# @return [String]
|
165
|
+
#
|
166
|
+
def base_commit
|
167
|
+
pr_json["base"]["sha"]
|
168
|
+
end
|
169
|
+
|
170
|
+
# @!group PR Commit Metadata
|
171
|
+
# The head commit to which the PR is requesting to be merged from.
|
172
|
+
# @return [String]
|
173
|
+
#
|
174
|
+
def head_commit
|
175
|
+
pr_json["head"]["sha"]
|
176
|
+
end
|
177
|
+
|
178
|
+
# @!group GitHub Misc
|
179
|
+
# The hash that represents the PR's JSON. For an example of what this looks like
|
180
|
+
# see the [Danger Fixture'd one](https://raw.githubusercontent.com/danger/danger/master/spec/fixtures/github_api/pr_response.json).
|
181
|
+
# @return [Hash]
|
182
|
+
#
|
183
|
+
def pr_json
|
184
|
+
@github.pr_json
|
185
|
+
end
|
186
|
+
|
187
|
+
# @!group GitHub Misc
|
188
|
+
# Provides access to the GitHub API client used inside Danger. Making
|
189
|
+
# it easy to use the GitHub API inside a Dangerfile.
|
190
|
+
# @return [Octokit::Client]
|
191
|
+
def api
|
192
|
+
@github.client
|
193
|
+
end
|
194
|
+
|
195
|
+
# @!group PR Content
|
196
|
+
# The unified diff produced by Github for this PR
|
197
|
+
# see [Unified diff](https://en.wikipedia.org/wiki/Diff_utility#Unified_format)
|
198
|
+
# @return [String]
|
199
|
+
def pr_diff
|
200
|
+
@github.pr_diff
|
201
|
+
end
|
202
|
+
|
203
|
+
# @!group GitHub Misc
|
204
|
+
# Returns a list of HTML anchors for a file, or files in the head repository. An example would be:
|
205
|
+
# `<a href='https://github.com/artsy/eigen/blob/561827e46167077b5e53515b4b7349b8ae04610b/file.txt'>file.txt</a>`. It returns a string of multiple anchors if passed an array.
|
206
|
+
# @param [String or Array<String>] paths
|
207
|
+
# A list of strings to convert to github anchors
|
208
|
+
# @param [Bool] full_path
|
209
|
+
# Shows the full path as the link's text, defaults to `true`.
|
210
|
+
#
|
211
|
+
# @return [String]
|
212
|
+
def html_link(paths, full_path: true)
|
213
|
+
paths = [paths] unless paths.kind_of?(Array)
|
214
|
+
commit = head_commit
|
215
|
+
repo = pr_json["head"]["repo"]["html_url"]
|
216
|
+
|
217
|
+
paths = paths.map do |path|
|
218
|
+
url_path = path.start_with?("/") ? path : "/#{path}"
|
219
|
+
text = full_path ? path : File.basename(path)
|
220
|
+
create_link("#{repo}/blob/#{commit}#{url_path}", text)
|
221
|
+
end
|
222
|
+
|
223
|
+
return paths.first if paths.count < 2
|
224
|
+
paths.first(paths.count - 1).join(", ") + " & " + paths.last
|
225
|
+
end
|
226
|
+
|
227
|
+
# @!group GitHub Misc
|
228
|
+
# Use to ignore inline messages which lay outside a diff's range, thereby not posting them in the main comment.
|
229
|
+
# You can set hash to change behavior per each kinds. (ex. `{warning: true, error: false}`)
|
230
|
+
# @param [Bool] or [Hash<Symbol, Bool>] dismiss
|
231
|
+
# Ignore out of range inline messages, defaults to `true`
|
232
|
+
#
|
233
|
+
# @return [void]
|
234
|
+
def dismiss_out_of_range_messages(dismiss = true)
|
235
|
+
if dismiss.kind_of?(Hash)
|
236
|
+
@github.dismiss_out_of_range_messages = dismiss
|
237
|
+
elsif dismiss.kind_of?(TrueClass)
|
238
|
+
@github.dismiss_out_of_range_messages = true
|
239
|
+
elsif dismiss.kind_of?(FalseClass)
|
240
|
+
@github.dismiss_out_of_range_messages = false
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
%i(title body author labels json).each do |suffix|
|
245
|
+
alias_method "mr_#{suffix}".to_sym, "pr_#{suffix}".to_sym
|
246
|
+
end
|
247
|
+
|
248
|
+
private
|
249
|
+
|
250
|
+
def create_link(href, text)
|
251
|
+
"<a href='#{href}'>#{text}</a>"
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end
|
@@ -0,0 +1,240 @@
|
|
1
|
+
require "danger/plugin_support/plugin"
|
2
|
+
|
3
|
+
module Danger
|
4
|
+
# Handles interacting with GitLab inside a Dangerfile. Provides a few functions which wrap `mr_json` and also
|
5
|
+
# through a few standard functions to simplify your code.
|
6
|
+
#
|
7
|
+
# @example Warn when an MR is classed as work in progress.
|
8
|
+
#
|
9
|
+
# warn "MR is classed as Work in Progress" if gitlab.mr_title.include? "[WIP]"
|
10
|
+
#
|
11
|
+
# @example Declare a MR to be simple to avoid specific Danger rules.
|
12
|
+
#
|
13
|
+
# declared_trivial = (gitlab.mr_title + gitlab.mr_body).include?("#trivial")
|
14
|
+
#
|
15
|
+
# @example Ensure that labels have been applied to the MR.
|
16
|
+
#
|
17
|
+
# failure "Please add labels to this MR" if gitlab.mr_labels.empty?
|
18
|
+
#
|
19
|
+
# @example Ensure that all MRs have an assignee.
|
20
|
+
#
|
21
|
+
# warn "This MR does not have any assignees yet." unless gitlab.mr_json["assignee"]
|
22
|
+
#
|
23
|
+
# @example Ensure there is a summary for a MR.
|
24
|
+
#
|
25
|
+
# failure "Please provide a summary in the Merge Request description" if gitlab.mr_body.length < 5
|
26
|
+
#
|
27
|
+
# @example Only accept MRs to the develop branch.
|
28
|
+
#
|
29
|
+
# failure "Please re-submit this MR to develop, we may have already fixed your issue." if gitlab.branch_for_merge != "develop"
|
30
|
+
#
|
31
|
+
# @example Note when MRs don't reference a milestone, make the warning stick around on subsequent runs
|
32
|
+
#
|
33
|
+
# has_milestone = gitlab.mr_json["milestone"] != nil
|
34
|
+
# warn("This MR does not refer to an existing milestone", sticky: true) unless has_milestone
|
35
|
+
#
|
36
|
+
# @example Note when a MR cannot be manually merged
|
37
|
+
#
|
38
|
+
# can_merge = gitlab.mr_json["mergeable"]
|
39
|
+
# warn("This MR cannot be merged yet.") unless can_merge
|
40
|
+
#
|
41
|
+
# @example Highlight when a celebrity makes a merge request.
|
42
|
+
#
|
43
|
+
# message "Welcome, Danger." if gitlab.mr_author == "dangermcshane"
|
44
|
+
#
|
45
|
+
# @example Send a message with links to a collection of specific files.
|
46
|
+
#
|
47
|
+
# if git.modified_files.include? "config/*.js"
|
48
|
+
# config_files = git.modified_files.select { |path| path.include? "config/" }
|
49
|
+
# message "This MR changes #{ gitlab.html_link(config_files) }"
|
50
|
+
# end
|
51
|
+
#
|
52
|
+
# @example Highlight with a clickable link if a Package.json is changed.
|
53
|
+
#
|
54
|
+
# warn "#{gitlab.html_link("Package.json")} was edited." if git.modified_files.include? "Package.json"
|
55
|
+
#
|
56
|
+
# @example Select a random group member as assignee if no assignee is selected
|
57
|
+
#
|
58
|
+
# if gitlab.mr_json["assignee"].nil?
|
59
|
+
# reviewer = gitlab.api.group_members(gitlab.api.merge_request_approvals(project_id, mr_id).to_hash["approver_groups"].first["group"]["id"]).sample
|
60
|
+
# if gitlab.api.group_members(gitlab.api.merge_request_approvals(project_id, mr_id).to_hash["approver_groups"].first["group"]["id"]).length > 1
|
61
|
+
# while reviewer.to_hash["id"] == gitlab.mr_json["author"]["id"] do
|
62
|
+
# reviewer = gitlab.api.group_members(gitlab.api.merge_request_approvals(project_id, mr_id).to_hash["approver_groups"].first["group"]["id"]).sample
|
63
|
+
# end
|
64
|
+
# end
|
65
|
+
# message "Reviewer roulete rolled for: #{reviewer.to_hash['name']} (@#{reviewer.to_hash['username']})"
|
66
|
+
# gitlab.api.update_merge_request(project_id, mr_id, { assignee_id: reviewer.to_hash["id"] })
|
67
|
+
# end
|
68
|
+
#
|
69
|
+
#
|
70
|
+
# @see danger/danger
|
71
|
+
# @tags core, gitlab
|
72
|
+
#
|
73
|
+
class DangerfileGitLabPlugin < Plugin
|
74
|
+
# So that this init can fail.
|
75
|
+
def self.new(dangerfile)
|
76
|
+
return nil if dangerfile.env.request_source.class != Danger::RequestSources::GitLab
|
77
|
+
super
|
78
|
+
end
|
79
|
+
|
80
|
+
# The instance name used in the Dangerfile
|
81
|
+
# @return [String]
|
82
|
+
#
|
83
|
+
def self.instance_name
|
84
|
+
"gitlab"
|
85
|
+
end
|
86
|
+
|
87
|
+
def initialize(dangerfile)
|
88
|
+
super(dangerfile)
|
89
|
+
|
90
|
+
@gitlab = dangerfile.env.request_source
|
91
|
+
end
|
92
|
+
|
93
|
+
# @!group MR Metadata
|
94
|
+
# The title of the Merge Request
|
95
|
+
# @return [String]
|
96
|
+
#
|
97
|
+
def mr_title
|
98
|
+
@gitlab.mr_json.title.to_s
|
99
|
+
end
|
100
|
+
|
101
|
+
# @!group MR Metadata
|
102
|
+
# The body text of the Merge Request
|
103
|
+
# @return [String]
|
104
|
+
#
|
105
|
+
def mr_body
|
106
|
+
@gitlab.mr_json.description.to_s
|
107
|
+
end
|
108
|
+
|
109
|
+
# @!group MR Metadata
|
110
|
+
# The username of the author of the Merge Request
|
111
|
+
# @return [String]
|
112
|
+
#
|
113
|
+
def mr_author
|
114
|
+
@gitlab.mr_json.author.username.to_s
|
115
|
+
end
|
116
|
+
|
117
|
+
# @!group MR Metadata
|
118
|
+
# The labels assigned to the Merge Request
|
119
|
+
# @return [String]
|
120
|
+
#
|
121
|
+
def mr_labels
|
122
|
+
@gitlab.mr_json.labels
|
123
|
+
end
|
124
|
+
|
125
|
+
# @!group MR Content
|
126
|
+
# The unified diff produced by GitLab for this MR
|
127
|
+
# see [Unified diff](https://en.wikipedia.org/wiki/Diff_utility#Unified_format)
|
128
|
+
# @return [String]
|
129
|
+
#
|
130
|
+
def mr_diff
|
131
|
+
@gitlab.mr_diff
|
132
|
+
end
|
133
|
+
|
134
|
+
# @!group MR Commit Metadata
|
135
|
+
# The branch to which the MR is going to be merged into
|
136
|
+
# @deprecated Please use {#branch_for_base} instead
|
137
|
+
# @return [String]
|
138
|
+
#
|
139
|
+
def branch_for_merge
|
140
|
+
branch_for_base
|
141
|
+
end
|
142
|
+
|
143
|
+
# @!group MR Commit Metadata
|
144
|
+
# The branch to which the MR is going to be merged into.
|
145
|
+
# @return [String]
|
146
|
+
#
|
147
|
+
def branch_for_base
|
148
|
+
@gitlab.mr_json.target_branch
|
149
|
+
end
|
150
|
+
|
151
|
+
# @!group MR Commit Metadata
|
152
|
+
# The branch to which the MR is going to be merged from.
|
153
|
+
# @return [String]
|
154
|
+
#
|
155
|
+
def branch_for_head
|
156
|
+
@gitlab.mr_json.source_branch
|
157
|
+
end
|
158
|
+
|
159
|
+
# @!group MR Commit Metadata
|
160
|
+
# The base commit to which the MR is going to be merged as a parent
|
161
|
+
# @return [String]
|
162
|
+
#
|
163
|
+
def base_commit
|
164
|
+
@gitlab.mr_json.diff_refs.base_sha
|
165
|
+
end
|
166
|
+
|
167
|
+
# @!group MR Commit Metadata
|
168
|
+
# The head commit to which the MR is requesting to be merged from
|
169
|
+
# @return [String]
|
170
|
+
#
|
171
|
+
def head_commit
|
172
|
+
@gitlab.mr_json.diff_refs.head_sha
|
173
|
+
end
|
174
|
+
|
175
|
+
# @!group GitLab Misc
|
176
|
+
# The hash that represents the MR's JSON. See documentation for the
|
177
|
+
# structure [here](http://docs.gitlab.com/ce/api/merge_requests.html#get-single-mr)
|
178
|
+
# @return [Hash]
|
179
|
+
#
|
180
|
+
def mr_json
|
181
|
+
@gitlab.mr_json.to_hash
|
182
|
+
end
|
183
|
+
|
184
|
+
# @!group GitLab Misc
|
185
|
+
# Provides access to the GitLab API client used inside Danger. Making
|
186
|
+
# it easy to use the GitLab API inside a Dangerfile. See the gitlab
|
187
|
+
# gem's [documentation](http://www.rubydoc.info/gems/gitlab/Gitlab/Client)
|
188
|
+
# for accessible methods.
|
189
|
+
# @return [GitLab::Client]
|
190
|
+
#
|
191
|
+
def api
|
192
|
+
@gitlab.client
|
193
|
+
end
|
194
|
+
|
195
|
+
# @!group GitLab Misc
|
196
|
+
# Returns the web_url of the source project.
|
197
|
+
# @return [String]
|
198
|
+
#
|
199
|
+
def repository_web_url
|
200
|
+
@repository_web_url ||= begin
|
201
|
+
project = api.project(mr_json["source_project_id"])
|
202
|
+
project.web_url
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
# @!group GitLab Misc
|
207
|
+
# Returns a list of HTML anchors for a file, or files in the head repository. An example would be:
|
208
|
+
# `<a href='https://gitlab.com/artsy/eigen/blob/561827e46167077b5e53515b4b7349b8ae04610b/file.txt'>file.txt</a>`. It returns a string of multiple anchors if passed an array.
|
209
|
+
# @param [String or Array<String>] paths
|
210
|
+
# A list of strings to convert to gitlab anchors
|
211
|
+
# @param [Bool] full_path
|
212
|
+
# Shows the full path as the link's text, defaults to `true`.
|
213
|
+
#
|
214
|
+
# @return [String]
|
215
|
+
#
|
216
|
+
def html_link(paths, full_path: true)
|
217
|
+
paths = [paths] unless paths.kind_of?(Array)
|
218
|
+
commit = head_commit
|
219
|
+
|
220
|
+
paths = paths.map do |path|
|
221
|
+
url_path = path.start_with?("/") ? path : "/#{path}"
|
222
|
+
text = full_path ? path : File.basename(path)
|
223
|
+
create_link("#{repository_web_url}/blob/#{commit}#{url_path}", text)
|
224
|
+
end
|
225
|
+
|
226
|
+
return paths.first if paths.count < 2
|
227
|
+
paths.first(paths.count - 1).join(", ") + " & " + paths.last
|
228
|
+
end
|
229
|
+
|
230
|
+
%i(title body author labels json diff).each do |suffix|
|
231
|
+
alias_method "pr_#{suffix}".to_sym, "mr_#{suffix}".to_sym
|
232
|
+
end
|
233
|
+
|
234
|
+
private
|
235
|
+
|
236
|
+
def create_link(href, text)
|
237
|
+
"<a href='#{href}'>#{text}</a>"
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|