gitlab-triage 1.53.0 → 1.54.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/Gemfile +3 -0
- data/Gemfile.lock +10 -9
- data/README.md +159 -1
- data/gitlab-triage.gemspec +1 -2
- data/lib/gitlab/triage/action/base.rb +62 -0
- data/lib/gitlab/triage/action/comment.rb +1 -9
- data/lib/gitlab/triage/action/comment_on_summary.rb +0 -6
- data/lib/gitlab/triage/action/issue.rb +31 -3
- data/lib/gitlab/triage/action/summarize.rb +21 -1
- data/lib/gitlab/triage/action/update.rb +432 -0
- data/lib/gitlab/triage/action/work_item.rb +0 -27
- data/lib/gitlab/triage/action.rb +18 -2
- data/lib/gitlab/triage/command_builders/cc_command_builder.rb +0 -4
- data/lib/gitlab/triage/entity_builders/issue_builder.rb +8 -0
- data/lib/gitlab/triage/entity_builders/issue_fields.rb +52 -0
- data/lib/gitlab/triage/entity_builders/summary_builder.rb +8 -0
- data/lib/gitlab/triage/graphql_network.rb +12 -2
- data/lib/gitlab/triage/network.rb +4 -0
- data/lib/gitlab/triage/network_adapters/httparty_adapter.rb +24 -0
- data/lib/gitlab/triage/network_adapters/test_adapter.rb +8 -0
- data/lib/gitlab/triage/policies/base_policy.rb +10 -2
- data/lib/gitlab/triage/policies/rule_policy.rb +18 -8
- data/lib/gitlab/triage/policies/summary_policy.rb +9 -0
- data/lib/gitlab/triage/rest_api_network.rb +22 -0
- data/lib/gitlab/triage/validators/policy_validator.rb +1 -3
- data/lib/gitlab/triage/version.rb +1 -1
- metadata +14 -10
- data/lib/gitlab/triage/command_builders/label_command_builder.rb +0 -42
- data/lib/gitlab/triage/command_builders/move_command_builder.rb +0 -21
- data/lib/gitlab/triage/command_builders/remove_label_command_builder.rb +0 -17
- data/lib/gitlab/triage/command_builders/status_command_builder.rb +0 -25
|
@@ -86,6 +86,30 @@ module Gitlab
|
|
|
86
86
|
}
|
|
87
87
|
end
|
|
88
88
|
|
|
89
|
+
def put(token, url, body)
|
|
90
|
+
response = HTTParty.put(
|
|
91
|
+
url,
|
|
92
|
+
body: body.to_json,
|
|
93
|
+
headers: {
|
|
94
|
+
'User-Agent' => USER_AGENT,
|
|
95
|
+
'Content-type' => 'application/json',
|
|
96
|
+
'PRIVATE-TOKEN' => token
|
|
97
|
+
}
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
raise_on_unauthorized_error!(response)
|
|
101
|
+
raise_on_internal_server_error!(response)
|
|
102
|
+
raise_on_too_many_requests!(response)
|
|
103
|
+
|
|
104
|
+
tracker&.record('PUT', url)
|
|
105
|
+
|
|
106
|
+
{
|
|
107
|
+
results: response.parsed_response,
|
|
108
|
+
ratelimit_remaining: response.headers['ratelimit-remaining'].to_i,
|
|
109
|
+
ratelimit_reset_at: Time.at(response.headers['ratelimit-reset'].to_i)
|
|
110
|
+
}
|
|
111
|
+
end
|
|
112
|
+
|
|
89
113
|
def delete(token, url)
|
|
90
114
|
response = HTTParty.delete(
|
|
91
115
|
url,
|
|
@@ -6,6 +6,11 @@ module Gitlab
|
|
|
6
6
|
class BasePolicy
|
|
7
7
|
InvalidPolicyError = Class.new(StandardError)
|
|
8
8
|
|
|
9
|
+
UPDATE_ACTION_KEYS = %i[
|
|
10
|
+
labels remove_labels assignees reviewers remove_assignees remove_reviewers
|
|
11
|
+
milestone due_date weight health_status title status discussion_locked move
|
|
12
|
+
].freeze
|
|
13
|
+
|
|
9
14
|
attr_reader :type, :policy_spec, :resources, :network
|
|
10
15
|
attr_accessor :summary
|
|
11
16
|
|
|
@@ -55,8 +60,11 @@ module Gitlab
|
|
|
55
60
|
end
|
|
56
61
|
|
|
57
62
|
def comment?
|
|
58
|
-
|
|
59
|
-
|
|
63
|
+
actions.key?(:comment) || actions.key?(:mention)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def update?
|
|
67
|
+
(actions.keys.map(&:to_sym) & UPDATE_ACTION_KEYS).any?
|
|
60
68
|
end
|
|
61
69
|
|
|
62
70
|
def issue?
|
|
@@ -9,27 +9,37 @@ module Gitlab
|
|
|
9
9
|
module Policies
|
|
10
10
|
class RulePolicy < BasePolicy
|
|
11
11
|
# Build a summary from a single rule policy
|
|
12
|
+
#
|
|
13
|
+
# The builder is kept for the life of the policy. Every action that asks
|
|
14
|
+
# for it gets the same one, so the title and description templates are
|
|
15
|
+
# evaluated once for the run rather than once per action.
|
|
12
16
|
def build_summary
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
EntityBuilders::SummaryBuilder.new(
|
|
17
|
+
@build_summary ||= EntityBuilders::SummaryBuilder.new(
|
|
16
18
|
type: type,
|
|
17
19
|
policy_spec: policy_spec,
|
|
18
|
-
action:
|
|
20
|
+
action: actions.fetch(:summarize, {}),
|
|
19
21
|
resources: resources,
|
|
20
22
|
network: network)
|
|
21
23
|
end
|
|
22
24
|
|
|
25
|
+
# The builder for one resource, kept for the life of the policy the same
|
|
26
|
+
# way build_summary is. Keyed on the resource itself, which the policy
|
|
27
|
+
# holds for the whole run, so two actions handed the same resource share
|
|
28
|
+
# one builder.
|
|
23
29
|
def build_issue(resource)
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
EntityBuilders::IssueBuilder.new(
|
|
30
|
+
issue_builders[resource] ||= EntityBuilders::IssueBuilder.new(
|
|
27
31
|
type: type,
|
|
28
32
|
policy_spec: policy_spec,
|
|
29
|
-
action:
|
|
33
|
+
action: actions.fetch(:issue, {}),
|
|
30
34
|
resource: resource,
|
|
31
35
|
network: network)
|
|
32
36
|
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
def issue_builders
|
|
41
|
+
@issue_builders ||= {}.compare_by_identity
|
|
42
|
+
end
|
|
33
43
|
end
|
|
34
44
|
end
|
|
35
45
|
end
|
|
@@ -8,7 +8,16 @@ module Gitlab
|
|
|
8
8
|
module Policies
|
|
9
9
|
class SummaryPolicy < BasePolicy
|
|
10
10
|
# Build a summary from several rules policies
|
|
11
|
+
#
|
|
12
|
+
# Kept for the life of the policy, like the single-rule version, so the
|
|
13
|
+
# child summaries are built once for the run.
|
|
11
14
|
def build_summary
|
|
15
|
+
@build_summary ||= build_combined_summary
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def build_combined_summary
|
|
12
21
|
action = actions[:summarize]
|
|
13
22
|
child_summaries = resources.map do |inner_policy_spec, inner_resources|
|
|
14
23
|
Policies::RulePolicy.new(
|
|
@@ -112,6 +112,28 @@ module Gitlab
|
|
|
112
112
|
end
|
|
113
113
|
end
|
|
114
114
|
|
|
115
|
+
def put_api(url, body)
|
|
116
|
+
response = execute_with_retry(
|
|
117
|
+
exception_types: [Net::ReadTimeout, Errors::Network::InternalServerError],
|
|
118
|
+
backoff_exceptions: Errors::Network::TooManyRequests, debug: options.debug) do
|
|
119
|
+
puts Gitlab::Triage::UI.debug "put_api: #{url}" if options.debug
|
|
120
|
+
|
|
121
|
+
@adapter.put(token, url, body)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
rate_limit_debug(response) if options.debug
|
|
125
|
+
rate_limit_wait(response)
|
|
126
|
+
|
|
127
|
+
results = response.delete(:results)
|
|
128
|
+
|
|
129
|
+
case results
|
|
130
|
+
when Hash
|
|
131
|
+
results.with_indifferent_access
|
|
132
|
+
else
|
|
133
|
+
raise_unexpected_response(results)
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
115
137
|
def delete_api(url)
|
|
116
138
|
response = execute_with_retry(
|
|
117
139
|
exception_types: [Net::ReadTimeout, Errors::Network::InternalServerError],
|
|
@@ -17,9 +17,7 @@ module Gitlab
|
|
|
17
17
|
'Use the issues policy type for comment actions.'
|
|
18
18
|
|
|
19
19
|
# Action keys Action.actions_for dispatches for work_items policies.
|
|
20
|
-
#
|
|
21
|
-
# comment fallback for unrecognized keys, so anything outside this
|
|
22
|
-
# list would silently do nothing - reject it up front instead.
|
|
20
|
+
# Anything outside this list would silently do nothing, so reject it up front.
|
|
23
21
|
SUPPORTED_WORK_ITEM_ACTIONS = %i[labels assignees summarize comment_on_summary].freeze
|
|
24
22
|
|
|
25
23
|
def initialize(resource_rules)
|
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.54.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- GitLab
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-09-24 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activesupport
|
|
@@ -76,16 +76,22 @@ dependencies:
|
|
|
76
76
|
name: httparty
|
|
77
77
|
requirement: !ruby/object:Gem::Requirement
|
|
78
78
|
requirements:
|
|
79
|
-
- - "
|
|
79
|
+
- - ">="
|
|
80
80
|
- !ruby/object:Gem::Version
|
|
81
|
-
version: 0.
|
|
81
|
+
version: 0.21.0
|
|
82
|
+
- - "<"
|
|
83
|
+
- !ruby/object:Gem::Version
|
|
84
|
+
version: '1.0'
|
|
82
85
|
type: :runtime
|
|
83
86
|
prerelease: false
|
|
84
87
|
version_requirements: !ruby/object:Gem::Requirement
|
|
85
88
|
requirements:
|
|
86
|
-
- - "
|
|
89
|
+
- - ">="
|
|
87
90
|
- !ruby/object:Gem::Version
|
|
88
|
-
version: 0.
|
|
91
|
+
version: 0.21.0
|
|
92
|
+
- - "<"
|
|
93
|
+
- !ruby/object:Gem::Version
|
|
94
|
+
version: '1.0'
|
|
89
95
|
- !ruby/object:Gem::Dependency
|
|
90
96
|
name: gitlab-dangerfiles
|
|
91
97
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -239,6 +245,7 @@ files:
|
|
|
239
245
|
- lib/gitlab/triage/action/delete.rb
|
|
240
246
|
- lib/gitlab/triage/action/issue.rb
|
|
241
247
|
- lib/gitlab/triage/action/summarize.rb
|
|
248
|
+
- lib/gitlab/triage/action/update.rb
|
|
242
249
|
- lib/gitlab/triage/action/work_item.rb
|
|
243
250
|
- lib/gitlab/triage/action/work_item_status.rb
|
|
244
251
|
- lib/gitlab/triage/api_observability.rb
|
|
@@ -249,13 +256,10 @@ files:
|
|
|
249
256
|
- lib/gitlab/triage/command_builders/base_command_builder.rb
|
|
250
257
|
- lib/gitlab/triage/command_builders/cc_command_builder.rb
|
|
251
258
|
- lib/gitlab/triage/command_builders/comment_command_builder.rb
|
|
252
|
-
- lib/gitlab/triage/command_builders/label_command_builder.rb
|
|
253
|
-
- lib/gitlab/triage/command_builders/move_command_builder.rb
|
|
254
|
-
- lib/gitlab/triage/command_builders/remove_label_command_builder.rb
|
|
255
|
-
- lib/gitlab/triage/command_builders/status_command_builder.rb
|
|
256
259
|
- lib/gitlab/triage/command_builders/text_content_builder.rb
|
|
257
260
|
- lib/gitlab/triage/engine.rb
|
|
258
261
|
- lib/gitlab/triage/entity_builders/issue_builder.rb
|
|
262
|
+
- lib/gitlab/triage/entity_builders/issue_fields.rb
|
|
259
263
|
- lib/gitlab/triage/entity_builders/summary_builder.rb
|
|
260
264
|
- lib/gitlab/triage/errors.rb
|
|
261
265
|
- lib/gitlab/triage/errors/network.rb
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative 'base_command_builder'
|
|
4
|
-
|
|
5
|
-
module Gitlab
|
|
6
|
-
module Triage
|
|
7
|
-
module CommandBuilders
|
|
8
|
-
class LabelCommandBuilder < BaseCommandBuilder
|
|
9
|
-
def build_command
|
|
10
|
-
ensure_labels_exist!
|
|
11
|
-
|
|
12
|
-
super
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
private
|
|
16
|
-
|
|
17
|
-
def ensure_labels_exist!
|
|
18
|
-
items.each do |label|
|
|
19
|
-
source_id_key = resource.key?(:group_id) ? :group_id : :project_id
|
|
20
|
-
label_opts = {
|
|
21
|
-
source_id_key => resource[source_id_key],
|
|
22
|
-
name: label
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
unless Resource::Label.new(label_opts, network: network).exist?
|
|
26
|
-
raise Resource::Label::LabelDoesntExistError,
|
|
27
|
-
"Label `#{label}` doesn't exist!"
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
def slash_command_string
|
|
33
|
-
"/label"
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
def format_item(item)
|
|
37
|
-
"~\"#{item}\""
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
end
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative 'base_command_builder'
|
|
4
|
-
|
|
5
|
-
module Gitlab
|
|
6
|
-
module Triage
|
|
7
|
-
module CommandBuilders
|
|
8
|
-
class MoveCommandBuilder < BaseCommandBuilder
|
|
9
|
-
private
|
|
10
|
-
|
|
11
|
-
def slash_command_string
|
|
12
|
-
"/move"
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def format_item(item)
|
|
16
|
-
item
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
end
|
|
21
|
-
end
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative 'base_command_builder'
|
|
4
|
-
|
|
5
|
-
module Gitlab
|
|
6
|
-
module Triage
|
|
7
|
-
module CommandBuilders
|
|
8
|
-
class RemoveLabelCommandBuilder < LabelCommandBuilder
|
|
9
|
-
private
|
|
10
|
-
|
|
11
|
-
def slash_command_string
|
|
12
|
-
'/unlabel'
|
|
13
|
-
end
|
|
14
|
-
end
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
end
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative 'base_command_builder'
|
|
4
|
-
|
|
5
|
-
module Gitlab
|
|
6
|
-
module Triage
|
|
7
|
-
module CommandBuilders
|
|
8
|
-
class StatusCommandBuilder < BaseCommandBuilder
|
|
9
|
-
private
|
|
10
|
-
|
|
11
|
-
def separator
|
|
12
|
-
''
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def slash_command_string
|
|
16
|
-
"/"
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def format_item(item)
|
|
20
|
-
item
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
end
|