gitlab-triage 1.14.2 → 1.18.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/.rubocop.yml +1 -1
- data/README.md +75 -4
- data/bin/gitlab-triage +5 -2
- data/lib/gitlab/triage/action.rb +8 -4
- data/lib/gitlab/triage/action/comment.rb +17 -5
- data/lib/gitlab/triage/action/comment_on_summary.rb +83 -0
- data/lib/gitlab/triage/action/summarize.rb +7 -1
- data/lib/gitlab/triage/api_query_builders/date_query_param_builder.rb +13 -50
- data/lib/gitlab/triage/command_builders/label_command_builder.rb +5 -1
- data/lib/gitlab/triage/engine.rb +46 -10
- data/lib/gitlab/triage/errors/network.rb +2 -0
- data/lib/gitlab/triage/filters/discussions_conditions_filter.rb +1 -3
- data/lib/gitlab/triage/graphql_network.rb +28 -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/network.rb +9 -3
- data/lib/gitlab/triage/network_adapters/base_adapter.rb +3 -1
- data/lib/gitlab/triage/network_adapters/graphql_adapter.rb +33 -10
- data/lib/gitlab/triage/network_adapters/httparty_adapter.rb +12 -0
- data/lib/gitlab/triage/option_parser.rb +2 -0
- data/lib/gitlab/triage/param_builders/date_param_builder.rb +58 -0
- data/lib/gitlab/triage/policies/base_policy.rb +30 -1
- data/lib/gitlab/triage/resource/context.rb +1 -0
- data/lib/gitlab/triage/resource/epic.rb +24 -0
- data/lib/gitlab/triage/retryable.rb +7 -5
- data/lib/gitlab/triage/utils.rb +13 -0
- data/lib/gitlab/triage/version.rb +1 -1
- metadata +10 -5
- data/lib/gitlab/triage/graphql_queries/threads_query.rb +0 -31
- 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: '0609b18bd6e787fbf4e4c586b8631bc5f8c83c0a9c1a90047da3f953b558a6d6'
|
|
4
|
+
data.tar.gz: dec00b0fe73a998726c0c42a845aa5fa48e5b590597df4f054ed26200d4a47ca
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: bb63d114b513c6a8705e47b432e5c7612fc4cbe9bf729d625286917b14341a0bfffc18ce70b06968a347b61ae8a2a629ed2c76f0e8d0c37b35a611c97b7d1045
|
|
7
|
+
data.tar.gz: e0752eb15014713b4ef6f1ad64494a6b3607348be75107a93a59e11659a2fa8fca4a80b4e45c8a9eca9fb7fe4ecd2dcd0923fd27bfae8d09de9ee3bf45c8e2f8
|
data/.rubocop.yml
CHANGED
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:
|
|
@@ -585,6 +605,7 @@ Available action types:
|
|
|
585
605
|
- [`comment` action](#comment-action)
|
|
586
606
|
- [`comment_type` action option](#comment-type-action-option)
|
|
587
607
|
- [`summarize` action](#summarize-action)
|
|
608
|
+
- [`comment_on_summary` action](#comment-on-summary-action)
|
|
588
609
|
|
|
589
610
|
##### Labels action
|
|
590
611
|
|
|
@@ -796,8 +817,8 @@ Accepts a hash of fields.
|
|
|
796
817
|
|
|
797
818
|
| Field | Type | Description | Required | Placeholders | Ruby expression | Default |
|
|
798
819
|
| ---- | ---- | ---- | ---- | ---- | ---- | ---- |
|
|
799
|
-
| `title` | string | The title of the generated issue | yes | yes |
|
|
800
|
-
| `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 |
|
|
801
822
|
| `item` | string | Template representing each triaged resource | no | yes | yes | |
|
|
802
823
|
| `summary` | string | The description of the generated issue | no | Only `{{title}}`, `{{items}}`, `{{type}}` | yes | |
|
|
803
824
|
| `redact_confidential_resources` | boolean | Whether redact fields for confidential resources | no | no | no | true |
|
|
@@ -867,6 +888,56 @@ Which could generate an issue like:
|
|
|
867
888
|
/label ~"needs attention"
|
|
868
889
|
```
|
|
869
890
|
|
|
891
|
+
##### Comment on summary action
|
|
892
|
+
|
|
893
|
+
Generates one comment for each resource, attaching these comments to the summary
|
|
894
|
+
created by the [`summarize` action](#summarize-action).
|
|
895
|
+
|
|
896
|
+
The use case for this is wanting to create a summary with an overview, and then
|
|
897
|
+
a threaded discussion for each resource, with a header comment starting each
|
|
898
|
+
discussion.
|
|
899
|
+
|
|
900
|
+
Accepts a single string value: the template used to generate the comments. For
|
|
901
|
+
details of the syntax of this template, see the [comment action](#comment-action).
|
|
902
|
+
|
|
903
|
+
Since this action depends on the summary, it is invalid to supply a
|
|
904
|
+
`comment_on_summary` action without an accompanying `summarize` sibling action.
|
|
905
|
+
The `summarize` action will always be completed first.
|
|
906
|
+
|
|
907
|
+
Just like for [comment action](#comment-action), setting `comment_type` in the
|
|
908
|
+
`actions` set controls whether the comment must be resolved for merge requests.
|
|
909
|
+
See: [`comment_type` action option](#comment-type-action-option).
|
|
910
|
+
|
|
911
|
+
Example:
|
|
912
|
+
|
|
913
|
+
```yml
|
|
914
|
+
resource_rules:
|
|
915
|
+
issues:
|
|
916
|
+
rules:
|
|
917
|
+
- name: List of issues to discuss
|
|
918
|
+
limits:
|
|
919
|
+
most_recent: 15
|
|
920
|
+
actions:
|
|
921
|
+
comment_type: thread
|
|
922
|
+
comment_on_summary: |
|
|
923
|
+
# {{title}}
|
|
924
|
+
|
|
925
|
+
author: {{author}}
|
|
926
|
+
summarize:
|
|
927
|
+
title: |
|
|
928
|
+
#{resource[:type].capitalize} require labels
|
|
929
|
+
item: |
|
|
930
|
+
- [ ] [{{title}}]({{web_url}}) {{labels}}
|
|
931
|
+
summary: |
|
|
932
|
+
The following {{type}} require labels:
|
|
933
|
+
|
|
934
|
+
{{items}}
|
|
935
|
+
|
|
936
|
+
Please take care of them before the end of #{7.days.from_now.strftime('%Y-%m-%d')}
|
|
937
|
+
|
|
938
|
+
/label ~"needs attention"
|
|
939
|
+
```
|
|
940
|
+
|
|
870
941
|
### Summary policies
|
|
871
942
|
|
|
872
943
|
Summary policies are special policies that join multiple rule policies together
|
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
|
data/lib/gitlab/triage/action.rb
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
require_relative 'action/summarize'
|
|
2
2
|
require_relative 'action/comment'
|
|
3
|
+
require_relative 'action/comment_on_summary'
|
|
3
4
|
|
|
4
5
|
module Gitlab
|
|
5
6
|
module Triage
|
|
6
7
|
module Action
|
|
7
8
|
def self.process(policy:, **args)
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
policy.validate!
|
|
10
|
+
|
|
11
|
+
[
|
|
12
|
+
[Summarize, policy.summarize?],
|
|
13
|
+
[Comment, policy.comment?],
|
|
14
|
+
[CommentOnSummary, policy.comment_on_summary?]
|
|
15
|
+
].each do |action, active|
|
|
12
16
|
act(action: action, policy: policy, **args) if active
|
|
13
17
|
end
|
|
14
18
|
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
|
-
resource_id: resource
|
|
65
|
+
resource_id: resource_id(resource),
|
|
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
|
|
|
@@ -81,6 +84,15 @@ module Gitlab
|
|
|
81
84
|
raise ArgumentError, "Unknown comment type: #{type}"
|
|
82
85
|
end
|
|
83
86
|
end
|
|
87
|
+
|
|
88
|
+
def resource_id(resource)
|
|
89
|
+
case policy.type
|
|
90
|
+
when 'epics'
|
|
91
|
+
resource['id']
|
|
92
|
+
else
|
|
93
|
+
resource['iid']
|
|
94
|
+
end
|
|
95
|
+
end
|
|
84
96
|
end
|
|
85
97
|
end
|
|
86
98
|
end
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base'
|
|
4
|
+
require_relative '../command_builders/text_content_builder'
|
|
5
|
+
require_relative '../command_builders/comment_command_builder'
|
|
6
|
+
require_relative '../command_builders/label_command_builder'
|
|
7
|
+
require_relative '../command_builders/remove_label_command_builder'
|
|
8
|
+
require_relative '../command_builders/cc_command_builder'
|
|
9
|
+
require_relative '../command_builders/status_command_builder'
|
|
10
|
+
require_relative '../command_builders/move_command_builder'
|
|
11
|
+
|
|
12
|
+
module Gitlab
|
|
13
|
+
module Triage
|
|
14
|
+
module Action
|
|
15
|
+
class CommentOnSummary < Base
|
|
16
|
+
class Dry < CommentOnSummary
|
|
17
|
+
def act
|
|
18
|
+
puts "The following comments would be posted for the rule **#{policy.name}**:\n\n"
|
|
19
|
+
|
|
20
|
+
super
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def perform(comment)
|
|
26
|
+
puts "# #{summary[:web_url]}\n```\n#{comment}\n```\n"
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
attr_reader :summary
|
|
31
|
+
|
|
32
|
+
def initialize(policy:, network:)
|
|
33
|
+
super(policy: policy, network: network)
|
|
34
|
+
@summary = policy.summary
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def act
|
|
38
|
+
policy.resources.each do |resource|
|
|
39
|
+
comment = build_comment(resource).strip
|
|
40
|
+
|
|
41
|
+
perform(comment) unless comment.empty?
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
private
|
|
46
|
+
|
|
47
|
+
def build_comment(resource)
|
|
48
|
+
CommandBuilders::TextContentBuilder.new(policy.actions[:comment_on_summary], resource: resource, network: network).build_command
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def perform(comment)
|
|
52
|
+
network.post_api(build_post_url, body: comment)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def build_post_url
|
|
56
|
+
# POST /projects/:id/issues/:issue_iid/notes
|
|
57
|
+
post_url = UrlBuilders::UrlBuilder.new(
|
|
58
|
+
network_options: network.options,
|
|
59
|
+
source_id: summary['project_id'],
|
|
60
|
+
resource_type: policy.type,
|
|
61
|
+
resource_id: summary['iid'],
|
|
62
|
+
sub_resource_type: sub_resource_type
|
|
63
|
+
).build
|
|
64
|
+
|
|
65
|
+
puts Gitlab::Triage::UI.debug "post_url: #{post_url}" if network.options.debug
|
|
66
|
+
|
|
67
|
+
post_url
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def sub_resource_type
|
|
71
|
+
case type = policy.actions[:comment_type]
|
|
72
|
+
when 'comment', nil # nil is default
|
|
73
|
+
'notes'
|
|
74
|
+
when 'thread'
|
|
75
|
+
'discussions'
|
|
76
|
+
else
|
|
77
|
+
raise ArgumentError, "Unknown comment type: #{type}"
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
@@ -10,6 +10,12 @@ module Gitlab
|
|
|
10
10
|
private
|
|
11
11
|
|
|
12
12
|
def perform
|
|
13
|
+
policy.summary = {
|
|
14
|
+
web_url: '[the-created-issue-url]',
|
|
15
|
+
project_id: 'some-id',
|
|
16
|
+
iid: 'some-iid'
|
|
17
|
+
}.with_indifferent_access
|
|
18
|
+
|
|
13
19
|
if group_summary_without_destination?
|
|
14
20
|
puts Gitlab::Triage::UI.warn("No issue will be created: No summary destination specified when source is 'groups'.")
|
|
15
21
|
return
|
|
@@ -35,7 +41,7 @@ module Gitlab
|
|
|
35
41
|
return
|
|
36
42
|
end
|
|
37
43
|
|
|
38
|
-
network.post_api(post_issue_url, post_issue_body)
|
|
44
|
+
policy.summary = network.post_api(post_issue_url, post_issue_body)
|
|
39
45
|
end
|
|
40
46
|
|
|
41
47
|
def issue
|
|
@@ -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
|
|
@@ -14,7 +14,11 @@ module Gitlab
|
|
|
14
14
|
|
|
15
15
|
def ensure_labels_exist!
|
|
16
16
|
items.each do |label|
|
|
17
|
-
|
|
17
|
+
source_id_key = resource.key?(:group_id) ? :group_id : :project_id
|
|
18
|
+
label_opts = {
|
|
19
|
+
source_id_key => resource[source_id_key],
|
|
20
|
+
name: label
|
|
21
|
+
}
|
|
18
22
|
|
|
19
23
|
unless Resource::Label.new(label_opts, network: network).exist?
|
|
20
24
|
raise Resource::Label::LabelDoesntExistError,
|
data/lib/gitlab/triage/engine.rb
CHANGED
|
@@ -37,6 +37,7 @@ module Gitlab
|
|
|
37
37
|
issues: %w[opened closed],
|
|
38
38
|
merge_requests: %w[opened closed merged]
|
|
39
39
|
}.with_indifferent_access.freeze
|
|
40
|
+
EpicsTriagingForProjectImpossibleError = Class.new(StandardError)
|
|
40
41
|
|
|
41
42
|
def initialize(policies:, options:, network_adapter_class: DEFAULT_NETWORK_ADAPTER, graphql_network_adapter_class: DEFAULT_GRAPHQL_ADAPTER)
|
|
42
43
|
options.host_url = policies.delete(:host_url) { options.host_url }
|
|
@@ -62,6 +63,10 @@ module Gitlab
|
|
|
62
63
|
puts
|
|
63
64
|
|
|
64
65
|
resource_rules.each do |resource_type, resource|
|
|
66
|
+
if resource_type == 'epics' && options.source != :groups
|
|
67
|
+
raise(EpicsTriagingForProjectImpossibleError, "Epics can only be triaged at the group level. Please set the `--source groups` option.")
|
|
68
|
+
end
|
|
69
|
+
|
|
65
70
|
puts Gitlab::Triage::UI.header("Processing rules for #{resource_type}", char: '-')
|
|
66
71
|
puts
|
|
67
72
|
|
|
@@ -177,14 +182,23 @@ module Gitlab
|
|
|
177
182
|
ExpandCondition.perform(rule_conditions(rule)) do |conditions|
|
|
178
183
|
# retrieving the resources for every rule is inefficient
|
|
179
184
|
# however, previous rules may affect those upcoming
|
|
180
|
-
resources =
|
|
181
|
-
|
|
185
|
+
resources = []
|
|
186
|
+
|
|
187
|
+
if rule[:api] == 'graphql'
|
|
188
|
+
graphql_query = build_graphql_query(resource_type, conditions, true)
|
|
189
|
+
resources = graphql_network.query(graphql_query, source: source_full_path)
|
|
190
|
+
else
|
|
191
|
+
resources = network.query_api(build_get_url(resource_type, conditions))
|
|
192
|
+
iids = resources.pluck('iid').map(&:to_s)
|
|
193
|
+
|
|
194
|
+
graphql_query = build_graphql_query(resource_type, conditions)
|
|
195
|
+
graphql_resources = graphql_network.query(graphql_query, source: source_full_path, iids: iids) if graphql_query.any?
|
|
196
|
+
|
|
197
|
+
decorate_resources_with_graphql_data(resources, graphql_resources)
|
|
198
|
+
end
|
|
182
199
|
|
|
183
|
-
graphql_query = build_graphql_query(resource_type, conditions)
|
|
184
|
-
graphql_resources = graphql_network.query(graphql_query, source: options.source_id, iids: iids) if graphql_query.present?
|
|
185
200
|
# In some filters/actions we want to know which resource type it is
|
|
186
201
|
attach_resource_type(resources, resource_type)
|
|
187
|
-
decorate_resources_with_graphql_data(resources, graphql_resources)
|
|
188
202
|
|
|
189
203
|
puts "\n\n* Found #{resources.count} resources..."
|
|
190
204
|
print "* Filtering resources..."
|
|
@@ -199,10 +213,17 @@ module Gitlab
|
|
|
199
213
|
end
|
|
200
214
|
end
|
|
201
215
|
|
|
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
216
|
def attach_resource_type(resources, resource_type)
|
|
205
|
-
resources.each { |resource| resource[:type]
|
|
217
|
+
resources.each { |resource| resource[:type] = resource_type }
|
|
218
|
+
# TODO: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
219
|
+
# We should not overwrite the attribute here, but we need to
|
|
220
|
+
# fix it first. We should instead use something like
|
|
221
|
+
# gitlab_triage_resource_type so it won't conflict with the
|
|
222
|
+
# existing fields.
|
|
223
|
+
# And we need to retain the backward compatibility that using
|
|
224
|
+
# {{type}} will give us this value, rather than from the REST API,
|
|
225
|
+
# which will give us ISSUE from:
|
|
226
|
+
# https://gitlab.com/gitlab-org/gitlab/-/merge_requests/59648
|
|
206
227
|
end
|
|
207
228
|
|
|
208
229
|
def decorate_resources_with_graphql_data(resources, graphql_resources)
|
|
@@ -313,9 +334,24 @@ module Gitlab
|
|
|
313
334
|
).build
|
|
314
335
|
end
|
|
315
336
|
|
|
316
|
-
def build_graphql_query(resource_type, conditions)
|
|
337
|
+
def build_graphql_query(resource_type, conditions, graphql_only = false)
|
|
317
338
|
Gitlab::Triage::GraphqlQueries::QueryBuilder
|
|
318
|
-
.new(options.source, resource_type, conditions)
|
|
339
|
+
.new(options.source, resource_type, conditions, graphql_only: graphql_only)
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
def source_full_path
|
|
343
|
+
@source_full_path ||= fetch_source_full_path
|
|
344
|
+
end
|
|
345
|
+
|
|
346
|
+
def fetch_source_full_path
|
|
347
|
+
return options.source_id unless /\A\d+\z/.match?(options.source_id)
|
|
348
|
+
|
|
349
|
+
source_details = network.query_api(build_get_url(nil, {})).first
|
|
350
|
+
full_path = source_details['full_path'] || source_details['path_with_namespace']
|
|
351
|
+
|
|
352
|
+
raise ArgumentError, 'A source with given source_id was not found!' if full_path.blank?
|
|
353
|
+
|
|
354
|
+
full_path
|
|
319
355
|
end
|
|
320
356
|
end
|
|
321
357
|
end
|