gitlab-triage 1.16.0 → 1.17.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +25 -5
- data/bin/gitlab-triage +5 -2
- data/lib/gitlab/triage/action/comment.rb +7 -4
- data/lib/gitlab/triage/api_query_builders/date_query_param_builder.rb +13 -50
- data/lib/gitlab/triage/engine.rb +26 -10
- data/lib/gitlab/triage/graphql_network.rb +11 -1
- data/lib/gitlab/triage/graphql_queries/query_builder.rb +72 -16
- data/lib/gitlab/triage/graphql_queries/query_param_builders/base_param_builder.rb +25 -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/param_builders/date_param_builder.rb +58 -0
- data/lib/gitlab/triage/policies/base_policy.rb +18 -0
- data/lib/gitlab/triage/utils.rb +13 -0
- data/lib/gitlab/triage/version.rb +1 -1
- metadata +8 -5
- data/lib/gitlab/triage/graphql_queries/threads_query.rb +0 -23
- data/lib/gitlab/triage/graphql_queries/user_notes_query.rb +0 -23
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 68a42526c02ea2ea87e7f0ca3d24ac0fb5acbdd145fb30fc2bbd79e533ce9b65
|
4
|
+
data.tar.gz: 274ba6fb0d4040abc095207eb3349c3719e57e6e37d6087af1bedaed78e8b6b5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: be15fd2ef8f9e4d12116f83906905bd43a45f0ba81978f03504aa751e97ae367f92110072abb2b2c4ae2419fd01c9599d89db3469f96c871341291dfdcddc43a
|
7
|
+
data.tar.gz: e2a9669fd8373304b66d8470fe24fae0c55349c229accf9a523462ead4e63ea4f8ef3f3bc3c1d9a6765073a5d7226f8787f2feeb8a1c6c4491d6dcedbaa3af1f
|
data/README.md
CHANGED
@@ -38,6 +38,7 @@ The format of the file is [YAML](https://en.wikipedia.org/wiki/YAML).
|
|
38
38
|
project.
|
39
39
|
|
40
40
|
Select which resource to add the policy to:
|
41
|
+
- `epics`
|
41
42
|
- `issues`
|
42
43
|
- `merge_requests`
|
43
44
|
|
@@ -47,9 +48,28 @@ For example:
|
|
47
48
|
|
48
49
|
```yml
|
49
50
|
resource_rules:
|
51
|
+
epics:
|
52
|
+
rules:
|
53
|
+
- name: My epic policy
|
54
|
+
conditions:
|
55
|
+
date:
|
56
|
+
attribute: updated_at
|
57
|
+
condition: older_than
|
58
|
+
interval_type: days
|
59
|
+
interval: 5
|
60
|
+
state: opened
|
61
|
+
labels:
|
62
|
+
- None
|
63
|
+
actions:
|
64
|
+
labels:
|
65
|
+
- needs attention
|
66
|
+
mention:
|
67
|
+
- markglenfletcher
|
68
|
+
comment: |
|
69
|
+
{{author}} This epic is unlabelled after 5 days. It needs attention. Please take care of this before the end of #{2.days.from_now.strftime('%Y-%m-%d')}
|
50
70
|
issues:
|
51
71
|
rules:
|
52
|
-
- name: My policy
|
72
|
+
- name: My issue policy
|
53
73
|
conditions:
|
54
74
|
date:
|
55
75
|
attribute: updated_at
|
@@ -86,7 +106,7 @@ resource_rules:
|
|
86
106
|
/label ~"needs attention"
|
87
107
|
merge_requests:
|
88
108
|
rules:
|
89
|
-
- name: My policy
|
109
|
+
- name: My merge request policy
|
90
110
|
conditions:
|
91
111
|
state: opened
|
92
112
|
labels:
|
@@ -797,8 +817,8 @@ Accepts a hash of fields.
|
|
797
817
|
|
798
818
|
| Field | Type | Description | Required | Placeholders | Ruby expression | Default |
|
799
819
|
| ---- | ---- | ---- | ---- | ---- | ---- | ---- |
|
800
|
-
| `title` | string | The title of the generated issue | yes | yes |
|
801
|
-
| `destination` | integer or string | The project ID or path to create the generated issue in | no
|
820
|
+
| `title` | string | The title of the generated issue | yes | yes | yes | |
|
821
|
+
| `destination` | integer or string | The project ID or path to create the generated issue in | no | no | no | source project |
|
802
822
|
| `item` | string | Template representing each triaged resource | no | yes | yes | |
|
803
823
|
| `summary` | string | The description of the generated issue | no | Only `{{title}}`, `{{items}}`, `{{type}}` | yes | |
|
804
824
|
| `redact_confidential_resources` | boolean | Whether redact fields for confidential resources | no | no | no | true |
|
@@ -901,7 +921,7 @@ resource_rules:
|
|
901
921
|
comment_type: thread
|
902
922
|
comment_on_summary: |
|
903
923
|
# {{title}}
|
904
|
-
|
924
|
+
|
905
925
|
author: {{author}}
|
906
926
|
summarize:
|
907
927
|
title: |
|
data/bin/gitlab-triage
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
require 'yaml'
|
4
4
|
require_relative '../lib/gitlab/triage/option_parser'
|
5
5
|
require_relative '../lib/gitlab/triage/engine'
|
6
|
+
require_relative '../lib/gitlab/triage/ui'
|
6
7
|
|
7
8
|
options = Gitlab::Triage::OptionParser.parse(ARGV)
|
8
9
|
options.policies_files << '.triage-policies.yml' if options.policies_files.empty?
|
@@ -10,7 +11,9 @@ options.policies_files << '.triage-policies.yml' if options.policies_files.empty
|
|
10
11
|
options.policies_files.each do |policies_file|
|
11
12
|
policies = HashWithIndifferentAccess.new(YAML.load_file(policies_file))
|
12
13
|
|
13
|
-
Gitlab::Triage::Engine
|
14
|
+
policy_engine = Gitlab::Triage::Engine
|
14
15
|
.new(policies: policies, options: options)
|
15
|
-
|
16
|
+
|
17
|
+
puts Gitlab::Triage::UI.header("Executing policies from #{policies_file}.", char: '*')
|
18
|
+
policy_engine.perform
|
16
19
|
end
|
@@ -57,14 +57,17 @@ module Gitlab
|
|
57
57
|
end
|
58
58
|
|
59
59
|
def build_post_url(resource)
|
60
|
-
|
61
|
-
post_url = UrlBuilders::UrlBuilder.new(
|
60
|
+
url_builder_opts = {
|
62
61
|
network_options: network.options,
|
63
|
-
|
62
|
+
source: policy.source,
|
63
|
+
source_id: resource[policy.source_id_sym],
|
64
64
|
resource_type: policy.type,
|
65
65
|
resource_id: resource['iid'],
|
66
66
|
sub_resource_type: sub_resource_type
|
67
|
-
|
67
|
+
}
|
68
|
+
|
69
|
+
# POST /(groups|projects)/:id/(epics|issues|merge_requests)/:iid/notes
|
70
|
+
post_url = UrlBuilders::UrlBuilder.new(url_builder_opts).build
|
68
71
|
|
69
72
|
puts Gitlab::Triage::UI.debug "post_url: #{post_url}" if network.options.debug
|
70
73
|
|
@@ -1,57 +1,32 @@
|
|
1
|
-
require_relative '../
|
1
|
+
require_relative '../param_builders/date_param_builder'
|
2
|
+
require_relative 'base_query_param_builder'
|
2
3
|
|
3
4
|
module Gitlab
|
4
5
|
module Triage
|
5
6
|
module APIQueryBuilders
|
6
|
-
class DateQueryParamBuilder
|
7
|
+
class DateQueryParamBuilder < BaseQueryParamBuilder
|
7
8
|
ATTRIBUTES = %w[updated_at created_at].freeze
|
8
|
-
CONDITIONS = %w[older_than newer_than].freeze
|
9
|
-
INTERVAL_TYPES = %w[days weeks months years].freeze
|
10
|
-
|
11
|
-
def self.filter_parameters
|
12
|
-
[
|
13
|
-
{
|
14
|
-
name: :attribute,
|
15
|
-
type: String,
|
16
|
-
values: ATTRIBUTES
|
17
|
-
},
|
18
|
-
{
|
19
|
-
name: :condition,
|
20
|
-
type: String,
|
21
|
-
values: CONDITIONS
|
22
|
-
},
|
23
|
-
{
|
24
|
-
name: :interval_type,
|
25
|
-
type: String,
|
26
|
-
values: INTERVAL_TYPES
|
27
|
-
},
|
28
|
-
{
|
29
|
-
name: :interval,
|
30
|
-
type: Numeric
|
31
|
-
}
|
32
|
-
]
|
33
|
-
end
|
34
9
|
|
35
10
|
def self.applicable?(condition)
|
36
11
|
ATTRIBUTES.include?(condition[:attribute].to_s)
|
37
12
|
end
|
38
13
|
|
39
14
|
def initialize(condition_hash)
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
@interval = condition_hash[:interval]
|
44
|
-
validate_condition(condition_hash)
|
15
|
+
date_param_builder = ParamBuilders::DateParamBuilder.new(ATTRIBUTES, condition_hash)
|
16
|
+
|
17
|
+
super(build_param_name(condition_hash), date_param_builder.param_content)
|
45
18
|
end
|
46
19
|
|
47
|
-
def
|
48
|
-
|
20
|
+
def param_content
|
21
|
+
param_contents
|
49
22
|
end
|
50
23
|
|
51
|
-
|
52
|
-
|
24
|
+
private
|
25
|
+
|
26
|
+
def build_param_name(condition_hash)
|
27
|
+
prefix = condition_hash[:attribute].to_s.sub(/_at\z/, '')
|
53
28
|
suffix =
|
54
|
-
case
|
29
|
+
case condition_hash[:condition].to_sym
|
55
30
|
when :older_than
|
56
31
|
'before'
|
57
32
|
when :newer_than
|
@@ -60,18 +35,6 @@ module Gitlab
|
|
60
35
|
|
61
36
|
"#{prefix}_#{suffix}"
|
62
37
|
end
|
63
|
-
|
64
|
-
def param_content
|
65
|
-
interval.public_send(interval_type).ago.to_date # rubocop:disable GitlabSecurity/PublicSend
|
66
|
-
end
|
67
|
-
|
68
|
-
def build_param
|
69
|
-
"&#{param_name}=#{param_content.strip}"
|
70
|
-
end
|
71
|
-
|
72
|
-
private
|
73
|
-
|
74
|
-
attr_reader :condition_hash, :attribute, :interval_condition, :interval_type, :interval
|
75
38
|
end
|
76
39
|
end
|
77
40
|
end
|
data/lib/gitlab/triage/engine.rb
CHANGED
@@ -177,14 +177,23 @@ module Gitlab
|
|
177
177
|
ExpandCondition.perform(rule_conditions(rule)) do |conditions|
|
178
178
|
# retrieving the resources for every rule is inefficient
|
179
179
|
# however, previous rules may affect those upcoming
|
180
|
-
resources =
|
181
|
-
|
180
|
+
resources = []
|
181
|
+
|
182
|
+
if rule[:api] == 'graphql'
|
183
|
+
graphql_query = build_graphql_query(resource_type, conditions, true)
|
184
|
+
resources = graphql_network.query(graphql_query, source: source_full_path)
|
185
|
+
else
|
186
|
+
resources = network.query_api(build_get_url(resource_type, conditions))
|
187
|
+
iids = resources.pluck('iid').map(&:to_s)
|
188
|
+
|
189
|
+
graphql_query = build_graphql_query(resource_type, conditions)
|
190
|
+
graphql_resources = graphql_network.query(graphql_query, source: source_full_path, iids: iids) if graphql_query.any?
|
191
|
+
|
192
|
+
decorate_resources_with_graphql_data(resources, graphql_resources)
|
193
|
+
end
|
182
194
|
|
183
|
-
graphql_query = build_graphql_query(resource_type, conditions)
|
184
|
-
graphql_resources = graphql_network.query(graphql_query, source: source_full_path, iids: iids) if graphql_query.present?
|
185
195
|
# In some filters/actions we want to know which resource type it is
|
186
196
|
attach_resource_type(resources, resource_type)
|
187
|
-
decorate_resources_with_graphql_data(resources, graphql_resources)
|
188
197
|
|
189
198
|
puts "\n\n* Found #{resources.count} resources..."
|
190
199
|
print "* Filtering resources..."
|
@@ -199,10 +208,17 @@ module Gitlab
|
|
199
208
|
end
|
200
209
|
end
|
201
210
|
|
202
|
-
# We don't have to do this once the response will contain the type
|
203
|
-
# of the resource. For now let's just attach it.
|
204
211
|
def attach_resource_type(resources, resource_type)
|
205
|
-
resources.each { |resource| resource[:type]
|
212
|
+
resources.each { |resource| resource[:type] = resource_type }
|
213
|
+
# TODO: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
214
|
+
# We should not overwrite the attribute here, but we need to
|
215
|
+
# fix it first. We should instead use something like
|
216
|
+
# gitlab_triage_resource_type so it won't conflict with the
|
217
|
+
# existing fields.
|
218
|
+
# And we need to retain the backward compatibility that using
|
219
|
+
# {{type}} will give us this value, rather than from the REST API,
|
220
|
+
# which will give us ISSUE from:
|
221
|
+
# https://gitlab.com/gitlab-org/gitlab/-/merge_requests/59648
|
206
222
|
end
|
207
223
|
|
208
224
|
def decorate_resources_with_graphql_data(resources, graphql_resources)
|
@@ -313,9 +329,9 @@ module Gitlab
|
|
313
329
|
).build
|
314
330
|
end
|
315
331
|
|
316
|
-
def build_graphql_query(resource_type, conditions)
|
332
|
+
def build_graphql_query(resource_type, conditions, graphql_only = false)
|
317
333
|
Gitlab::Triage::GraphqlQueries::QueryBuilder
|
318
|
-
.new(options.source, resource_type, conditions)
|
334
|
+
.new(options.source, resource_type, conditions, graphql_only: graphql_only)
|
319
335
|
end
|
320
336
|
|
321
337
|
def source_full_path
|
@@ -44,11 +44,21 @@ module Gitlab
|
|
44
44
|
resources
|
45
45
|
.map { |resource| resource.deep_transform_keys(&:underscore) }
|
46
46
|
.map(&:with_indifferent_access)
|
47
|
-
.map { |resource|
|
47
|
+
.map { |resource| normalize(resource) }
|
48
48
|
end
|
49
49
|
|
50
50
|
private
|
51
51
|
|
52
|
+
def normalize(resource)
|
53
|
+
resource
|
54
|
+
.slice(:iid, :state, :author, :merged_at, :user_notes_count, :user_discussions_count, :upvotes, :downvotes, :project_id, :web_url)
|
55
|
+
.merge(
|
56
|
+
id: extract_id_from_global_id(resource[:id]),
|
57
|
+
labels: [*resource.dig(:labels, :nodes)].pluck(:title),
|
58
|
+
assignees: [*resource.dig(:assignees, :nodes)]
|
59
|
+
)
|
60
|
+
end
|
61
|
+
|
52
62
|
def extract_id_from_global_id(global_id)
|
53
63
|
return if global_id.blank?
|
54
64
|
|
@@ -1,14 +1,16 @@
|
|
1
|
-
require_relative '
|
2
|
-
require_relative '
|
1
|
+
require_relative 'query_param_builders/base_param_builder'
|
2
|
+
require_relative 'query_param_builders/date_param_builder'
|
3
|
+
require_relative 'query_param_builders/labels_param_builder'
|
3
4
|
|
4
5
|
module Gitlab
|
5
6
|
module Triage
|
6
7
|
module GraphqlQueries
|
7
8
|
class QueryBuilder
|
8
|
-
def initialize(source_type, resource_type, conditions)
|
9
|
+
def initialize(source_type, resource_type, conditions, graphql_only: false)
|
9
10
|
@source_type = source_type.to_s.singularize
|
10
11
|
@resource_type = resource_type
|
11
12
|
@conditions = conditions
|
13
|
+
@graphql_only = graphql_only
|
12
14
|
end
|
13
15
|
|
14
16
|
def resource_path
|
@@ -16,30 +18,84 @@ module Gitlab
|
|
16
18
|
end
|
17
19
|
|
18
20
|
def query
|
19
|
-
return if
|
21
|
+
return if resource_fields.empty?
|
20
22
|
|
21
|
-
format(
|
23
|
+
format(
|
24
|
+
BASE_QUERY,
|
25
|
+
source_type: source_type,
|
26
|
+
resource_type: resource_type.to_s.camelize(:lower),
|
27
|
+
resource_fields: resource_fields.join(' '),
|
28
|
+
resource_query: resource_query,
|
29
|
+
iids_declaration: graphql_only ? nil : ', $iids: [String!]',
|
30
|
+
iids_query: graphql_only ? nil : ', iids: $iids'
|
31
|
+
)
|
22
32
|
end
|
23
33
|
|
24
|
-
delegate :
|
34
|
+
delegate :any?, to: :resource_fields
|
25
35
|
|
26
36
|
private
|
27
37
|
|
28
|
-
attr_reader :source_type, :resource_type, :conditions
|
38
|
+
attr_reader :source_type, :resource_type, :conditions, :graphql_only
|
29
39
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
40
|
+
BASE_QUERY = <<~GRAPHQL.freeze
|
41
|
+
query($source: ID!, $after: String%{iids_declaration}) {
|
42
|
+
%{source_type}(fullPath: $source) {
|
43
|
+
id
|
44
|
+
%{resource_type}(after: $after%{iids_query}%{resource_query}) {
|
45
|
+
pageInfo {
|
46
|
+
hasNextPage
|
47
|
+
endCursor
|
48
|
+
}
|
49
|
+
nodes {
|
50
|
+
id iid title updatedAt createdAt webUrl projectId %{resource_fields}
|
51
|
+
}
|
52
|
+
}
|
53
|
+
}
|
54
|
+
}
|
55
|
+
GRAPHQL
|
56
|
+
|
57
|
+
def resource_fields
|
58
|
+
fields = []
|
59
|
+
|
60
|
+
fields << 'userNotesCount' if conditions.dig(:discussions, :attribute).to_s == 'notes'
|
61
|
+
fields << 'userDiscussionsCount' if conditions.dig(:discussions, :attribute).to_s == 'threads'
|
62
|
+
|
63
|
+
if graphql_only
|
64
|
+
fields << 'labels { nodes { title } }'
|
65
|
+
fields << 'author { id name username }'
|
66
|
+
fields << 'assignees { nodes { id name username } }' if conditions.key?(:assignee_member)
|
67
|
+
fields << 'upvotes' if conditions.dig(:upvotes, :attribute).to_s == 'upvotes'
|
68
|
+
fields << 'downvotes' if conditions.dig(:upvotes, :attribute).to_s == 'downvotes'
|
69
|
+
fields << 'mergedAt' if resource_type == 'merge_requests'
|
36
70
|
end
|
71
|
+
|
72
|
+
fields
|
37
73
|
end
|
38
74
|
|
39
|
-
def
|
40
|
-
|
75
|
+
def resource_query
|
76
|
+
condition_queries = []
|
77
|
+
|
78
|
+
condition_queries << QueryParamBuilders::BaseParamBuilder.new('includeSubgroups', true, with_quotes: false) if source_type == 'group'
|
79
|
+
|
80
|
+
conditions.each do |condition, condition_params|
|
81
|
+
condition_queries << QueryParamBuilders::DateParamBuilder.new(condition_params) if condition.to_s == 'date'
|
82
|
+
condition_queries << QueryParamBuilders::BaseParamBuilder.new('milestoneTitle', condition_params) if condition.to_s == 'milestone'
|
83
|
+
condition_queries << QueryParamBuilders::BaseParamBuilder.new('state', condition_params, with_quotes: false) if condition.to_s == 'state'
|
84
|
+
|
85
|
+
if resource_type == 'merge_requests'
|
86
|
+
condition_queries << QueryParamBuilders::LabelsParamBuilder.new('labels', condition_params) if condition.to_s == 'labels'
|
87
|
+
condition_queries << QueryParamBuilders::BaseParamBuilder.new('sourceBranch', condition_params) if condition.to_s == 'source_branch'
|
88
|
+
condition_queries << QueryParamBuilders::BaseParamBuilder.new('targetBranch', condition_params) if condition.to_s == 'target_branch'
|
89
|
+
end
|
90
|
+
|
91
|
+
if resource_type == 'issues'
|
92
|
+
condition_queries << QueryParamBuilders::LabelsParamBuilder.new('labelName', condition_params) if condition.to_s == 'labels'
|
93
|
+
end
|
94
|
+
end
|
41
95
|
|
42
|
-
|
96
|
+
condition_queries
|
97
|
+
.map(&:build_param)
|
98
|
+
.join
|
43
99
|
end
|
44
100
|
end
|
45
101
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require_relative '../../utils'
|
2
|
+
|
3
|
+
module Gitlab
|
4
|
+
module Triage
|
5
|
+
module GraphqlQueries
|
6
|
+
module QueryParamBuilders
|
7
|
+
class BaseParamBuilder
|
8
|
+
attr_reader :param_name, :param_contents, :with_quotes
|
9
|
+
|
10
|
+
def initialize(param_name, param_contents, with_quotes: true)
|
11
|
+
@param_name = param_name
|
12
|
+
@param_contents = param_contents.to_s.strip
|
13
|
+
@with_quotes = with_quotes
|
14
|
+
end
|
15
|
+
|
16
|
+
def build_param
|
17
|
+
contents = with_quotes ? Utils.graphql_quote(param_contents) : param_contents
|
18
|
+
|
19
|
+
", #{param_name}: #{contents}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require_relative '../../param_builders/date_param_builder'
|
2
|
+
require_relative 'base_param_builder'
|
3
|
+
|
4
|
+
module Gitlab
|
5
|
+
module Triage
|
6
|
+
module GraphqlQueries
|
7
|
+
module QueryParamBuilders
|
8
|
+
class DateParamBuilder < BaseParamBuilder
|
9
|
+
ATTRIBUTES = %w[updated_at created_at merged_at].freeze
|
10
|
+
|
11
|
+
def initialize(condition_hash)
|
12
|
+
date_param_builder = ParamBuilders::DateParamBuilder.new(ATTRIBUTES, condition_hash)
|
13
|
+
|
14
|
+
super(build_param_name(condition_hash), date_param_builder.param_content)
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def build_param_name(condition_hash)
|
20
|
+
prefix = condition_hash[:attribute].to_s.sub(/_at\z/, '')
|
21
|
+
suffix =
|
22
|
+
case condition_hash[:condition].to_sym
|
23
|
+
when :older_than
|
24
|
+
'Before'
|
25
|
+
when :newer_than
|
26
|
+
'After'
|
27
|
+
end
|
28
|
+
|
29
|
+
"#{prefix}#{suffix}"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require_relative '../../utils'
|
2
|
+
require_relative 'base_param_builder'
|
3
|
+
|
4
|
+
module Gitlab
|
5
|
+
module Triage
|
6
|
+
module GraphqlQueries
|
7
|
+
module QueryParamBuilders
|
8
|
+
class LabelsParamBuilder < BaseParamBuilder
|
9
|
+
def initialize(param_name, labels)
|
10
|
+
label_param_content = labels.map { |label| Utils.graphql_quote(label) }.join(', ').then { |content| "[#{content}]" }
|
11
|
+
|
12
|
+
super(param_name, label_param_content, with_quotes: false)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require_relative '../validators/params_validator'
|
2
|
+
|
3
|
+
module Gitlab
|
4
|
+
module Triage
|
5
|
+
module ParamBuilders
|
6
|
+
class DateParamBuilder
|
7
|
+
CONDITIONS = %w[older_than newer_than].freeze
|
8
|
+
INTERVAL_TYPES = %w[days weeks months years].freeze
|
9
|
+
|
10
|
+
def initialize(allowed_attributes, condition_hash)
|
11
|
+
@allowed_attributes = allowed_attributes
|
12
|
+
@attribute = condition_hash[:attribute].to_s
|
13
|
+
@interval_condition = condition_hash[:condition].to_sym
|
14
|
+
@interval_type = condition_hash[:interval_type]
|
15
|
+
@interval = condition_hash[:interval]
|
16
|
+
|
17
|
+
validate_condition(condition_hash)
|
18
|
+
end
|
19
|
+
|
20
|
+
def param_content
|
21
|
+
interval.public_send(interval_type).ago.to_date # rubocop:disable GitlabSecurity/PublicSend
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
attr_reader :allowed_attributes, :attribute, :interval_condition, :interval_type, :interval
|
27
|
+
|
28
|
+
def validate_condition(condition)
|
29
|
+
ParamsValidator.new(filter_parameters, condition).validate!
|
30
|
+
end
|
31
|
+
|
32
|
+
def filter_parameters
|
33
|
+
[
|
34
|
+
{
|
35
|
+
name: :attribute,
|
36
|
+
type: String,
|
37
|
+
values: allowed_attributes
|
38
|
+
},
|
39
|
+
{
|
40
|
+
name: :condition,
|
41
|
+
type: String,
|
42
|
+
values: CONDITIONS
|
43
|
+
},
|
44
|
+
{
|
45
|
+
name: :interval_type,
|
46
|
+
type: String,
|
47
|
+
values: INTERVAL_TYPES
|
48
|
+
},
|
49
|
+
{
|
50
|
+
name: :interval,
|
51
|
+
type: Numeric
|
52
|
+
}
|
53
|
+
]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -24,6 +24,24 @@ module Gitlab
|
|
24
24
|
@name ||= (policy_spec[:name] || "#{type}-#{object_id}")
|
25
25
|
end
|
26
26
|
|
27
|
+
def source
|
28
|
+
case type
|
29
|
+
when 'epics'
|
30
|
+
'groups'
|
31
|
+
else
|
32
|
+
'projects'
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def source_id_sym
|
37
|
+
case type
|
38
|
+
when 'epics'
|
39
|
+
:group_id
|
40
|
+
else
|
41
|
+
:project_id
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
27
45
|
def actions
|
28
46
|
@actions ||= policy_spec.fetch(:actions) { {} }
|
29
47
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gitlab-triage
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.17.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- GitLab
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-05-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -196,8 +196,9 @@ files:
|
|
196
196
|
- lib/gitlab/triage/filters/votes_conditions_filter.rb
|
197
197
|
- lib/gitlab/triage/graphql_network.rb
|
198
198
|
- lib/gitlab/triage/graphql_queries/query_builder.rb
|
199
|
-
- lib/gitlab/triage/graphql_queries/
|
200
|
-
- lib/gitlab/triage/graphql_queries/
|
199
|
+
- lib/gitlab/triage/graphql_queries/query_param_builders/base_param_builder.rb
|
200
|
+
- lib/gitlab/triage/graphql_queries/query_param_builders/date_param_builder.rb
|
201
|
+
- lib/gitlab/triage/graphql_queries/query_param_builders/labels_param_builder.rb
|
201
202
|
- lib/gitlab/triage/limiters/base_limiter.rb
|
202
203
|
- lib/gitlab/triage/limiters/date_field_limiter.rb
|
203
204
|
- lib/gitlab/triage/network.rb
|
@@ -207,6 +208,7 @@ files:
|
|
207
208
|
- lib/gitlab/triage/network_adapters/test_adapter.rb
|
208
209
|
- lib/gitlab/triage/option_parser.rb
|
209
210
|
- lib/gitlab/triage/options.rb
|
211
|
+
- lib/gitlab/triage/param_builders/date_param_builder.rb
|
210
212
|
- lib/gitlab/triage/policies/base_policy.rb
|
211
213
|
- lib/gitlab/triage/policies/rule_policy.rb
|
212
214
|
- lib/gitlab/triage/policies/summary_policy.rb
|
@@ -225,6 +227,7 @@ files:
|
|
225
227
|
- lib/gitlab/triage/retryable.rb
|
226
228
|
- lib/gitlab/triage/ui.rb
|
227
229
|
- lib/gitlab/triage/url_builders/url_builder.rb
|
230
|
+
- lib/gitlab/triage/utils.rb
|
228
231
|
- lib/gitlab/triage/validators/limiter_validator.rb
|
229
232
|
- lib/gitlab/triage/validators/params_validator.rb
|
230
233
|
- lib/gitlab/triage/version.rb
|
@@ -249,7 +252,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
249
252
|
- !ruby/object:Gem::Version
|
250
253
|
version: '0'
|
251
254
|
requirements: []
|
252
|
-
rubygems_version: 3.1.
|
255
|
+
rubygems_version: 3.1.6
|
253
256
|
signing_key:
|
254
257
|
specification_version: 4
|
255
258
|
summary: GitLab triage automation project.
|
@@ -1,23 +0,0 @@
|
|
1
|
-
module Gitlab
|
2
|
-
module Triage
|
3
|
-
module GraphqlQueries
|
4
|
-
ThreadsQuery = <<-GRAPHQL.freeze # rubocop:disable Naming/ConstantName
|
5
|
-
query($source: ID!, $after: String, $iids: [String!]) {
|
6
|
-
%{source_type}(fullPath: $source) {
|
7
|
-
id
|
8
|
-
%{resource_type}(after: $after, iids: $iids%{group_query}) {
|
9
|
-
pageInfo {
|
10
|
-
hasNextPage
|
11
|
-
endCursor
|
12
|
-
}
|
13
|
-
nodes {
|
14
|
-
id
|
15
|
-
userDiscussionsCount
|
16
|
-
}
|
17
|
-
}
|
18
|
-
}
|
19
|
-
}
|
20
|
-
GRAPHQL
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
@@ -1,23 +0,0 @@
|
|
1
|
-
module Gitlab
|
2
|
-
module Triage
|
3
|
-
module GraphqlQueries
|
4
|
-
UserNotesQuery = <<-GRAPHQL.freeze # rubocop:disable Naming/ConstantName
|
5
|
-
query($source: ID!, $after: String, $iids: [String!]) {
|
6
|
-
%{source_type}(fullPath: $source) {
|
7
|
-
id
|
8
|
-
%{resource_type}(after: $after, iids: $iids%{group_query}) {
|
9
|
-
pageInfo {
|
10
|
-
hasNextPage
|
11
|
-
endCursor
|
12
|
-
}
|
13
|
-
nodes {
|
14
|
-
id
|
15
|
-
userNotesCount
|
16
|
-
}
|
17
|
-
}
|
18
|
-
}
|
19
|
-
}
|
20
|
-
GRAPHQL
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|