gitlab-triage 1.53.1 → 1.55.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 +4 -3
- data/README.md +173 -5
- 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 +36 -3
- data/lib/gitlab/triage/action/summarize.rb +26 -1
- data/lib/gitlab/triage/action/update.rb +454 -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/engine.rb +13 -4
- data/lib/gitlab/triage/entity_builders/issue_builder.rb +8 -0
- data/lib/gitlab/triage/entity_builders/issue_fields.rb +65 -0
- data/lib/gitlab/triage/entity_builders/summary_builder.rb +8 -0
- data/lib/gitlab/triage/graphql_network.rb +22 -5
- data/lib/gitlab/triage/graphql_queries/query_builder.rb +46 -3
- 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 +4 -6
- 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
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4c82752f4e75557f79131d794be458ada5ea59f6c6e128a9e9a1f85d9228b04c
|
|
4
|
+
data.tar.gz: e7b98029e513b4990e61a546b0d60d347468857a5a713ad571fec55df7015302
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1799682dbf8208cf4bfa5609d3e5fffc99726f2f5a7e8425c52a6a900bc525cf4fb540243ddc2c514a7e0110f55f5fdf008019281fe4afb057937ee391cbd101
|
|
7
|
+
data.tar.gz: 76dc04fa7184e8fb766b7861879e9578b2c0adeb4177887f4fd034f40510f1b02191c10912917a9ecfd308838d11c1bd1e9714d5286fbbb8dfd037d0a259f73b
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
gitlab-triage (1.
|
|
4
|
+
gitlab-triage (1.55.0)
|
|
5
5
|
activesupport (>= 5.1)
|
|
6
6
|
globalid (~> 1.0, >= 1.0.1)
|
|
7
7
|
graphql (< 2.1.0)
|
|
@@ -58,7 +58,7 @@ GEM
|
|
|
58
58
|
danger
|
|
59
59
|
gitlab (~> 4.2, >= 4.2.0)
|
|
60
60
|
diff-lcs (1.5.1)
|
|
61
|
-
drb (2.2.
|
|
61
|
+
drb (2.2.3)
|
|
62
62
|
faraday (2.9.1)
|
|
63
63
|
faraday-net_http (>= 2.0, < 3.2)
|
|
64
64
|
faraday-http-cache (2.5.1)
|
|
@@ -124,7 +124,7 @@ GEM
|
|
|
124
124
|
lumberjack (1.2.10)
|
|
125
125
|
method_source (1.1.0)
|
|
126
126
|
mini_mime (1.1.5)
|
|
127
|
-
minitest (5.
|
|
127
|
+
minitest (5.26.1)
|
|
128
128
|
multi_xml (0.6.0)
|
|
129
129
|
mutex_m (0.2.0)
|
|
130
130
|
nap (1.1.0)
|
|
@@ -230,6 +230,7 @@ DEPENDENCIES
|
|
|
230
230
|
gitlab-triage!
|
|
231
231
|
guard-rspec (~> 4.7.3)
|
|
232
232
|
lefthook (~> 1.3)
|
|
233
|
+
minitest (= 5.26.1)
|
|
233
234
|
rake (~> 13.2)
|
|
234
235
|
rspec (~> 3.8)
|
|
235
236
|
webmock (~> 3.4)
|
data/README.md
CHANGED
|
@@ -903,6 +903,15 @@ Used to declare an action to be carried out on a resource if **all** conditions
|
|
|
903
903
|
Available action types:
|
|
904
904
|
- [`labels` action](#labels-action)
|
|
905
905
|
- [`remove_labels` action](#remove-labels-action)
|
|
906
|
+
- [`assignees` action](#assignees-action)
|
|
907
|
+
- [`reviewers` action](#reviewers-action)
|
|
908
|
+
- [`remove_assignees` and `remove_reviewers` actions](#remove-assignees-and-remove-reviewers-actions)
|
|
909
|
+
- [`milestone` action](#milestone-action)
|
|
910
|
+
- [`due_date` action](#due-date-action)
|
|
911
|
+
- [`weight` action](#weight-action)
|
|
912
|
+
- [`health_status` action](#health-status-action)
|
|
913
|
+
- [`title` action](#title-action)
|
|
914
|
+
- [`discussion_locked` action](#discussion-locked-action)
|
|
906
915
|
- [`status` action](#status-action)
|
|
907
916
|
- [`work_item_status` action](#work-item-status-action)
|
|
908
917
|
- [`mention` action](#mention-action)
|
|
@@ -919,7 +928,9 @@ Available action types:
|
|
|
919
928
|
|
|
920
929
|
Adds a number of labels to the resource.
|
|
921
930
|
|
|
922
|
-
Accepts an array of strings. Each element is the name of a label to add.
|
|
931
|
+
Accepts an array of strings. Each element is the name of a label to add. An
|
|
932
|
+
element may interpolate to a comma-separated list, which is expanded into one
|
|
933
|
+
label per value.
|
|
923
934
|
|
|
924
935
|
If any of the labels doesn't exist, the automation will stop immediately so
|
|
925
936
|
that if a label is renamed or deleted, you'll have to explicitly update or remove
|
|
@@ -934,11 +945,23 @@ actions:
|
|
|
934
945
|
- awaiting feedback
|
|
935
946
|
```
|
|
936
947
|
|
|
948
|
+
Each entry supports Ruby string interpolation. An entry that interpolates to an
|
|
949
|
+
empty string is dropped, so a label can be made conditional on the resource:
|
|
950
|
+
|
|
951
|
+
```yml
|
|
952
|
+
actions:
|
|
953
|
+
labels:
|
|
954
|
+
- Community contribution
|
|
955
|
+
- "#{'1st contribution' if first_contribution?}"
|
|
956
|
+
```
|
|
957
|
+
|
|
937
958
|
##### Remove labels action
|
|
938
959
|
|
|
939
960
|
Removes a number of labels from the resource.
|
|
940
961
|
|
|
941
|
-
Accepts an array of strings. Each element is the name of a label to remove.
|
|
962
|
+
Accepts an array of strings. Each element is the name of a label to remove. An
|
|
963
|
+
element may interpolate to a comma-separated list, which is expanded into one
|
|
964
|
+
label per value.
|
|
942
965
|
|
|
943
966
|
If any of the labels doesn't exist, the automation will stop immediately so
|
|
944
967
|
that if a label is renamed or deleted, you'll have to explicitly update or remove
|
|
@@ -953,6 +976,142 @@ actions:
|
|
|
953
976
|
- awaiting feedback
|
|
954
977
|
```
|
|
955
978
|
|
|
979
|
+
##### Assignees action
|
|
980
|
+
|
|
981
|
+
Sets the assignees on the resource. Applies to issues and merge requests.
|
|
982
|
+
|
|
983
|
+
Accepts an array of usernames (without the leading `@`). If any username does not exist, the automation stops immediately.
|
|
984
|
+
|
|
985
|
+
Setting an empty array (`[]`) removes all assignees.
|
|
986
|
+
|
|
987
|
+
Example:
|
|
988
|
+
|
|
989
|
+
```yml
|
|
990
|
+
actions:
|
|
991
|
+
assignees:
|
|
992
|
+
- username1
|
|
993
|
+
- username2
|
|
994
|
+
```
|
|
995
|
+
|
|
996
|
+
##### Reviewers action
|
|
997
|
+
|
|
998
|
+
Sets the reviewers on the resource. Applies to merge requests only.
|
|
999
|
+
|
|
1000
|
+
Accepts an array of usernames (without the leading `@`). If any username does not exist, the automation stops immediately.
|
|
1001
|
+
|
|
1002
|
+
Setting an empty array (`[]`) removes all reviewers.
|
|
1003
|
+
|
|
1004
|
+
Example:
|
|
1005
|
+
|
|
1006
|
+
```yml
|
|
1007
|
+
actions:
|
|
1008
|
+
reviewers:
|
|
1009
|
+
- username1
|
|
1010
|
+
```
|
|
1011
|
+
|
|
1012
|
+
Both actions replace the whole list rather than adding to it, and both support Ruby string interpolation in each entry. An entry that interpolates to a comma-separated list is expanded, so a policy can compute the list from the resource.
|
|
1013
|
+
|
|
1014
|
+
Entries that interpolate to nothing are dropped. If every entry drops out, the action is skipped rather than clearing the list, so a conditional assignee cannot unassign by accident. Only a literal `[]` clears.
|
|
1015
|
+
|
|
1016
|
+
##### Remove assignees and remove reviewers actions
|
|
1017
|
+
|
|
1018
|
+
Removes the named users and keeps the rest. `remove_assignees` applies to issues and merge requests, `remove_reviewers` to merge requests only.
|
|
1019
|
+
|
|
1020
|
+
Accepts an array of usernames (without the leading `@`), with the same interpolation and comma expansion as the actions above. Names that are not on the resource are ignored, and a resource with nobody assigned is left alone.
|
|
1021
|
+
|
|
1022
|
+
Example:
|
|
1023
|
+
|
|
1024
|
+
```yml
|
|
1025
|
+
actions:
|
|
1026
|
+
remove_reviewers:
|
|
1027
|
+
- some-bot
|
|
1028
|
+
```
|
|
1029
|
+
|
|
1030
|
+
Prefer these over computing the surviving list yourself: they read the ids straight off the resource, so they cost no extra API call and cannot clear the list by accident.
|
|
1031
|
+
|
|
1032
|
+
##### Milestone action
|
|
1033
|
+
|
|
1034
|
+
Sets the milestone on the resource. Applies to issues and merge requests.
|
|
1035
|
+
|
|
1036
|
+
Accepts a string containing the milestone title. If the milestone does not exist, the automation stops immediately.
|
|
1037
|
+
|
|
1038
|
+
Supports Ruby string interpolation in the value.
|
|
1039
|
+
|
|
1040
|
+
Example:
|
|
1041
|
+
|
|
1042
|
+
```yml
|
|
1043
|
+
actions:
|
|
1044
|
+
milestone: "17.0"
|
|
1045
|
+
```
|
|
1046
|
+
|
|
1047
|
+
##### Due date action
|
|
1048
|
+
|
|
1049
|
+
Sets the due date on the resource. Applies to issues only. The epics endpoint takes `due_date_fixed` and `due_date_is_fixed` instead, and merge requests have no due date.
|
|
1050
|
+
|
|
1051
|
+
Accepts a string in `YYYY-MM-DD` format. Supports Ruby string interpolation.
|
|
1052
|
+
|
|
1053
|
+
Example:
|
|
1054
|
+
|
|
1055
|
+
```yml
|
|
1056
|
+
actions:
|
|
1057
|
+
due_date: "#{(Date.today + 7).iso8601}"
|
|
1058
|
+
```
|
|
1059
|
+
|
|
1060
|
+
##### Weight action
|
|
1061
|
+
|
|
1062
|
+
Sets the weight on an issue. Issues only.
|
|
1063
|
+
|
|
1064
|
+
Accepts an integer, or `~` (YAML null) to clear the weight.
|
|
1065
|
+
|
|
1066
|
+
Example:
|
|
1067
|
+
|
|
1068
|
+
```yml
|
|
1069
|
+
actions:
|
|
1070
|
+
weight: 3
|
|
1071
|
+
```
|
|
1072
|
+
|
|
1073
|
+
##### Health status action
|
|
1074
|
+
|
|
1075
|
+
Sets the health status on an issue. Issues only.
|
|
1076
|
+
|
|
1077
|
+
Accepts one of `on_track`, `needs_attention`, or `at_risk`, or `~` (YAML null) to clear it.
|
|
1078
|
+
|
|
1079
|
+
This one goes through the work item GraphQL API, because the REST issue update
|
|
1080
|
+
endpoint does not accept a health status parameter.
|
|
1081
|
+
|
|
1082
|
+
Example:
|
|
1083
|
+
|
|
1084
|
+
```yml
|
|
1085
|
+
actions:
|
|
1086
|
+
health_status: needs_attention
|
|
1087
|
+
```
|
|
1088
|
+
|
|
1089
|
+
##### Title action
|
|
1090
|
+
|
|
1091
|
+
Updates the title of the resource.
|
|
1092
|
+
|
|
1093
|
+
Accepts a string. Supports Ruby string interpolation.
|
|
1094
|
+
|
|
1095
|
+
Example:
|
|
1096
|
+
|
|
1097
|
+
```yml
|
|
1098
|
+
actions:
|
|
1099
|
+
title: "#{resource[:title]} [archived]"
|
|
1100
|
+
```
|
|
1101
|
+
|
|
1102
|
+
##### Discussion locked action
|
|
1103
|
+
|
|
1104
|
+
Locks or unlocks discussions on the resource. Applies to issues and merge requests.
|
|
1105
|
+
|
|
1106
|
+
Accepts `true` or `false`.
|
|
1107
|
+
|
|
1108
|
+
Example:
|
|
1109
|
+
|
|
1110
|
+
```yml
|
|
1111
|
+
actions:
|
|
1112
|
+
discussion_locked: true
|
|
1113
|
+
```
|
|
1114
|
+
|
|
956
1115
|
##### Status action
|
|
957
1116
|
|
|
958
1117
|
Changes the open or closed state of the resource.
|
|
@@ -999,7 +1158,7 @@ actions:
|
|
|
999
1158
|
|
|
1000
1159
|
##### Mention action
|
|
1001
1160
|
|
|
1002
|
-
Mentions a number of users.
|
|
1161
|
+
Mentions a number of users. The usernames are appended to the comment body as `@username` references. Prior to 1.54.0 they were emitted as `/cc @username`; the mention effect is identical but the rendered text differs.
|
|
1003
1162
|
|
|
1004
1163
|
Accepts an array of strings. Each element is the username of a user to mention.
|
|
1005
1164
|
|
|
@@ -1018,6 +1177,9 @@ Moves an issue (merge request is not supported yet) to the specified project.
|
|
|
1018
1177
|
|
|
1019
1178
|
Accepts a string containing the target project path.
|
|
1020
1179
|
|
|
1180
|
+
When combined with other update actions, the move runs last, because it gives the
|
|
1181
|
+
issue a new internal ID at the destination.
|
|
1182
|
+
|
|
1021
1183
|
Example:
|
|
1022
1184
|
|
|
1023
1185
|
```yml
|
|
@@ -1188,7 +1350,10 @@ Accepts a hash of fields.
|
|
|
1188
1350
|
| `destination` | integer or string | The project ID or path to create the generated issue in | no | no | no | source project |
|
|
1189
1351
|
| `item` | string | Template representing each triaged resource | no | yes | yes | |
|
|
1190
1352
|
| `summary` | string | The description of the generated issue | no | Only `{{title}}`, `{{items}}`, `{{type}}` | yes | |
|
|
1353
|
+
| `labels` | array of strings | Labels to add to the generated issue. An element may interpolate to a comma-separated list, which is expanded into one label per value | no | yes | yes | |
|
|
1354
|
+
| `assignees` | array of strings | Usernames to assign to the generated issue. An element may interpolate to a comma-separated list, which is expanded into one assignee per value | no | yes | yes | |
|
|
1191
1355
|
| `redact_confidential_resources` | boolean | Whether redact fields for confidential resources | no | no | no | true |
|
|
1356
|
+
| `confidential` | boolean or string | Create the issue confidential. A string is interpolated and counts as true when it evaluates to `true` | no | no | yes | false |
|
|
1192
1357
|
|
|
1193
1358
|
The following placeholders are supported for `summary`:
|
|
1194
1359
|
|
|
@@ -1208,8 +1373,8 @@ The following placeholders are supported for `summary`:
|
|
|
1208
1373
|
> - `redact_confidential_resources` defaults to `true`, so fields on
|
|
1209
1374
|
> confidential resources will be converted to `(confidential)` except for
|
|
1210
1375
|
> `{{web_url}}`. Setting it to `false` will reveal the confidential fields.
|
|
1211
|
-
> This
|
|
1212
|
-
>
|
|
1376
|
+
> This is useful when the summary is itself `confidential`, or if we're
|
|
1377
|
+
> posting to another private project (not implemented yet).
|
|
1213
1378
|
|
|
1214
1379
|
Example:
|
|
1215
1380
|
|
|
@@ -1322,7 +1487,10 @@ Accepts a hash of fields.
|
|
|
1322
1487
|
| `title` | string | The title of the generated issue | yes | yes | yes | |
|
|
1323
1488
|
| `destination` | integer or string | The project ID or path to create the generated issue in | no | no | no | source project |
|
|
1324
1489
|
| `description` | string | The description of the generated issue | no | yes | yes | |
|
|
1490
|
+
| `labels` | array of strings | Labels to add to the generated issue. An element may interpolate to a comma-separated list, which is expanded into one label per value | no | yes | yes | |
|
|
1491
|
+
| `assignees` | array of strings | Usernames to assign to the generated issue. An element may interpolate to a comma-separated list, which is expanded into one assignee per value | no | yes | yes | |
|
|
1325
1492
|
| `redact_confidential_resources` | boolean | Whether redact fields for confidential resources | no | no | no | true |
|
|
1493
|
+
| `confidential` | boolean or string | Create the issue confidential. A string is interpolated and counts as true when it evaluates to `true` | no | no | yes | false |
|
|
1326
1494
|
|
|
1327
1495
|
The placeholders available in `title` and `destination` are the properties of the resource being used to generate the issue.
|
|
1328
1496
|
|
|
@@ -1,15 +1,77 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'cgi'
|
|
4
|
+
|
|
5
|
+
require_relative '../url_builders/url_builder'
|
|
6
|
+
require_relative '../resource/label'
|
|
7
|
+
|
|
3
8
|
module Gitlab
|
|
4
9
|
module Triage
|
|
5
10
|
module Action
|
|
6
11
|
class Base
|
|
12
|
+
AssigneeDoesntExistError = Class.new(StandardError)
|
|
13
|
+
MilestoneDoesntExistError = Class.new(StandardError)
|
|
14
|
+
|
|
7
15
|
attr_reader :policy, :network
|
|
8
16
|
|
|
9
17
|
def initialize(**args)
|
|
10
18
|
@policy = args[:policy]
|
|
11
19
|
@network = args[:network]
|
|
12
20
|
end
|
|
21
|
+
|
|
22
|
+
# Action.process calls this on every active action before any of them
|
|
23
|
+
# writes. Actions with nothing to look up have nothing to check.
|
|
24
|
+
def verify!; end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
def ensure_labels_exist!(labels, source_id, source_id_key: :project_id)
|
|
29
|
+
labels.each do |label|
|
|
30
|
+
label_opts = { source_id_key => source_id, name: label }
|
|
31
|
+
next if Resource::Label.new(label_opts, network: network).exist?
|
|
32
|
+
|
|
33
|
+
raise Resource::Label::LabelDoesntExistError, "Label `#{label}` doesn't exist!"
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def resolve_user_ids(usernames, error_class = AssigneeDoesntExistError)
|
|
38
|
+
Array(usernames).map do |username|
|
|
39
|
+
id = resolve_user_id(username)
|
|
40
|
+
raise error_class, "User `#{username}` doesn't exist!" unless id
|
|
41
|
+
|
|
42
|
+
id
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
alias_method :resolve_assignee_ids, :resolve_user_ids
|
|
46
|
+
|
|
47
|
+
def resolve_user_id(username)
|
|
48
|
+
users = network.query_api_cached(users_url(username))
|
|
49
|
+
users.first&.dig(:id)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def users_url(username)
|
|
53
|
+
opts = network.options
|
|
54
|
+
"#{opts.host_url}/api/#{opts.api_version}/users?username=#{CGI.escape(username)}"
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# include_ancestors matches the /milestone quick action, which also resolves
|
|
58
|
+
# milestones defined on a parent group.
|
|
59
|
+
def milestones_url(source_id, title, source: 'projects')
|
|
60
|
+
UrlBuilders::UrlBuilder.new(
|
|
61
|
+
network_options: network.options,
|
|
62
|
+
source: source,
|
|
63
|
+
source_id: source_id,
|
|
64
|
+
resource_type: 'milestones',
|
|
65
|
+
params: { title: title, include_ancestors: true }
|
|
66
|
+
).build
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def resolve_milestone_id(source_id, title, source: 'projects')
|
|
70
|
+
milestone = network.query_api_cached(milestones_url(source_id, title, source: source)).first
|
|
71
|
+
raise MilestoneDoesntExistError, "Milestone `#{title}` doesn't exist!" unless milestone
|
|
72
|
+
|
|
73
|
+
milestone[:id]
|
|
74
|
+
end
|
|
13
75
|
end
|
|
14
76
|
end
|
|
15
77
|
end
|
|
@@ -3,11 +3,7 @@
|
|
|
3
3
|
require_relative 'base'
|
|
4
4
|
require_relative '../command_builders/text_content_builder'
|
|
5
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
6
|
require_relative '../command_builders/cc_command_builder'
|
|
9
|
-
require_relative '../command_builders/status_command_builder'
|
|
10
|
-
require_relative '../command_builders/move_command_builder'
|
|
11
7
|
|
|
12
8
|
module Gitlab
|
|
13
9
|
module Triage
|
|
@@ -51,11 +47,7 @@ module Gitlab
|
|
|
51
47
|
network: network,
|
|
52
48
|
redact_confidentials: policy.actions.fetch(:redact_confidential_resources, true)
|
|
53
49
|
).build_command,
|
|
54
|
-
CommandBuilders::
|
|
55
|
-
CommandBuilders::RemoveLabelCommandBuilder.new(policy.actions[:remove_labels], resource: resource, network: network).build_command,
|
|
56
|
-
CommandBuilders::CcCommandBuilder.new(policy.actions[:mention]).build_command,
|
|
57
|
-
CommandBuilders::MoveCommandBuilder.new(policy.actions[:move]).build_command,
|
|
58
|
-
CommandBuilders::StatusCommandBuilder.new(policy.actions[:status]).build_command
|
|
50
|
+
CommandBuilders::CcCommandBuilder.new(policy.actions[:mention]).build_command
|
|
59
51
|
]
|
|
60
52
|
).build_command
|
|
61
53
|
end
|
|
@@ -2,12 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
require_relative 'base'
|
|
4
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
5
|
|
|
12
6
|
module Gitlab
|
|
13
7
|
module Triage
|
|
@@ -19,11 +19,34 @@ module Gitlab
|
|
|
19
19
|
puts ">>>"
|
|
20
20
|
puts "* Project: #{issue.destination || resource[policy.source_id_sym]}"
|
|
21
21
|
puts "* Title: #{issue.title}"
|
|
22
|
+
puts "* Labels: #{issue.labels.join(', ')}" if issue.labels.any?
|
|
23
|
+
puts "* Assignees: #{issue.assignee_usernames.join(', ')}" if issue.assignee_usernames&.any?
|
|
24
|
+
puts "* Due date: #{issue.due_date}" if issue.due_date
|
|
25
|
+
puts "* Milestone: #{issue.milestone_title}" if issue.milestone_title
|
|
26
|
+
puts "* Confidential: true" if issue.confidential?
|
|
22
27
|
puts "* Description: #{issue.description}"
|
|
23
28
|
puts ">>>"
|
|
24
29
|
end
|
|
25
30
|
end
|
|
26
31
|
|
|
32
|
+
# Resolving the assignees and milestone here too keeps a rule naming an
|
|
33
|
+
# unknown one from failing after Comment has already posted.
|
|
34
|
+
def verify!
|
|
35
|
+
policy.resources.each do |resource|
|
|
36
|
+
issue = policy.build_issue(resource)
|
|
37
|
+
next unless issue.valid?
|
|
38
|
+
|
|
39
|
+
destination_id = issue.destination || resource[policy.source_id_sym]
|
|
40
|
+
|
|
41
|
+
ensure_labels_exist!(issue.labels, destination_id)
|
|
42
|
+
resolve_assignee_ids(issue.assignee_usernames) if issue.assignee_usernames.any?
|
|
43
|
+
resolve_milestone_id(destination_id, issue.milestone_title) if issue.milestone_title
|
|
44
|
+
# Evaluated here too, so a bad confidential: template raises before
|
|
45
|
+
# any action writes rather than mid-way through post_issue_body.
|
|
46
|
+
issue.confidential?
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
27
50
|
def act
|
|
28
51
|
policy.resources.each do |resource|
|
|
29
52
|
issue = policy.build_issue(resource)
|
|
@@ -35,7 +58,7 @@ module Gitlab
|
|
|
35
58
|
private
|
|
36
59
|
|
|
37
60
|
def perform(resource, issue)
|
|
38
|
-
network.post_api(build_post_url(resource, issue), post_issue_body(issue))
|
|
61
|
+
network.post_api(build_post_url(resource, issue), post_issue_body(resource, issue))
|
|
39
62
|
end
|
|
40
63
|
|
|
41
64
|
def build_post_url(resource, issue)
|
|
@@ -52,11 +75,21 @@ module Gitlab
|
|
|
52
75
|
post_url
|
|
53
76
|
end
|
|
54
77
|
|
|
55
|
-
def post_issue_body(issue)
|
|
56
|
-
|
|
78
|
+
def post_issue_body(resource, issue)
|
|
79
|
+
destination_id = issue.destination || resource[policy.source_id_sym]
|
|
80
|
+
|
|
81
|
+
body = {
|
|
57
82
|
title: issue.title,
|
|
58
83
|
description: issue.description
|
|
59
84
|
}
|
|
85
|
+
|
|
86
|
+
body[:labels] = issue.labels.join(',') if issue.labels.any?
|
|
87
|
+
body[:assignee_ids] = resolve_assignee_ids(issue.assignee_usernames) if issue.assignee_usernames.any?
|
|
88
|
+
body[:due_date] = issue.due_date if issue.due_date
|
|
89
|
+
body[:milestone_id] = resolve_milestone_id(destination_id, issue.milestone_title) if issue.milestone_title
|
|
90
|
+
body[:confidential] = true if issue.confidential?
|
|
91
|
+
|
|
92
|
+
body
|
|
60
93
|
end
|
|
61
94
|
end
|
|
62
95
|
end
|
|
@@ -27,11 +27,28 @@ module Gitlab
|
|
|
27
27
|
puts "The following issue would be created in project `#{destination}` for the rule **#{policy.name}**:\n\n"
|
|
28
28
|
puts ">>>"
|
|
29
29
|
puts "* Title: #{issue.title}"
|
|
30
|
+
puts "* Labels: #{issue.labels.join(', ')}" if issue.labels.any?
|
|
31
|
+
puts "* Assignees: #{issue.assignee_usernames.join(', ')}" if issue.assignee_usernames&.any?
|
|
32
|
+
puts "* Due date: #{issue.due_date}" if issue.due_date
|
|
33
|
+
puts "* Milestone: #{issue.milestone_title}" if issue.milestone_title
|
|
34
|
+
puts "* Confidential: true" if issue.confidential?
|
|
30
35
|
puts "* Description: #{issue.description}"
|
|
31
36
|
puts ">>>"
|
|
32
37
|
end
|
|
33
38
|
end
|
|
34
39
|
|
|
40
|
+
def verify!
|
|
41
|
+
return unless issue.valid?
|
|
42
|
+
return if group_summary_without_destination?
|
|
43
|
+
|
|
44
|
+
ensure_labels_exist!(issue.labels, destination)
|
|
45
|
+
resolve_assignee_ids(issue.assignee_usernames) if issue.assignee_usernames.any?
|
|
46
|
+
resolve_milestone_id(destination, issue.milestone_title) if issue.milestone_title
|
|
47
|
+
# Evaluated here too, so a bad confidential: template raises before
|
|
48
|
+
# any action writes rather than mid-way through post_issue_body.
|
|
49
|
+
issue.confidential?
|
|
50
|
+
end
|
|
51
|
+
|
|
35
52
|
def act
|
|
36
53
|
perform if issue.valid?
|
|
37
54
|
end
|
|
@@ -75,10 +92,18 @@ module Gitlab
|
|
|
75
92
|
end
|
|
76
93
|
|
|
77
94
|
def post_issue_body
|
|
78
|
-
{
|
|
95
|
+
body = {
|
|
79
96
|
title: issue.title,
|
|
80
97
|
description: issue.description
|
|
81
98
|
}
|
|
99
|
+
|
|
100
|
+
body[:labels] = issue.labels.join(',') if issue.labels.any?
|
|
101
|
+
body[:assignee_ids] = resolve_assignee_ids(issue.assignee_usernames) if issue.assignee_usernames.any?
|
|
102
|
+
body[:due_date] = issue.due_date if issue.due_date
|
|
103
|
+
body[:milestone_id] = resolve_milestone_id(destination, issue.milestone_title) if issue.milestone_title
|
|
104
|
+
body[:confidential] = true if issue.confidential?
|
|
105
|
+
|
|
106
|
+
body
|
|
82
107
|
end
|
|
83
108
|
end
|
|
84
109
|
end
|