gitlab-triage 1.16.0 → 1.17.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/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
|