Class: Gitlab::Triage::Action::WorkItem
- Inherits:
-
Base
- Object
- Base
- Gitlab::Triage::Action::WorkItem
show all
- Defined in:
- lib/gitlab/triage/action/work_item.rb
Overview
Applies work_items actions through the Work Items REST API update
endpoint (PATCH) rather than the issues note/quick-action path.
- labels -> features.labels.add_label_ids (resolved from names)
- assignees -> features.assignees.assignee_ids (resolved from usernames)
Missing labels or usernames stop the automation immediately (matching
the labels action behaviour on the issues type) rather than silently
applying nothing - which is especially important because clearing the
assignees array would unassign everyone.
Defined Under Namespace
Classes: Dry
Constant Summary
collapse
- AssigneeDoesntExistError =
Class.new(StandardError)
- UpdateNotAppliedError =
Class.new(StandardError)
Instance Attribute Summary
Attributes inherited from Base
#network, #policy
Instance Method Summary
collapse
Methods inherited from Base
#initialize
Instance Method Details
#act ⇒ Object
45
46
47
48
49
50
51
|
# File 'lib/gitlab/triage/action/work_item.rb', line 45
def act
return unless requested_labels.any? || requested_assignees.any?
policy.resources.each do |resource|
perform(resource)
end
end
|
#assignee_ids ⇒ Object
96
97
98
|
# File 'lib/gitlab/triage/action/work_item.rb', line 96
def assignee_ids
@assignee_ids ||= resolve_assignee_ids(requested_assignees)
end
|
#build_features(resource) ⇒ Object
64
65
66
67
68
69
70
71
|
# File 'lib/gitlab/triage/action/work_item.rb', line 64
def build_features(resource)
features = {}
features[:labels] = { add_label_ids: label_ids_to_add(resource) } if requested_labels.any?
features[:assignees] = { assignee_ids: assignee_ids } if requested_assignees.any?
features
end
|
#label_ids_to_add(resource) ⇒ Object
Label ids are namespace-specific, so resolve them against the
resource's own namespace and cache per scope - a group-spanning run
then makes one label lookup per distinct project/group.
89
90
91
92
93
94
|
# File 'lib/gitlab/triage/action/work_item.rb', line 89
def label_ids_to_add(resource)
scope = source.scope_for(resource)
@label_ids_by_scope ||= {}
@label_ids_by_scope[scope] ||= resolve_label_ids(requested_labels, scope)
end
|
#labels_url(scope) ⇒ Object
163
164
165
166
167
168
169
170
171
172
173
|
# File 'lib/gitlab/triage/action/work_item.rb', line 163
def labels_url(scope)
scope_source, scope_id = scope
UrlBuilders::UrlBuilder.new(
network_options: network.options,
source: scope_source,
source_id: scope_id,
resource_type: 'labels',
params: { per_page: 100 }
).build
end
|
55
56
57
58
59
60
61
62
|
# File 'lib/gitlab/triage/action/work_item.rb', line 55
def perform(resource)
features = build_features(resource)
return if features.empty?
response = source.update(resource, features)
verify_applied!(resource, response)
end
|
#requested_assignees ⇒ Object
77
78
79
|
# File 'lib/gitlab/triage/action/work_item.rb', line 77
def requested_assignees
@requested_assignees ||= Array(policy.actions[:assignees])
end
|
#requested_labels ⇒ Object
73
74
75
|
# File 'lib/gitlab/triage/action/work_item.rb', line 73
def requested_labels
@requested_labels ||= Array(policy.actions[:labels])
end
|
#resolve_assignee_ids(usernames) ⇒ Object
Resolve every requested username to an id. A missing username raises
rather than being dropped, because an empty assignee_ids array would
clear all assignees on the work item.
119
120
121
122
123
124
125
126
127
128
|
# File 'lib/gitlab/triage/action/work_item.rb', line 119
def resolve_assignee_ids(usernames)
return [] if usernames.empty?
usernames.map do |username|
id = resolve_user_id(username)
raise AssigneeDoesntExistError, "User `#{username}` doesn't exist!" unless id
id
end
end
|
#resolve_label_ids(names, scope) ⇒ Object
Resolve every requested label name to an id. Any name that does not
resolve raises, so the run stops instead of PATCHing a partial (or
empty) label set.
103
104
105
106
107
108
109
110
111
112
113
114
|
# File 'lib/gitlab/triage/action/work_item.rb', line 103
def resolve_label_ids(names, scope)
return [] if names.empty?
by_name = network.query_api(labels_url(scope)).index_by { |label| label[:name] }
names.map do |name|
label = by_name[name]
raise Resource::Label::LabelDoesntExistError, "Label `#{name}` doesn't exist!" unless label
label[:id]
end
end
|
#resolve_user_id(username) ⇒ Object
130
131
132
133
134
|
# File 'lib/gitlab/triage/action/work_item.rb', line 130
def resolve_user_id(username)
users = network.query_api(users_url(username))
users.first&.dig(:id)
end
|
#source ⇒ Object
81
82
83
84
|
# File 'lib/gitlab/triage/action/work_item.rb', line 81
def source
@source ||= Sources::WorkItemsRestSource.new(
network: network, options: network.options)
end
|
#users_url(username) ⇒ Object
175
176
177
178
179
|
# File 'lib/gitlab/triage/action/work_item.rb', line 175
def users_url(username)
options = network.options
"#{options.host_url}/api/#{options.api_version}/users?username=#{CGI.escape(username)}"
end
|
#verify_applied!(resource, response) ⇒ Object
The Work Items REST update endpoint can return success without
persisting a change when the token lacks permission. The response
echoes the resulting widgets, so confirm the requested ids landed and
raise otherwise rather than reporting a silent no-op as success.
140
141
142
143
|
# File 'lib/gitlab/triage/action/work_item.rb', line 140
def verify_applied!(resource, response)
verify_labels_applied!(resource, response) if requested_labels.any?
verify_assignees_applied!(resource, response) if requested_assignees.any?
end
|
#verify_assignees_applied!(resource, response) ⇒ Object
154
155
156
157
158
159
160
161
|
# File 'lib/gitlab/triage/action/work_item.rb', line 154
def verify_assignees_applied!(resource, response)
applied_ids = [*response.dig(:features, :assignees)].pluck(:id)
missing = assignee_ids - applied_ids
return if missing.empty?
raise UpdateNotAppliedError,
"Assignees were not applied to #{resource[:web_url]}; the token may lack permission."
end
|
#verify_labels_applied!(resource, response) ⇒ Object
145
146
147
148
149
150
151
152
|
# File 'lib/gitlab/triage/action/work_item.rb', line 145
def verify_labels_applied!(resource, response)
applied_ids = [*response.dig(:features, :labels, :labels)].pluck(:id)
missing = label_ids_to_add(resource) - applied_ids
return if missing.empty?
raise UpdateNotAppliedError,
"Labels were not applied to #{resource[:web_url]}; the token may lack permission."
end
|