gitlab-triage 1.14.3 → 1.19.0
Sign up to get free protection for your applications and to get access to all the features.
- 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/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/resource/shared/issuable.rb +2 -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 -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: 75bd839eb28f1b1feee624b5591b623966520685ecf9577d66bd08eb68e25227
|
4
|
+
data.tar.gz: 6fe5843105229f7488bc6c5e54fb58269a928bd80df3b579163636639cd64f6b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d0f70cecc7cd0315143783856920a36970f63d834838ad26ca3210e2077f60859a54ae1208cb1c21d7ead6c718cae36900ad47724e43cbb3c1c3ad095441d715
|
7
|
+
data.tar.gz: 9044cb1de497e46b1b24f0e8ddf73da2fdd9d1dde178c4c0b1a5ff62e599c0581cb965f946ea14802a861180c9f37f72ba84fc972545b759644b528bb1865204
|
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
|