gitlab-dangerfiles 3.13.0 → 4.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 +4 -4
- data/.gitignore +0 -1
- data/.gitlab/CODEOWNERS +1 -1
- data/.gitlab/merge_request_templates/Release.md +1 -1
- data/.gitlab-ci.yml +21 -42
- data/.rubocop.yml +6 -16
- data/.rubocop_todo.yml +5 -8
- data/Gemfile +0 -16
- data/Gemfile.lock +234 -0
- data/README.md +96 -9
- data/gitlab-dangerfiles.gemspec +13 -5
- data/lefthook.yml +0 -5
- data/lib/danger/plugins/changelog.rb +9 -7
- data/lib/danger/plugins/duo_code.rb +12 -0
- data/lib/danger/plugins/internal/helper.rb +34 -10
- data/lib/danger/plugins/roulette.rb +95 -256
- data/lib/danger/rules/commit_messages/Dangerfile +2 -7
- data/lib/danger/rules/duo_code_review/Dangerfile +10 -0
- data/lib/danger/rules/simple_roulette/Dangerfile +17 -10
- data/lib/danger/rules/type_label/Dangerfile +0 -8
- data/lib/danger/rules/z_add_labels/Dangerfile +3 -3
- data/lib/gitlab/dangerfiles/approval.rb +22 -0
- data/lib/gitlab/dangerfiles/base_linter.rb +1 -1
- data/lib/gitlab/dangerfiles/capability.rb +82 -0
- data/lib/gitlab/dangerfiles/commit_linter.rb +2 -2
- data/lib/gitlab/dangerfiles/config.rb +29 -3
- data/lib/gitlab/dangerfiles/emoji_checker.rb +1 -1
- data/lib/gitlab/dangerfiles/spec_helper.rb +231 -1
- data/lib/gitlab/dangerfiles/spin.rb +15 -0
- data/lib/gitlab/dangerfiles/spinner.rb +191 -0
- data/lib/gitlab/dangerfiles/teammate.rb +94 -20
- data/lib/gitlab/dangerfiles/type_label_guesser.rb +2 -2
- data/lib/gitlab/dangerfiles/version.rb +1 -1
- data/lib/gitlab/dangerfiles.rb +0 -1
- metadata +100 -25
- data/lib/danger/rules/subtype_label/Dangerfile +0 -14
- data/lib/gitlab/dangerfiles/category.rb +0 -111
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "spin"
|
|
4
|
+
require_relative "teammate"
|
|
5
|
+
require_relative "weightage/maintainers"
|
|
6
|
+
require_relative "weightage/reviewers"
|
|
7
|
+
|
|
8
|
+
module Gitlab
|
|
9
|
+
module Dangerfiles
|
|
10
|
+
class Spinner
|
|
11
|
+
attr_reader :project, :author, :team_author, :labels, :categories
|
|
12
|
+
|
|
13
|
+
def initialize(
|
|
14
|
+
project:, author:, team_author: nil, labels: [], categories: [],
|
|
15
|
+
random: Random.new, ux_fallback_wider_community_reviewer: nil)
|
|
16
|
+
@project = project
|
|
17
|
+
@author = author
|
|
18
|
+
@team_author = team_author
|
|
19
|
+
@labels = labels
|
|
20
|
+
@categories = categories.reject do |category|
|
|
21
|
+
import_and_integrate_reject_category?(project, category, labels)
|
|
22
|
+
end
|
|
23
|
+
@random = random
|
|
24
|
+
@ux_fallback_wider_community_reviewer = ux_fallback_wider_community_reviewer
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
28
|
+
def spin
|
|
29
|
+
spins = categories.sort_by(&:to_s).map do |category|
|
|
30
|
+
spin_for_category(category)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
backend_spin = spins.find { |spin| spin.category == :backend }
|
|
34
|
+
frontend_spin = spins.find { |spin| spin.category == :frontend }
|
|
35
|
+
|
|
36
|
+
spins.each do |spin|
|
|
37
|
+
case spin.category
|
|
38
|
+
when :qa
|
|
39
|
+
spin.optional_role = :maintainer if
|
|
40
|
+
categories.size > 1 && author_no_qa_capability?
|
|
41
|
+
when :test
|
|
42
|
+
spin.optional_role = :maintainer
|
|
43
|
+
|
|
44
|
+
if spin.no_reviewer?
|
|
45
|
+
# Fetch an already picked backend reviewer, or pick one otherwise
|
|
46
|
+
spin.reviewer = backend_spin&.reviewer || spin_for_category(:backend).reviewer
|
|
47
|
+
end
|
|
48
|
+
when :tooling
|
|
49
|
+
if spin.no_maintainer?
|
|
50
|
+
# Fetch an already picked backend maintainer, or pick one otherwise
|
|
51
|
+
spin.maintainer = backend_spin&.maintainer || spin_for_category(:backend).maintainer
|
|
52
|
+
end
|
|
53
|
+
when :ci_template # rubocop:disable Lint/DuplicateBranch -- bug?
|
|
54
|
+
if spin.no_maintainer?
|
|
55
|
+
# Fetch an already picked backend maintainer, or pick one otherwise
|
|
56
|
+
spin.maintainer = backend_spin&.maintainer || spin_for_category(:backend).maintainer
|
|
57
|
+
end
|
|
58
|
+
when :analytics_instrumentation
|
|
59
|
+
spin.optional_role = :maintainer
|
|
60
|
+
|
|
61
|
+
if spin.no_maintainer?
|
|
62
|
+
# Fetch an already picked maintainer, or pick one otherwise
|
|
63
|
+
spin.maintainer = backend_spin&.maintainer || frontend_spin&.maintainer || spin_for_category(:backend).maintainer
|
|
64
|
+
end
|
|
65
|
+
when :import_integrate_be, :import_integrate_fe
|
|
66
|
+
spin.optional_role = :maintainer
|
|
67
|
+
when :ux
|
|
68
|
+
spin.optional_role = :maintainer
|
|
69
|
+
|
|
70
|
+
# We want at least a UX reviewer who can review any wider community
|
|
71
|
+
# contribution even without a team designer. We assign this to Pedro.
|
|
72
|
+
spin.reviewer = ux_fallback_wider_community_reviewer if
|
|
73
|
+
labels.include?("Community contribution") &&
|
|
74
|
+
spin.no_reviewer? &&
|
|
75
|
+
spin.no_maintainer?
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
spins
|
|
80
|
+
end
|
|
81
|
+
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
82
|
+
|
|
83
|
+
# Spin a reviewer for a particular approval rule
|
|
84
|
+
#
|
|
85
|
+
# @param [Hash] rule of approval
|
|
86
|
+
#
|
|
87
|
+
# @return [Gitlab::Dangerfiles::Teammate]
|
|
88
|
+
def spin_for_approver(rule)
|
|
89
|
+
approvers = rule["eligible_approvers"].filter_map do |approver|
|
|
90
|
+
Gitlab::Dangerfiles::Teammate.find_member(
|
|
91
|
+
approver["username"], project: project)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
spin_for_person(approvers) || spin_for_approver_fallback(rule)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
private
|
|
98
|
+
|
|
99
|
+
attr_reader :random, :ux_fallback_wider_community_reviewer
|
|
100
|
+
|
|
101
|
+
# Reject Import and Integrate categories if the MR author has reviewing abilities for the category.
|
|
102
|
+
#
|
|
103
|
+
# @param [String] category name
|
|
104
|
+
# @return [Boolean]
|
|
105
|
+
def import_and_integrate_reject_category?(project, category, labels)
|
|
106
|
+
[:import_integrate_be, :import_integrate_fe].include?(category) && team_author &&
|
|
107
|
+
(team_author.reviewer?(project, category, labels) || team_author.maintainer?(project, category, labels))
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# MR includes QA changes, but also other changes, and author isn't an SET
|
|
111
|
+
def author_no_qa_capability?
|
|
112
|
+
!(team_author && team_author.capabilities(project).any? { |capability| capability.end_with?("qa") })
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def spin_for_category(category)
|
|
116
|
+
reviewers, traintainers, maintainers =
|
|
117
|
+
%i[reviewer traintainer maintainer].map do |role|
|
|
118
|
+
spin_role_for_category(role, category)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
weighted_reviewers = Weightage::Reviewers.new(reviewers, traintainers).execute
|
|
122
|
+
weighted_maintainers = Weightage::Maintainers.new(maintainers).execute
|
|
123
|
+
|
|
124
|
+
reviewer = spin_for_person(weighted_reviewers)
|
|
125
|
+
maintainer = spin_for_person(weighted_maintainers)
|
|
126
|
+
|
|
127
|
+
# allow projects with small number of reviewers to take from maintainers if possible
|
|
128
|
+
if reviewer.nil? && weighted_maintainers.uniq.size > 1
|
|
129
|
+
weighted_maintainers.delete(maintainer)
|
|
130
|
+
reviewer = spin_for_person(weighted_maintainers)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
Spin.new(category, reviewer, maintainer, false)
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def spin_role_for_category(role, category)
|
|
137
|
+
team.select do |member|
|
|
138
|
+
member.public_send(:"#{role}?", project, category, labels)
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# Known issue: If someone is rejected due to OOO, and then becomes not OOO, the
|
|
143
|
+
# selection will change on next spin.
|
|
144
|
+
#
|
|
145
|
+
# @param [Array<Gitlab::Dangerfiles::Teammate>] people
|
|
146
|
+
#
|
|
147
|
+
# @return [Gitlab::Dangerfiles::Teammate]
|
|
148
|
+
def spin_for_person(people)
|
|
149
|
+
shuffled_people = people.shuffle(random: random)
|
|
150
|
+
|
|
151
|
+
shuffled_people.find { |person| valid_person?(person) }
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
# @param [Gitlab::Dangerfiles::Teammate] person
|
|
155
|
+
# @return [Boolean]
|
|
156
|
+
def valid_person?(person)
|
|
157
|
+
person.username != author && person.available
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
# It can be possible that we don't have a valid reviewer for approval.
|
|
161
|
+
# In this case, we sample again without considering:
|
|
162
|
+
#
|
|
163
|
+
# * If they're available
|
|
164
|
+
# * If they're an actual reviewer from roulette data
|
|
165
|
+
#
|
|
166
|
+
# We do this because we strictly require an approval from the approvers.
|
|
167
|
+
#
|
|
168
|
+
# @param [Hash] rule of approval
|
|
169
|
+
#
|
|
170
|
+
# @return [Gitlab::Dangerfiles::Teammate]
|
|
171
|
+
def spin_for_approver_fallback(rule)
|
|
172
|
+
fallback_approvers = rule["eligible_approvers"].map do |approver|
|
|
173
|
+
Teammate.find_member(approver["username"]) || Teammate.new(approver)
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
# Intentionally not using `spin_for_person` to skip `valid_person?`.
|
|
177
|
+
# This should strictly return someone so we don't filter anything,
|
|
178
|
+
# and it's a fallback mechanism which should not happen often that
|
|
179
|
+
# deserves a complex algorithm.
|
|
180
|
+
fallback_approvers.sample(random: random)
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
# @return [Array<Gitlab::Dangerfiles::Teammate>]
|
|
184
|
+
def team
|
|
185
|
+
@team ||= Teammate.company_members.select do |member|
|
|
186
|
+
member.in_project?(project)
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
end
|
|
@@ -1,12 +1,84 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
require "net/http"
|
|
4
|
+
require "json"
|
|
5
|
+
|
|
6
|
+
require_relative "capability"
|
|
4
7
|
|
|
5
8
|
module Gitlab
|
|
6
9
|
module Dangerfiles
|
|
7
10
|
class Teammate
|
|
11
|
+
ROULETTE_DATA_URL = "https://gitlab-org.gitlab.io/gitlab-roulette/roulette.json"
|
|
12
|
+
|
|
13
|
+
def self.find_member(username, project: nil)
|
|
14
|
+
company_members.find do |member|
|
|
15
|
+
member.username == username &&
|
|
16
|
+
(project.nil? || member.in_project?(project))
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def self.has_member_for_the_group?(category, labels:, **arguments)
|
|
21
|
+
capabilities = %i[reviewer maintainer].map do |kind|
|
|
22
|
+
# Use new to use the base class for original has_capability? method
|
|
23
|
+
Capability.new(category: category, kind: kind, labels: labels, **arguments)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
company_members.any? do |teammate|
|
|
27
|
+
capabilities.any? do |capability|
|
|
28
|
+
capability.has_capability?(teammate) &&
|
|
29
|
+
teammate.member_of_the_group?(labels)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Looks up the current list of GitLab team members and parses it into a
|
|
35
|
+
# useful form.
|
|
36
|
+
#
|
|
37
|
+
# @return [Array<Gitlab::Dangerfiles::Teammate>]
|
|
38
|
+
def self.company_members
|
|
39
|
+
@company_members ||= fetch_company_members
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def self.fetch_company_members
|
|
43
|
+
data = http_get_json(ROULETTE_DATA_URL) || []
|
|
44
|
+
data.map { |hash| Teammate.new(hash) }
|
|
45
|
+
rescue JSON::ParserError
|
|
46
|
+
warnings << "Failed to parse JSON response from #{ROULETTE_DATA_URL}"
|
|
47
|
+
[]
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Fetches the given +url+ and parse its response as JSON.
|
|
51
|
+
#
|
|
52
|
+
# @param [String] url
|
|
53
|
+
#
|
|
54
|
+
# @return [Hash, Array, NilClass]
|
|
55
|
+
def self.http_get_json(url)
|
|
56
|
+
rsp = Net::HTTP.get_response(URI.parse(url))
|
|
57
|
+
|
|
58
|
+
if rsp.is_a?(Net::HTTPRedirection)
|
|
59
|
+
uri = URI.parse(rsp.header["location"])
|
|
60
|
+
|
|
61
|
+
uri.query = nil if uri
|
|
62
|
+
|
|
63
|
+
warnings << "Redirection detected: #{uri}."
|
|
64
|
+
return nil
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
unless rsp.is_a?(Net::HTTPOK)
|
|
68
|
+
message = rsp.message[0, 30]
|
|
69
|
+
warnings << "HTTPError: Failed to read #{url}: #{rsp.code} #{message}."
|
|
70
|
+
return nil
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
JSON.parse(rsp.body)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def self.warnings
|
|
77
|
+
@warnings ||= []
|
|
78
|
+
end
|
|
79
|
+
|
|
8
80
|
attr_reader :options, :username, :name, :role, :specialty, :projects, :available, :hungry, :reduced_capacity, :tz_offset_hours,
|
|
9
|
-
|
|
81
|
+
:only_maintainer_reviews
|
|
10
82
|
|
|
11
83
|
# The options data are produced by https://gitlab.com/gitlab-org/gitlab-roulette/-/blob/main/lib/team_member.rb
|
|
12
84
|
def initialize(options = {})
|
|
@@ -14,7 +86,7 @@ module Gitlab
|
|
|
14
86
|
@username = options["username"]
|
|
15
87
|
@name = options["name"]
|
|
16
88
|
@markdown_name = options["markdown_name"] ||
|
|
17
|
-
|
|
89
|
+
default_markdown_name(options["username"])
|
|
18
90
|
@role = options["role"]
|
|
19
91
|
@specialty = options["specialty"]
|
|
20
92
|
@projects = process_projects(options["projects"])
|
|
@@ -25,6 +97,20 @@ module Gitlab
|
|
|
25
97
|
@only_maintainer_reviews = options["only_maintainer_reviews"]
|
|
26
98
|
end
|
|
27
99
|
|
|
100
|
+
def member_of_the_group?(labels)
|
|
101
|
+
# Specialty can be:
|
|
102
|
+
# Source Code
|
|
103
|
+
# [Growth: Activation, Growth: Expansion]
|
|
104
|
+
# Runner
|
|
105
|
+
group_labels = Array(specialty).map do |field|
|
|
106
|
+
group = field.strip.sub(/^.+: ?/, "").downcase
|
|
107
|
+
|
|
108
|
+
"group::#{group}"
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
(group_labels & labels).any?
|
|
112
|
+
end
|
|
113
|
+
|
|
28
114
|
def to_h
|
|
29
115
|
options
|
|
30
116
|
end
|
|
@@ -55,18 +141,6 @@ module Gitlab
|
|
|
55
141
|
has_capability?(project, category, :maintainer, labels)
|
|
56
142
|
end
|
|
57
143
|
|
|
58
|
-
def import_integrate_be?(project, category, labels)
|
|
59
|
-
return false unless category == :import_integrate_be
|
|
60
|
-
|
|
61
|
-
has_capability?(project, category, :reviewer, labels)
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
def import_integrate_fe?(project, category, labels)
|
|
65
|
-
return false unless category == :import_integrate_fe
|
|
66
|
-
|
|
67
|
-
has_capability?(project, category, :reviewer, labels)
|
|
68
|
-
end
|
|
69
|
-
|
|
70
144
|
def markdown_name(author: nil)
|
|
71
145
|
"#{@markdown_name}#{utc_offset_text(author)}"
|
|
72
146
|
end
|
|
@@ -89,8 +163,8 @@ module Gitlab
|
|
|
89
163
|
|
|
90
164
|
private
|
|
91
165
|
|
|
92
|
-
def default_markdown_name(username
|
|
93
|
-
"
|
|
166
|
+
def default_markdown_name(username)
|
|
167
|
+
"`@#{username}` [](https://gitlab.com/#{username})"
|
|
94
168
|
end
|
|
95
169
|
|
|
96
170
|
def process_projects(projects)
|
|
@@ -119,16 +193,16 @@ module Gitlab
|
|
|
119
193
|
|
|
120
194
|
def offset_diff_compared_to_author(author)
|
|
121
195
|
diff = floored_offset_hours - author.floored_offset_hours
|
|
122
|
-
return "same timezone as
|
|
196
|
+
return "same timezone as author" if diff == 0
|
|
123
197
|
|
|
124
198
|
ahead_or_behind = diff < 0 ? "behind" : "ahead of"
|
|
125
199
|
pluralized_hours = pluralize(diff.abs, "hour", "hours")
|
|
126
200
|
|
|
127
|
-
"#{pluralized_hours} #{ahead_or_behind}
|
|
201
|
+
"#{pluralized_hours} #{ahead_or_behind} author"
|
|
128
202
|
end
|
|
129
203
|
|
|
130
204
|
def has_capability?(project, category, kind, labels)
|
|
131
|
-
|
|
205
|
+
Capability.for(category, project: project, kind: kind, labels: labels).has_capability?(self)
|
|
132
206
|
end
|
|
133
207
|
|
|
134
208
|
def pluralize(count, singular, plural)
|
|
@@ -8,8 +8,8 @@ module Gitlab
|
|
|
8
8
|
security: %w[type::bug bug::vulnerability],
|
|
9
9
|
performance: %w[type::bug bug::performance],
|
|
10
10
|
added: %w[type::feature feature::addition],
|
|
11
|
-
deprecated: %w[type::
|
|
12
|
-
removed: %w[type::
|
|
11
|
+
deprecated: %w[type::maintenance maintenance::removal],
|
|
12
|
+
removed: %w[type::maintenance maintenance::removal]
|
|
13
13
|
}.freeze
|
|
14
14
|
|
|
15
15
|
def labels_from_changelog_categories(categories)
|
data/lib/gitlab/dangerfiles.rb
CHANGED
metadata
CHANGED
|
@@ -1,29 +1,29 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: gitlab-dangerfiles
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 4.10.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- GitLab
|
|
8
|
-
autorequire:
|
|
8
|
+
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2025-07-25 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rake
|
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
|
16
16
|
requirements:
|
|
17
|
-
- - "
|
|
17
|
+
- - "~>"
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: '0'
|
|
19
|
+
version: '13.0'
|
|
20
20
|
type: :runtime
|
|
21
21
|
prerelease: false
|
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
23
|
requirements:
|
|
24
|
-
- - "
|
|
24
|
+
- - "~>"
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
|
-
version: '0'
|
|
26
|
+
version: '13.0'
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
28
28
|
name: danger-gitlab
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -44,28 +44,70 @@ dependencies:
|
|
|
44
44
|
requirements:
|
|
45
45
|
- - ">="
|
|
46
46
|
- !ruby/object:Gem::Version
|
|
47
|
-
version:
|
|
47
|
+
version: 9.3.0
|
|
48
48
|
type: :runtime
|
|
49
49
|
prerelease: false
|
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
|
51
51
|
requirements:
|
|
52
52
|
- - ">="
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
|
-
version:
|
|
54
|
+
version: 9.3.0
|
|
55
55
|
- !ruby/object:Gem::Dependency
|
|
56
|
-
name:
|
|
56
|
+
name: climate_control
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - ">="
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '0'
|
|
62
|
+
type: :development
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - ">="
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '0'
|
|
69
|
+
- !ruby/object:Gem::Dependency
|
|
70
|
+
name: gitlab-styles
|
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
|
58
72
|
requirements:
|
|
59
73
|
- - "~>"
|
|
60
74
|
- !ruby/object:Gem::Version
|
|
61
|
-
version: '
|
|
75
|
+
version: '10.0'
|
|
62
76
|
type: :development
|
|
63
77
|
prerelease: false
|
|
64
78
|
version_requirements: !ruby/object:Gem::Requirement
|
|
65
79
|
requirements:
|
|
66
80
|
- - "~>"
|
|
67
81
|
- !ruby/object:Gem::Version
|
|
68
|
-
version: '
|
|
82
|
+
version: '10.0'
|
|
83
|
+
- !ruby/object:Gem::Dependency
|
|
84
|
+
name: guard-rspec
|
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
|
86
|
+
requirements:
|
|
87
|
+
- - "~>"
|
|
88
|
+
- !ruby/object:Gem::Version
|
|
89
|
+
version: 4.7.3
|
|
90
|
+
type: :development
|
|
91
|
+
prerelease: false
|
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
93
|
+
requirements:
|
|
94
|
+
- - "~>"
|
|
95
|
+
- !ruby/object:Gem::Version
|
|
96
|
+
version: 4.7.3
|
|
97
|
+
- !ruby/object:Gem::Dependency
|
|
98
|
+
name: lefthook
|
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
|
100
|
+
requirements:
|
|
101
|
+
- - "~>"
|
|
102
|
+
- !ruby/object:Gem::Version
|
|
103
|
+
version: '1.3'
|
|
104
|
+
type: :development
|
|
105
|
+
prerelease: false
|
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
107
|
+
requirements:
|
|
108
|
+
- - "~>"
|
|
109
|
+
- !ruby/object:Gem::Version
|
|
110
|
+
version: '1.3'
|
|
69
111
|
- !ruby/object:Gem::Dependency
|
|
70
112
|
name: rspec-parameterized
|
|
71
113
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -81,21 +123,49 @@ dependencies:
|
|
|
81
123
|
- !ruby/object:Gem::Version
|
|
82
124
|
version: '0'
|
|
83
125
|
- !ruby/object:Gem::Dependency
|
|
84
|
-
name:
|
|
126
|
+
name: rspec
|
|
85
127
|
requirement: !ruby/object:Gem::Requirement
|
|
86
128
|
requirements:
|
|
87
|
-
- - "
|
|
129
|
+
- - "~>"
|
|
88
130
|
- !ruby/object:Gem::Version
|
|
89
|
-
version: '
|
|
131
|
+
version: '3.8'
|
|
90
132
|
type: :development
|
|
91
133
|
prerelease: false
|
|
92
134
|
version_requirements: !ruby/object:Gem::Requirement
|
|
93
135
|
requirements:
|
|
94
|
-
- - "
|
|
136
|
+
- - "~>"
|
|
95
137
|
- !ruby/object:Gem::Version
|
|
96
|
-
version: '
|
|
138
|
+
version: '3.8'
|
|
97
139
|
- !ruby/object:Gem::Dependency
|
|
98
|
-
name:
|
|
140
|
+
name: racc
|
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
|
142
|
+
requirements:
|
|
143
|
+
- - "~>"
|
|
144
|
+
- !ruby/object:Gem::Version
|
|
145
|
+
version: '1.8'
|
|
146
|
+
type: :development
|
|
147
|
+
prerelease: false
|
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
149
|
+
requirements:
|
|
150
|
+
- - "~>"
|
|
151
|
+
- !ruby/object:Gem::Version
|
|
152
|
+
version: '1.8'
|
|
153
|
+
- !ruby/object:Gem::Dependency
|
|
154
|
+
name: rubocop-rails
|
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
|
156
|
+
requirements:
|
|
157
|
+
- - "<"
|
|
158
|
+
- !ruby/object:Gem::Version
|
|
159
|
+
version: 2.21.2
|
|
160
|
+
type: :development
|
|
161
|
+
prerelease: false
|
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
163
|
+
requirements:
|
|
164
|
+
- - "<"
|
|
165
|
+
- !ruby/object:Gem::Version
|
|
166
|
+
version: 2.21.2
|
|
167
|
+
- !ruby/object:Gem::Dependency
|
|
168
|
+
name: timecop
|
|
99
169
|
requirement: !ruby/object:Gem::Requirement
|
|
100
170
|
requirements:
|
|
101
171
|
- - ">="
|
|
@@ -109,7 +179,7 @@ dependencies:
|
|
|
109
179
|
- !ruby/object:Gem::Version
|
|
110
180
|
version: '0'
|
|
111
181
|
- !ruby/object:Gem::Dependency
|
|
112
|
-
name:
|
|
182
|
+
name: webmock
|
|
113
183
|
requirement: !ruby/object:Gem::Requirement
|
|
114
184
|
requirements:
|
|
115
185
|
- - ">="
|
|
@@ -123,7 +193,7 @@ dependencies:
|
|
|
123
193
|
- !ruby/object:Gem::Version
|
|
124
194
|
version: '0'
|
|
125
195
|
- !ruby/object:Gem::Dependency
|
|
126
|
-
name:
|
|
196
|
+
name: yard
|
|
127
197
|
requirement: !ruby/object:Gem::Requirement
|
|
128
198
|
requirements:
|
|
129
199
|
- - ">="
|
|
@@ -157,6 +227,7 @@ files:
|
|
|
157
227
|
- CONTRIBUTING.md
|
|
158
228
|
- Dangerfile
|
|
159
229
|
- Gemfile
|
|
230
|
+
- Gemfile.lock
|
|
160
231
|
- Guardfile
|
|
161
232
|
- LICENSE.txt
|
|
162
233
|
- README.md
|
|
@@ -168,29 +239,33 @@ files:
|
|
|
168
239
|
- gitlab-dangerfiles.gemspec
|
|
169
240
|
- lefthook.yml
|
|
170
241
|
- lib/danger/plugins/changelog.rb
|
|
242
|
+
- lib/danger/plugins/duo_code.rb
|
|
171
243
|
- lib/danger/plugins/internal/helper.rb
|
|
172
244
|
- lib/danger/plugins/roulette.rb
|
|
173
245
|
- lib/danger/rules/changelog/Dangerfile
|
|
174
246
|
- lib/danger/rules/changes_size/Dangerfile
|
|
175
247
|
- lib/danger/rules/commit_messages/Dangerfile
|
|
176
248
|
- lib/danger/rules/commits_counter/Dangerfile
|
|
249
|
+
- lib/danger/rules/duo_code_review/Dangerfile
|
|
177
250
|
- lib/danger/rules/metadata/Dangerfile
|
|
178
251
|
- lib/danger/rules/simple_roulette/Dangerfile
|
|
179
|
-
- lib/danger/rules/subtype_label/Dangerfile
|
|
180
252
|
- lib/danger/rules/type_label/Dangerfile
|
|
181
253
|
- lib/danger/rules/z_add_labels/Dangerfile
|
|
182
254
|
- lib/danger/rules/z_retry_link/Dangerfile
|
|
183
255
|
- lib/gitlab-dangerfiles.rb
|
|
184
256
|
- lib/gitlab/Dangerfile
|
|
185
257
|
- lib/gitlab/dangerfiles.rb
|
|
258
|
+
- lib/gitlab/dangerfiles/approval.rb
|
|
186
259
|
- lib/gitlab/dangerfiles/base_linter.rb
|
|
187
|
-
- lib/gitlab/dangerfiles/
|
|
260
|
+
- lib/gitlab/dangerfiles/capability.rb
|
|
188
261
|
- lib/gitlab/dangerfiles/changes.rb
|
|
189
262
|
- lib/gitlab/dangerfiles/commit_linter.rb
|
|
190
263
|
- lib/gitlab/dangerfiles/config.rb
|
|
191
264
|
- lib/gitlab/dangerfiles/emoji_checker.rb
|
|
192
265
|
- lib/gitlab/dangerfiles/merge_request_linter.rb
|
|
193
266
|
- lib/gitlab/dangerfiles/spec_helper.rb
|
|
267
|
+
- lib/gitlab/dangerfiles/spin.rb
|
|
268
|
+
- lib/gitlab/dangerfiles/spinner.rb
|
|
194
269
|
- lib/gitlab/dangerfiles/task_loader.rb
|
|
195
270
|
- lib/gitlab/dangerfiles/tasks/main.rake
|
|
196
271
|
- lib/gitlab/dangerfiles/teammate.rb
|
|
@@ -208,7 +283,7 @@ metadata:
|
|
|
208
283
|
homepage_uri: https://gitlab.com/gitlab-org/ruby/gems/gitlab-dangerfiles
|
|
209
284
|
source_code_uri: https://gitlab.com/gitlab-org/ruby/gems/gitlab-dangerfiles
|
|
210
285
|
changelog_uri: https://gitlab.com/gitlab-org/ruby/gems/gitlab-dangerfiles/-/releases
|
|
211
|
-
post_install_message:
|
|
286
|
+
post_install_message:
|
|
212
287
|
rdoc_options: []
|
|
213
288
|
require_paths:
|
|
214
289
|
- lib
|
|
@@ -223,8 +298,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
223
298
|
- !ruby/object:Gem::Version
|
|
224
299
|
version: '0'
|
|
225
300
|
requirements: []
|
|
226
|
-
rubygems_version: 3.
|
|
227
|
-
signing_key:
|
|
301
|
+
rubygems_version: 3.5.22
|
|
302
|
+
signing_key:
|
|
228
303
|
specification_version: 4
|
|
229
304
|
summary: This gem provides common Dangerfile and plugins for GitLab projects.
|
|
230
305
|
test_files: []
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
SUBTYPE_LABEL_MISSING_MESSAGE = "Please add a [merge request subtype](https://about.gitlab.com/handbook/engineering/metrics/#work-type-classification) to this merge request."
|
|
4
|
-
|
|
5
|
-
types = %w(bug feature maintenance)
|
|
6
|
-
types.each do |type|
|
|
7
|
-
return if helper.has_scoped_label_with_scope?(type)
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
if ENV['DANGER_ERROR_WHEN_SUBTYPE_LABEL_IS_MISSING'] == 'true'
|
|
11
|
-
fail SUBTYPE_LABEL_MISSING_MESSAGE
|
|
12
|
-
else
|
|
13
|
-
warn SUBTYPE_LABEL_MISSING_MESSAGE
|
|
14
|
-
end
|