payping-gitlab-triage 0.1.1
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/.codeclimate.yml +19 -0
- data/.gitignore +15 -0
- data/.gitlab/CODEOWNERS +2 -0
- data/.gitlab/changelog_config.yml +13 -0
- data/.gitlab/issue_templates/Default.md +13 -0
- data/.gitlab/merge_request_templates/Default.md +11 -0
- data/.gitlab/merge_request_templates/Release.md +13 -0
- data/.gitlab-ci.yml +146 -0
- data/.rubocop.yml +21 -0
- data/.rubocop_todo.yml +145 -0
- data/.ruby-version +1 -0
- data/.tool-versions +1 -0
- data/.yardopts +4 -0
- data/CONTRIBUTING.md +31 -0
- data/Dangerfile +5 -0
- data/Gemfile +15 -0
- data/Guardfile +70 -0
- data/LICENSE.md +25 -0
- data/README.md +1480 -0
- data/Rakefile +6 -0
- data/bin/gitlab-triage +19 -0
- data/gitlab-triage.gemspec +41 -0
- data/lib/gitlab/triage/action/base.rb +14 -0
- data/lib/gitlab/triage/action/comment.rb +104 -0
- data/lib/gitlab/triage/action/comment_on_summary.rb +83 -0
- data/lib/gitlab/triage/action/delete.rb +56 -0
- data/lib/gitlab/triage/action/issue.rb +64 -0
- data/lib/gitlab/triage/action/summarize.rb +82 -0
- data/lib/gitlab/triage/action.rb +36 -0
- data/lib/gitlab/triage/api_query_builders/base_query_param_builder.rb +27 -0
- data/lib/gitlab/triage/api_query_builders/date_query_param_builder.rb +42 -0
- data/lib/gitlab/triage/api_query_builders/multi_query_param_builder.rb +28 -0
- data/lib/gitlab/triage/api_query_builders/single_query_param_builder.rb +13 -0
- data/lib/gitlab/triage/command_builders/base_command_builder.rb +40 -0
- data/lib/gitlab/triage/command_builders/cc_command_builder.rb +19 -0
- data/lib/gitlab/triage/command_builders/comment_command_builder.rb +19 -0
- data/lib/gitlab/triage/command_builders/label_command_builder.rb +40 -0
- data/lib/gitlab/triage/command_builders/move_command_builder.rb +19 -0
- data/lib/gitlab/triage/command_builders/remove_label_command_builder.rb +15 -0
- data/lib/gitlab/triage/command_builders/status_command_builder.rb +23 -0
- data/lib/gitlab/triage/command_builders/text_content_builder.rb +138 -0
- data/lib/gitlab/triage/engine.rb +635 -0
- data/lib/gitlab/triage/entity_builders/issue_builder.rb +54 -0
- data/lib/gitlab/triage/entity_builders/summary_builder.rb +82 -0
- data/lib/gitlab/triage/errors/network.rb +11 -0
- data/lib/gitlab/triage/errors.rb +1 -0
- data/lib/gitlab/triage/expand_condition/expansion.rb +203 -0
- data/lib/gitlab/triage/expand_condition/list.rb +25 -0
- data/lib/gitlab/triage/expand_condition/sequence.rb +25 -0
- data/lib/gitlab/triage/expand_condition.rb +23 -0
- data/lib/gitlab/triage/filters/assignee_member_conditions_filter.rb +13 -0
- data/lib/gitlab/triage/filters/author_member_conditions_filter.rb +13 -0
- data/lib/gitlab/triage/filters/base_conditions_filter.rb +58 -0
- data/lib/gitlab/triage/filters/branch_date_filter.rb +73 -0
- data/lib/gitlab/triage/filters/branch_protected_filter.rb +26 -0
- data/lib/gitlab/triage/filters/discussions_conditions_filter.rb +58 -0
- data/lib/gitlab/triage/filters/issue_date_conditions_filter.rb +78 -0
- data/lib/gitlab/triage/filters/member_conditions_filter.rb +84 -0
- data/lib/gitlab/triage/filters/merge_request_date_conditions_filter.rb +13 -0
- data/lib/gitlab/triage/filters/name_conditions_filter.rb +26 -0
- data/lib/gitlab/triage/filters/no_additional_labels_conditions_filter.rb +30 -0
- data/lib/gitlab/triage/filters/ruby_conditions_filter.rb +33 -0
- data/lib/gitlab/triage/filters/votes_conditions_filter.rb +54 -0
- data/lib/gitlab/triage/graphql_network.rb +81 -0
- data/lib/gitlab/triage/graphql_queries/query_builder.rb +158 -0
- data/lib/gitlab/triage/graphql_queries/query_param_builders/base_param_builder.rb +30 -0
- data/lib/gitlab/triage/graphql_queries/query_param_builders/date_param_builder.rb +35 -0
- data/lib/gitlab/triage/graphql_queries/query_param_builders/labels_param_builder.rb +18 -0
- data/lib/gitlab/triage/limiters/base_limiter.rb +35 -0
- data/lib/gitlab/triage/limiters/date_field_limiter.rb +45 -0
- data/lib/gitlab/triage/network.rb +39 -0
- data/lib/gitlab/triage/network_adapters/base_adapter.rb +17 -0
- data/lib/gitlab/triage/network_adapters/graphql_adapter.rb +92 -0
- data/lib/gitlab/triage/network_adapters/httparty_adapter.rb +116 -0
- data/lib/gitlab/triage/network_adapters/test_adapter.rb +39 -0
- data/lib/gitlab/triage/option_parser.rb +105 -0
- data/lib/gitlab/triage/options.rb +30 -0
- data/lib/gitlab/triage/param_builders/date_param_builder.rb +64 -0
- data/lib/gitlab/triage/policies/base_policy.rb +80 -0
- data/lib/gitlab/triage/policies/rule_policy.rb +36 -0
- data/lib/gitlab/triage/policies/summary_policy.rb +29 -0
- data/lib/gitlab/triage/policies_resources/rule_resources.rb +11 -0
- data/lib/gitlab/triage/policies_resources/summary_resources.rb +11 -0
- data/lib/gitlab/triage/resource/base.rb +102 -0
- data/lib/gitlab/triage/resource/branch.rb +13 -0
- data/lib/gitlab/triage/resource/context.rb +47 -0
- data/lib/gitlab/triage/resource/epic.rb +20 -0
- data/lib/gitlab/triage/resource/instance_version.rb +35 -0
- data/lib/gitlab/triage/resource/issue.rb +52 -0
- data/lib/gitlab/triage/resource/label.rb +56 -0
- data/lib/gitlab/triage/resource/label_event.rb +48 -0
- data/lib/gitlab/triage/resource/linked_issue.rb +15 -0
- data/lib/gitlab/triage/resource/merge_request.rb +23 -0
- data/lib/gitlab/triage/resource/milestone.rb +98 -0
- data/lib/gitlab/triage/resource/shared/issuable.rb +119 -0
- data/lib/gitlab/triage/rest_api_network.rb +125 -0
- data/lib/gitlab/triage/retryable.rb +33 -0
- data/lib/gitlab/triage/ui.rb +23 -0
- data/lib/gitlab/triage/url_builders/url_builder.rb +54 -0
- data/lib/gitlab/triage/utils.rb +13 -0
- data/lib/gitlab/triage/validators/limiter_validator.rb +21 -0
- data/lib/gitlab/triage/validators/params_validator.rb +43 -0
- data/lib/gitlab/triage/version.rb +7 -0
- data/lib/gitlab/triage.rb +6 -0
- data/support/.gitlab-ci.example.yml +22 -0
- data/support/.triage-policies.example.yml +51 -0
- metadata +280 -0
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../command_builders/text_content_builder'
|
|
4
|
+
|
|
5
|
+
module Gitlab
|
|
6
|
+
module Triage
|
|
7
|
+
module EntityBuilders
|
|
8
|
+
class SummaryBuilder
|
|
9
|
+
def initialize(
|
|
10
|
+
type:, action:, resources:, network:,
|
|
11
|
+
policy_spec: {}, separator: "\n")
|
|
12
|
+
@type = type
|
|
13
|
+
@policy_spec = policy_spec
|
|
14
|
+
@item_template = action[:item]
|
|
15
|
+
@title_template = action[:title]
|
|
16
|
+
@summary_template = action[:summary]
|
|
17
|
+
@summary_destination = action[:destination]
|
|
18
|
+
@redact_confidentials =
|
|
19
|
+
action[:redact_confidential_resources] != false
|
|
20
|
+
@resources = resources
|
|
21
|
+
@network = network
|
|
22
|
+
@separator = separator
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def title
|
|
26
|
+
@title ||= build_text(title_resource, @title_template)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def description
|
|
30
|
+
@description ||= build_text(description_resource, @summary_template)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def destination
|
|
34
|
+
@summary_destination
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def valid?
|
|
38
|
+
title =~ /\S+/ && any_resources?
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def any_resources?
|
|
42
|
+
@resources.any?
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
private
|
|
46
|
+
|
|
47
|
+
def title_resource
|
|
48
|
+
{ type: @type }
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def description_resource
|
|
52
|
+
title_resource.merge(
|
|
53
|
+
title: title, items: items, resources: @resources)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def items
|
|
57
|
+
@items ||= @resources.map { |x| build_item(x) }.join(@separator)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def build_item(resource)
|
|
61
|
+
case resource
|
|
62
|
+
when SummaryBuilder
|
|
63
|
+
resource.description
|
|
64
|
+
else
|
|
65
|
+
build_text(resource, @item_template)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def build_text(resource, template)
|
|
70
|
+
return '' unless template
|
|
71
|
+
|
|
72
|
+
CommandBuilders::TextContentBuilder.new(
|
|
73
|
+
template,
|
|
74
|
+
resource: resource,
|
|
75
|
+
network: @network,
|
|
76
|
+
redact_confidentials: @redact_confidentials)
|
|
77
|
+
.build_command.chomp
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require_relative 'errors/network'
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
module Gitlab
|
|
2
|
+
module Triage
|
|
3
|
+
module ExpandCondition
|
|
4
|
+
class Expansion
|
|
5
|
+
# @pattern describes how we're looking for the pattern, and
|
|
6
|
+
# @compile is a block which should compile the scanned data
|
|
7
|
+
# into a list of results.
|
|
8
|
+
#
|
|
9
|
+
# Please see the comments for #perform to see actual example.
|
|
10
|
+
def initialize(pattern, &compile)
|
|
11
|
+
@pattern = pattern
|
|
12
|
+
@compile = compile
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# This method will take a list of strings, which contains
|
|
16
|
+
# some kind of pattern, described by @pattern and expand them
|
|
17
|
+
# into each possible matches via @compile. For example,
|
|
18
|
+
# suppose @pattern is:
|
|
19
|
+
#
|
|
20
|
+
# /\{(\d+)\.\.(\d+)\}/
|
|
21
|
+
#
|
|
22
|
+
# And @compile is:
|
|
23
|
+
#
|
|
24
|
+
# do |(lower, upper)|
|
|
25
|
+
# Integer(lower)..Integer(upper)
|
|
26
|
+
# end
|
|
27
|
+
#
|
|
28
|
+
# And the input is:
|
|
29
|
+
#
|
|
30
|
+
# * a:{0..1}
|
|
31
|
+
# * b:{2..3}
|
|
32
|
+
# * c
|
|
33
|
+
#
|
|
34
|
+
# The result would be:
|
|
35
|
+
#
|
|
36
|
+
# * * a:0
|
|
37
|
+
# * b:2
|
|
38
|
+
# * c
|
|
39
|
+
# * * a:0
|
|
40
|
+
# * b:3
|
|
41
|
+
# * c
|
|
42
|
+
# * * a:1
|
|
43
|
+
# * b:2
|
|
44
|
+
# * c
|
|
45
|
+
# * * a:1
|
|
46
|
+
# * b:3
|
|
47
|
+
# * c
|
|
48
|
+
#
|
|
49
|
+
# We get this by picking the 1st number from the 1st string,
|
|
50
|
+
# which is 0 from "a:{0..1}", and the 1st number from the
|
|
51
|
+
# 2nd string, which is 2 from "b:{2..3}", and since the 3rd
|
|
52
|
+
# string is just a fixed string, we just pick it.
|
|
53
|
+
#
|
|
54
|
+
# This way we have the first possible match, that is:
|
|
55
|
+
#
|
|
56
|
+
# * a:0
|
|
57
|
+
# * b:2
|
|
58
|
+
# * c
|
|
59
|
+
#
|
|
60
|
+
# Then we repeat the process by picking the next number for the
|
|
61
|
+
# next possible match, starting from the least significant
|
|
62
|
+
# string, which is c, but there's nothing more to pick. Then we
|
|
63
|
+
# go to the next one, which will be the 2nd string: "b:{2..3}",
|
|
64
|
+
# and we pick the 2nd number for it: 3. Since we have a new pick,
|
|
65
|
+
# we have a new possible match:
|
|
66
|
+
#
|
|
67
|
+
# * a:0
|
|
68
|
+
# * b:3
|
|
69
|
+
# * c
|
|
70
|
+
#
|
|
71
|
+
# Again we repeat the process, and 2nd string doesn't have more
|
|
72
|
+
# choices therefore we need to go to the 1st string now. When
|
|
73
|
+
# this happens, we'll need to reset the picks from the previous
|
|
74
|
+
# string, thus 2nd string will go back to 2. The next number for
|
|
75
|
+
# the 1st string is 1, and then we form the new match:
|
|
76
|
+
#
|
|
77
|
+
# * a:1
|
|
78
|
+
# * b:2
|
|
79
|
+
# * c
|
|
80
|
+
#
|
|
81
|
+
# The next step will be the last match by picking the next number
|
|
82
|
+
# from the 2nd string again: 3, and we get:
|
|
83
|
+
#
|
|
84
|
+
# * a:1
|
|
85
|
+
# * b:3
|
|
86
|
+
# * c
|
|
87
|
+
#
|
|
88
|
+
# The method will stop here because it had walked through all the
|
|
89
|
+
# possible combinations. The total number of results is the product
|
|
90
|
+
# of numbers of sequences.
|
|
91
|
+
#
|
|
92
|
+
# Note that a string can contain multiple sequences, and it will
|
|
93
|
+
# also walk through them one by one. For example, given:
|
|
94
|
+
#
|
|
95
|
+
# * a:{0..1}:{2..3}
|
|
96
|
+
# * c
|
|
97
|
+
#
|
|
98
|
+
# We'll get:
|
|
99
|
+
#
|
|
100
|
+
# * * a:0:2
|
|
101
|
+
# * c
|
|
102
|
+
# * * a:0:3
|
|
103
|
+
# * c
|
|
104
|
+
# * * a:1:2
|
|
105
|
+
# * c
|
|
106
|
+
# * * a:1:3
|
|
107
|
+
# * c
|
|
108
|
+
def perform(strings)
|
|
109
|
+
expanded_strings =
|
|
110
|
+
strings.map(&:strip).map(&method(:expand_patterns))
|
|
111
|
+
|
|
112
|
+
product_of_all(expanded_strings)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# This method returns the product of list of lists. For example,
|
|
116
|
+
# giving it [%w[a:0 a:1], %w[b:2 b:3], %w[c]] will return:
|
|
117
|
+
#
|
|
118
|
+
# [%w[a:0 b:2 c], %w[a:0 b:3 c], %w[a:1 b:2 c], %w[a:1 b:3 c]]
|
|
119
|
+
def product_of_all(expanded_strings)
|
|
120
|
+
expanded_strings.first.product(*expanded_strings.drop(1))
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# This method expands the string from the sequences. For example,
|
|
124
|
+
# giving it "a:{0..1}:{2..3}" will return:
|
|
125
|
+
#
|
|
126
|
+
# %w[
|
|
127
|
+
# a:0:2
|
|
128
|
+
# a:0:3
|
|
129
|
+
# a:1:2
|
|
130
|
+
# a:1:3
|
|
131
|
+
# ]
|
|
132
|
+
def expand_patterns(string)
|
|
133
|
+
expand(string, scan_patterns(string))
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# This method extracts the sequences from the string. For example,
|
|
137
|
+
# giving it "a:{0..1}:{2..3}" will return:
|
|
138
|
+
#
|
|
139
|
+
# [0..1, 2..3]
|
|
140
|
+
def scan_patterns(string)
|
|
141
|
+
string.scan(@pattern).map(&@compile)
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# This recursive method does the heavy lifting. It substitutes the
|
|
145
|
+
# sequence patterns in a string with a picked number from the
|
|
146
|
+
# sequence, and collect all the results. Here's an example:
|
|
147
|
+
#
|
|
148
|
+
# expand("a:{0..1}:{2..3}", [0..1, 2..3])
|
|
149
|
+
#
|
|
150
|
+
# This means that we want to pick the numbers from the sequences,
|
|
151
|
+
# and fill them back to the string containing the pattern in the
|
|
152
|
+
# respective order. We don't care which pattern it is because
|
|
153
|
+
# the order should have spoken for it. The result will be:
|
|
154
|
+
#
|
|
155
|
+
# %w[
|
|
156
|
+
# a:0:2
|
|
157
|
+
# a:0:3
|
|
158
|
+
# a:1:2
|
|
159
|
+
# a:1:3
|
|
160
|
+
# ]
|
|
161
|
+
#
|
|
162
|
+
# We start by picking the first sequence, which is 0..1 here. We
|
|
163
|
+
# want all the possible picks, thus we flat_map on it, substituting
|
|
164
|
+
# the first pattern with the picked number. This means we get:
|
|
165
|
+
#
|
|
166
|
+
# "a:0:{2..3}"
|
|
167
|
+
#
|
|
168
|
+
# For the first iteration. Before we jump to the next pick from the
|
|
169
|
+
# sequence, we recursively do this again on the current string,
|
|
170
|
+
# which only has one sequence pattern left. It will be called like:
|
|
171
|
+
#
|
|
172
|
+
# expand("a:0:{2..3}", [2..3])
|
|
173
|
+
#
|
|
174
|
+
# Because we also dropped the first sequence we have already used.
|
|
175
|
+
# On the next recursive call, we don't have any sequences left,
|
|
176
|
+
# therefore we just return the current string: "a:0:2".
|
|
177
|
+
#
|
|
178
|
+
# Flattening the recursion, it might look like this:
|
|
179
|
+
#
|
|
180
|
+
# (0..1).flat_map do |x|
|
|
181
|
+
# (2..3).flat_map do |y|
|
|
182
|
+
# "a:{0..1}:{2..3}".sub(PATTERN, x.to_s).sub(PATTERN, y.to_s)
|
|
183
|
+
# end
|
|
184
|
+
# end
|
|
185
|
+
#
|
|
186
|
+
# So here we could clearly see that we go deep first, substituting
|
|
187
|
+
# the least significant pattern first, and then go back to the
|
|
188
|
+
# previous one, until there's nothing more to pick.
|
|
189
|
+
def expand(string, items)
|
|
190
|
+
if items.empty?
|
|
191
|
+
[string]
|
|
192
|
+
else
|
|
193
|
+
remainings = items.drop(1)
|
|
194
|
+
|
|
195
|
+
items.first.flat_map do |item|
|
|
196
|
+
expand(string.sub(@pattern, item.to_s), remainings)
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
require_relative 'expansion'
|
|
2
|
+
|
|
3
|
+
module Gitlab
|
|
4
|
+
module Triage
|
|
5
|
+
module ExpandCondition
|
|
6
|
+
module List
|
|
7
|
+
PATTERN = /\{.+?,.+?\}/m.freeze
|
|
8
|
+
|
|
9
|
+
def self.expand(conditions)
|
|
10
|
+
labels = conditions[:labels]
|
|
11
|
+
|
|
12
|
+
return conditions unless labels
|
|
13
|
+
|
|
14
|
+
expansion = Expansion.new(PATTERN) do |list|
|
|
15
|
+
list.gsub(/\{|\}/, '').split(',').map(&:strip)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
expansion.perform(labels).map do |new_labels|
|
|
19
|
+
conditions.merge(labels: new_labels)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
require_relative 'expansion'
|
|
2
|
+
|
|
3
|
+
module Gitlab
|
|
4
|
+
module Triage
|
|
5
|
+
module ExpandCondition
|
|
6
|
+
module Sequence
|
|
7
|
+
PATTERN = /\{\s*(\d+)\s*\.\.\s*(\d+)\s*\}/.freeze
|
|
8
|
+
|
|
9
|
+
def self.expand(conditions)
|
|
10
|
+
labels = conditions[:labels]
|
|
11
|
+
|
|
12
|
+
return conditions unless labels
|
|
13
|
+
|
|
14
|
+
expansion = Expansion.new(PATTERN) do |(lower, upper)|
|
|
15
|
+
Integer(lower)..Integer(upper)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
expansion.perform(labels).map do |new_labels|
|
|
19
|
+
conditions.merge(labels: new_labels)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
require_relative 'expand_condition/list'
|
|
2
|
+
require_relative 'expand_condition/sequence'
|
|
3
|
+
|
|
4
|
+
module Gitlab
|
|
5
|
+
module Triage
|
|
6
|
+
module ExpandCondition
|
|
7
|
+
PIPELINE = [
|
|
8
|
+
List,
|
|
9
|
+
Sequence
|
|
10
|
+
].freeze
|
|
11
|
+
|
|
12
|
+
def self.perform(conditions, pipeline = PIPELINE, &block)
|
|
13
|
+
expand([conditions], pipeline).each(&block)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def self.expand(conditions, pipeline = PIPELINE)
|
|
17
|
+
pipeline.inject(conditions) do |result, job|
|
|
18
|
+
result.flat_map(&job.method(:expand))
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
require 'active_support/all'
|
|
2
|
+
require_relative '../validators/params_validator'
|
|
3
|
+
|
|
4
|
+
module Gitlab
|
|
5
|
+
module Triage
|
|
6
|
+
module Filters
|
|
7
|
+
class BaseConditionsFilter
|
|
8
|
+
def initialize(resource, condition)
|
|
9
|
+
@resource = resource
|
|
10
|
+
validate_condition(condition)
|
|
11
|
+
initialize_variables(condition)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def calculate
|
|
15
|
+
raise NotImplementedError
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def self.filter_parameters
|
|
19
|
+
[]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def self.params_filter_names(params = nil)
|
|
23
|
+
params ||= filter_parameters
|
|
24
|
+
|
|
25
|
+
params.map do |param|
|
|
26
|
+
param[:name]
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def self.all_params_filter_names
|
|
31
|
+
params_filter_names
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def self.params_checking_condition_value
|
|
35
|
+
params_filter_names params_check_for_field(:values)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def self.params_checking_condition_type
|
|
39
|
+
params_filter_names params_check_for_field(:type)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def self.params_check_for_field(field)
|
|
43
|
+
filter_parameters.select do |param|
|
|
44
|
+
param[field].present?
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
private
|
|
49
|
+
|
|
50
|
+
def validate_condition(condition)
|
|
51
|
+
ParamsValidator.new(self.class.filter_parameters, condition).validate!
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def initialize_variables(condition); end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
require_relative 'base_conditions_filter'
|
|
2
|
+
|
|
3
|
+
module Gitlab
|
|
4
|
+
module Triage
|
|
5
|
+
module Filters
|
|
6
|
+
class BranchDateFilter < BaseConditionsFilter
|
|
7
|
+
ATTRIBUTES = %w[committed_date authored_date].freeze
|
|
8
|
+
CONDITIONS = %w[older_than newer_than].freeze
|
|
9
|
+
TIME_BASED_INTERVALS = %w[minutes hours].freeze
|
|
10
|
+
DATE_BASED_INTERVALS = %w[days weeks months years].freeze
|
|
11
|
+
INTERVAL_TYPES = TIME_BASED_INTERVALS + DATE_BASED_INTERVALS
|
|
12
|
+
|
|
13
|
+
def self.allowed_attributes
|
|
14
|
+
self::ATTRIBUTES
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def self.filter_parameters
|
|
18
|
+
[
|
|
19
|
+
{
|
|
20
|
+
name: :attribute,
|
|
21
|
+
type: String,
|
|
22
|
+
values: allowed_attributes
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
name: :condition,
|
|
26
|
+
type: String,
|
|
27
|
+
values: CONDITIONS
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
name: :interval_type,
|
|
31
|
+
type: String,
|
|
32
|
+
values: INTERVAL_TYPES
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
name: :interval,
|
|
36
|
+
type: Numeric
|
|
37
|
+
}
|
|
38
|
+
]
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def initialize_variables(condition)
|
|
42
|
+
@attribute = condition[:attribute].to_sym
|
|
43
|
+
@condition = condition[:condition].to_sym
|
|
44
|
+
@interval_type = condition[:interval_type].to_sym
|
|
45
|
+
@interval = condition[:interval]
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def resource_value
|
|
49
|
+
@resource[:commit][@attribute]&.to_date
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def condition_value
|
|
53
|
+
if TIME_BASED_INTERVALS.include?(@interval_type.to_s)
|
|
54
|
+
@interval.public_send(@interval_type).ago.to_datetime # rubocop:disable GitlabSecurity/PublicSend
|
|
55
|
+
else
|
|
56
|
+
@interval.public_send(@interval_type).ago.to_date # rubocop:disable GitlabSecurity/PublicSend
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def calculate
|
|
61
|
+
return false unless resource_value
|
|
62
|
+
|
|
63
|
+
case @condition
|
|
64
|
+
when :older_than
|
|
65
|
+
resource_value < condition_value
|
|
66
|
+
when :newer_than
|
|
67
|
+
resource_value > condition_value
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
require_relative 'base_conditions_filter'
|
|
2
|
+
|
|
3
|
+
module Gitlab
|
|
4
|
+
module Triage
|
|
5
|
+
module Filters
|
|
6
|
+
class BranchProtectedFilter < BaseConditionsFilter
|
|
7
|
+
def initialize_variables(config_value)
|
|
8
|
+
@attribute = :protected
|
|
9
|
+
@condition = config_value.nil? ? true : config_value
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def resource_value
|
|
13
|
+
@resource[:protected]
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def condition_value
|
|
17
|
+
@condition
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def calculate
|
|
21
|
+
resource_value == condition_value
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
require_relative 'base_conditions_filter'
|
|
2
|
+
|
|
3
|
+
module Gitlab
|
|
4
|
+
module Triage
|
|
5
|
+
module Filters
|
|
6
|
+
class DiscussionsConditionsFilter < BaseConditionsFilter
|
|
7
|
+
ATTRIBUTES = %w[notes threads].freeze
|
|
8
|
+
CONDITIONS = %w[greater_than less_than].freeze
|
|
9
|
+
|
|
10
|
+
def self.filter_parameters
|
|
11
|
+
[
|
|
12
|
+
{
|
|
13
|
+
name: :attribute,
|
|
14
|
+
type: String,
|
|
15
|
+
values: ATTRIBUTES
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
name: :condition,
|
|
19
|
+
type: String,
|
|
20
|
+
values: CONDITIONS
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
name: :threshold,
|
|
24
|
+
type: Numeric
|
|
25
|
+
}
|
|
26
|
+
]
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def initialize_variables(condition)
|
|
30
|
+
@attribute = condition[:attribute].to_sym
|
|
31
|
+
@condition = condition[:condition].to_sym
|
|
32
|
+
@threshold = condition[:threshold]
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def resource_value
|
|
36
|
+
if @attribute == :notes
|
|
37
|
+
@resource[:user_notes_count]
|
|
38
|
+
else
|
|
39
|
+
@resource[:user_discussions_count]
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def condition_value
|
|
44
|
+
@threshold
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def calculate
|
|
48
|
+
case @condition
|
|
49
|
+
when :greater_than
|
|
50
|
+
resource_value.to_i > condition_value
|
|
51
|
+
when :less_than
|
|
52
|
+
resource_value.to_i < condition_value
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
require_relative 'base_conditions_filter'
|
|
2
|
+
|
|
3
|
+
module Gitlab
|
|
4
|
+
module Triage
|
|
5
|
+
module Filters
|
|
6
|
+
class IssueDateConditionsFilter < BaseConditionsFilter
|
|
7
|
+
CONDITIONS = %w[older_than newer_than].freeze
|
|
8
|
+
TIME_BASED_INTERVALS = %w[minutes hours].freeze
|
|
9
|
+
DATE_BASED_INTERVALS = %w[days weeks months years].freeze
|
|
10
|
+
INTERVAL_TYPES = TIME_BASED_INTERVALS + DATE_BASED_INTERVALS
|
|
11
|
+
|
|
12
|
+
def self.generate_allowed_attributes
|
|
13
|
+
%w[updated_at created_at]
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def self.allowed_attributes
|
|
17
|
+
@allowed_attributes ||= generate_allowed_attributes.freeze
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def self.filter_parameters
|
|
21
|
+
[
|
|
22
|
+
{
|
|
23
|
+
name: :attribute,
|
|
24
|
+
type: String,
|
|
25
|
+
values: allowed_attributes
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
name: :condition,
|
|
29
|
+
type: String,
|
|
30
|
+
values: CONDITIONS
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
name: :interval_type,
|
|
34
|
+
type: String,
|
|
35
|
+
values: INTERVAL_TYPES
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
name: :interval,
|
|
39
|
+
type: Numeric
|
|
40
|
+
}
|
|
41
|
+
]
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def initialize_variables(condition)
|
|
45
|
+
@attribute = condition[:attribute].to_sym
|
|
46
|
+
@condition = condition[:condition].to_sym
|
|
47
|
+
@interval_type = condition[:interval_type].to_sym
|
|
48
|
+
@interval = condition[:interval]
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Guard against merge requests with no merged_at values
|
|
52
|
+
def resource_value
|
|
53
|
+
@resource[@attribute]&.to_date
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def condition_value
|
|
57
|
+
if TIME_BASED_INTERVALS.include?(@interval_type.to_s)
|
|
58
|
+
@interval.public_send(@interval_type).ago.to_datetime # rubocop:disable GitlabSecurity/PublicSend
|
|
59
|
+
else
|
|
60
|
+
@interval.public_send(@interval_type).ago.to_date # rubocop:disable GitlabSecurity/PublicSend
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Guard against merge requests with no merged_at values
|
|
65
|
+
def calculate
|
|
66
|
+
return false unless resource_value
|
|
67
|
+
|
|
68
|
+
case @condition
|
|
69
|
+
when :older_than
|
|
70
|
+
resource_value < condition_value
|
|
71
|
+
when :newer_than
|
|
72
|
+
resource_value > condition_value
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|