payping-gitlab-triage 0.1.1

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.
Files changed (108) hide show
  1. checksums.yaml +7 -0
  2. data/.codeclimate.yml +19 -0
  3. data/.gitignore +15 -0
  4. data/.gitlab/CODEOWNERS +2 -0
  5. data/.gitlab/changelog_config.yml +13 -0
  6. data/.gitlab/issue_templates/Default.md +13 -0
  7. data/.gitlab/merge_request_templates/Default.md +11 -0
  8. data/.gitlab/merge_request_templates/Release.md +13 -0
  9. data/.gitlab-ci.yml +146 -0
  10. data/.rubocop.yml +21 -0
  11. data/.rubocop_todo.yml +145 -0
  12. data/.ruby-version +1 -0
  13. data/.tool-versions +1 -0
  14. data/.yardopts +4 -0
  15. data/CONTRIBUTING.md +31 -0
  16. data/Dangerfile +5 -0
  17. data/Gemfile +15 -0
  18. data/Guardfile +70 -0
  19. data/LICENSE.md +25 -0
  20. data/README.md +1480 -0
  21. data/Rakefile +6 -0
  22. data/bin/gitlab-triage +19 -0
  23. data/gitlab-triage.gemspec +41 -0
  24. data/lib/gitlab/triage/action/base.rb +14 -0
  25. data/lib/gitlab/triage/action/comment.rb +104 -0
  26. data/lib/gitlab/triage/action/comment_on_summary.rb +83 -0
  27. data/lib/gitlab/triage/action/delete.rb +56 -0
  28. data/lib/gitlab/triage/action/issue.rb +64 -0
  29. data/lib/gitlab/triage/action/summarize.rb +82 -0
  30. data/lib/gitlab/triage/action.rb +36 -0
  31. data/lib/gitlab/triage/api_query_builders/base_query_param_builder.rb +27 -0
  32. data/lib/gitlab/triage/api_query_builders/date_query_param_builder.rb +42 -0
  33. data/lib/gitlab/triage/api_query_builders/multi_query_param_builder.rb +28 -0
  34. data/lib/gitlab/triage/api_query_builders/single_query_param_builder.rb +13 -0
  35. data/lib/gitlab/triage/command_builders/base_command_builder.rb +40 -0
  36. data/lib/gitlab/triage/command_builders/cc_command_builder.rb +19 -0
  37. data/lib/gitlab/triage/command_builders/comment_command_builder.rb +19 -0
  38. data/lib/gitlab/triage/command_builders/label_command_builder.rb +40 -0
  39. data/lib/gitlab/triage/command_builders/move_command_builder.rb +19 -0
  40. data/lib/gitlab/triage/command_builders/remove_label_command_builder.rb +15 -0
  41. data/lib/gitlab/triage/command_builders/status_command_builder.rb +23 -0
  42. data/lib/gitlab/triage/command_builders/text_content_builder.rb +138 -0
  43. data/lib/gitlab/triage/engine.rb +635 -0
  44. data/lib/gitlab/triage/entity_builders/issue_builder.rb +54 -0
  45. data/lib/gitlab/triage/entity_builders/summary_builder.rb +82 -0
  46. data/lib/gitlab/triage/errors/network.rb +11 -0
  47. data/lib/gitlab/triage/errors.rb +1 -0
  48. data/lib/gitlab/triage/expand_condition/expansion.rb +203 -0
  49. data/lib/gitlab/triage/expand_condition/list.rb +25 -0
  50. data/lib/gitlab/triage/expand_condition/sequence.rb +25 -0
  51. data/lib/gitlab/triage/expand_condition.rb +23 -0
  52. data/lib/gitlab/triage/filters/assignee_member_conditions_filter.rb +13 -0
  53. data/lib/gitlab/triage/filters/author_member_conditions_filter.rb +13 -0
  54. data/lib/gitlab/triage/filters/base_conditions_filter.rb +58 -0
  55. data/lib/gitlab/triage/filters/branch_date_filter.rb +73 -0
  56. data/lib/gitlab/triage/filters/branch_protected_filter.rb +26 -0
  57. data/lib/gitlab/triage/filters/discussions_conditions_filter.rb +58 -0
  58. data/lib/gitlab/triage/filters/issue_date_conditions_filter.rb +78 -0
  59. data/lib/gitlab/triage/filters/member_conditions_filter.rb +84 -0
  60. data/lib/gitlab/triage/filters/merge_request_date_conditions_filter.rb +13 -0
  61. data/lib/gitlab/triage/filters/name_conditions_filter.rb +26 -0
  62. data/lib/gitlab/triage/filters/no_additional_labels_conditions_filter.rb +30 -0
  63. data/lib/gitlab/triage/filters/ruby_conditions_filter.rb +33 -0
  64. data/lib/gitlab/triage/filters/votes_conditions_filter.rb +54 -0
  65. data/lib/gitlab/triage/graphql_network.rb +81 -0
  66. data/lib/gitlab/triage/graphql_queries/query_builder.rb +158 -0
  67. data/lib/gitlab/triage/graphql_queries/query_param_builders/base_param_builder.rb +30 -0
  68. data/lib/gitlab/triage/graphql_queries/query_param_builders/date_param_builder.rb +35 -0
  69. data/lib/gitlab/triage/graphql_queries/query_param_builders/labels_param_builder.rb +18 -0
  70. data/lib/gitlab/triage/limiters/base_limiter.rb +35 -0
  71. data/lib/gitlab/triage/limiters/date_field_limiter.rb +45 -0
  72. data/lib/gitlab/triage/network.rb +39 -0
  73. data/lib/gitlab/triage/network_adapters/base_adapter.rb +17 -0
  74. data/lib/gitlab/triage/network_adapters/graphql_adapter.rb +92 -0
  75. data/lib/gitlab/triage/network_adapters/httparty_adapter.rb +116 -0
  76. data/lib/gitlab/triage/network_adapters/test_adapter.rb +39 -0
  77. data/lib/gitlab/triage/option_parser.rb +105 -0
  78. data/lib/gitlab/triage/options.rb +30 -0
  79. data/lib/gitlab/triage/param_builders/date_param_builder.rb +64 -0
  80. data/lib/gitlab/triage/policies/base_policy.rb +80 -0
  81. data/lib/gitlab/triage/policies/rule_policy.rb +36 -0
  82. data/lib/gitlab/triage/policies/summary_policy.rb +29 -0
  83. data/lib/gitlab/triage/policies_resources/rule_resources.rb +11 -0
  84. data/lib/gitlab/triage/policies_resources/summary_resources.rb +11 -0
  85. data/lib/gitlab/triage/resource/base.rb +102 -0
  86. data/lib/gitlab/triage/resource/branch.rb +13 -0
  87. data/lib/gitlab/triage/resource/context.rb +47 -0
  88. data/lib/gitlab/triage/resource/epic.rb +20 -0
  89. data/lib/gitlab/triage/resource/instance_version.rb +35 -0
  90. data/lib/gitlab/triage/resource/issue.rb +52 -0
  91. data/lib/gitlab/triage/resource/label.rb +56 -0
  92. data/lib/gitlab/triage/resource/label_event.rb +48 -0
  93. data/lib/gitlab/triage/resource/linked_issue.rb +15 -0
  94. data/lib/gitlab/triage/resource/merge_request.rb +23 -0
  95. data/lib/gitlab/triage/resource/milestone.rb +98 -0
  96. data/lib/gitlab/triage/resource/shared/issuable.rb +119 -0
  97. data/lib/gitlab/triage/rest_api_network.rb +125 -0
  98. data/lib/gitlab/triage/retryable.rb +33 -0
  99. data/lib/gitlab/triage/ui.rb +23 -0
  100. data/lib/gitlab/triage/url_builders/url_builder.rb +54 -0
  101. data/lib/gitlab/triage/utils.rb +13 -0
  102. data/lib/gitlab/triage/validators/limiter_validator.rb +21 -0
  103. data/lib/gitlab/triage/validators/params_validator.rb +43 -0
  104. data/lib/gitlab/triage/version.rb +7 -0
  105. data/lib/gitlab/triage.rb +6 -0
  106. data/support/.gitlab-ci.example.yml +22 -0
  107. data/support/.triage-policies.example.yml +51 -0
  108. metadata +280 -0
data/README.md ADDED
@@ -0,0 +1,1480 @@
1
+ [![pipeline status](https://gitlab.com/gitlab-org/ruby/gems/gitlab-triage/badges/master/pipeline.svg)](https://gitlab.com/gitlab-org/ruby/gems/gitlab-triage/-/commits/master)
2
+
3
+ # GitLab Triage Project
4
+
5
+ This project allows to automate triaging of issues and merge requests for GitLab projects or groups.
6
+
7
+ ## gitlab-triage gem
8
+
9
+ ### Abstract
10
+
11
+ The `gitlab-triage` gem aims to enable project managers and maintainers to
12
+ automatically triage Issues and Merge Requests in GitLab projects or groups
13
+ based on defined policies.
14
+
15
+ See [Running with the installed gem](#running-with-the-installed-gem) for how to specify a project or a
16
+ group.
17
+
18
+ ### What is a triage policy?
19
+
20
+ Triage policies are defined on a resource level basis, resources being:
21
+ - Epics
22
+ - Issues
23
+ - Merge Requests
24
+ - Branches
25
+
26
+ Each policy can declare a number of conditions that must all be satisfied before
27
+ a number of actions are carried out.
28
+
29
+ Summary policies are special policies that join multiple policies together to
30
+ create a summary issue with all the sub-policies' summaries, see
31
+ [Summary policies](#summary-policies).
32
+
33
+ ### Defining a policy
34
+
35
+ Policies are defined in a policy file (by default `./.triage-policies.yml`).
36
+ The format of the file is [YAML](https://en.wikipedia.org/wiki/YAML).
37
+
38
+ > **Note:** You can use the [`--init`](#usage) option to add an example
39
+ [`.triage-policies.yml` file](support/.triage-policies.example.yml) to your
40
+ project.
41
+
42
+ Select which resource to add the policy to:
43
+ - `epics`
44
+ - `issues`
45
+ - `merge_requests`
46
+ - `branches`
47
+
48
+ And create an array of `rules` to define your policies:
49
+
50
+ For example:
51
+
52
+ ```yml
53
+ resource_rules:
54
+ epics:
55
+ rules:
56
+ - name: My epic policy
57
+ conditions:
58
+ date:
59
+ attribute: updated_at
60
+ condition: older_than
61
+ interval_type: days
62
+ interval: 5
63
+ state: opened
64
+ labels:
65
+ - None
66
+ actions:
67
+ labels:
68
+ - needs attention
69
+ mention:
70
+ - markglenfletcher
71
+ comment: |
72
+ {{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')}
73
+ issues:
74
+ rules:
75
+ - name: My issue policy
76
+ conditions:
77
+ date:
78
+ attribute: updated_at
79
+ condition: older_than
80
+ interval_type: days
81
+ interval: 5
82
+ state: opened
83
+ labels:
84
+ - None
85
+ limits:
86
+ most_recent: 50
87
+ actions:
88
+ labels:
89
+ - needs attention
90
+ mention:
91
+ - markglenfletcher
92
+ move: gitlab-org/backlog
93
+ comment: |
94
+ {{author}} This issue 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')}
95
+ summarize:
96
+ destination: gitlab-org/ruby/gems/gitlab-triage
97
+ title: |
98
+ #{resource[:type].capitalize} require labels
99
+ item: |
100
+ - [ ] [{{title}}]({{web_url}}) {{labels}}
101
+ redact_confidential_resources: false
102
+ summary: |
103
+ The following issues require labels:
104
+
105
+ {{items}}
106
+
107
+ Please take care of them before the end of #{7.days.from_now.strftime('%Y-%m-%d')}
108
+
109
+ /label ~"needs attention"
110
+ merge_requests:
111
+ rules:
112
+ - name: My merge request policy
113
+ conditions:
114
+ state: opened
115
+ labels:
116
+ - None
117
+ limits:
118
+ most_recent: 50
119
+ actions:
120
+ labels:
121
+ - needs attention
122
+ comment_type: thread
123
+ comment: |
124
+ {{author}} This issue is unlabelled. Please add one or more labels.
125
+ branches:
126
+ rules:
127
+ - name: My branch policy
128
+ conditions:
129
+ date:
130
+ attribute: committed_date
131
+ condition: older_than
132
+ interval_type: 6
133
+ interval: months
134
+ name: ^feature
135
+ actions:
136
+ delete: true
137
+ ```
138
+
139
+ ### Real world example
140
+
141
+ We're enforcing multiple polices with pipeline schedules at [triage-ops](
142
+ https://gitlab.com/gitlab-org/quality/triage-ops), where we're also
143
+ extensively utilizing the [plugins system](#can-i-customize).
144
+
145
+ ### Fields
146
+
147
+ A policy consists of the following fields:
148
+ - [Name field](#name-field)
149
+ - [Conditions field](#conditions-field)
150
+ - [Limits field](#limits-field)
151
+ - [Actions field](#actions-field)
152
+
153
+ #### Name field
154
+
155
+ The name field is used to describe the purpose of the individual policy.
156
+
157
+ Example:
158
+
159
+ ```yml
160
+ name: Policy name
161
+ ```
162
+
163
+ #### Conditions field
164
+
165
+ Used to declare a condition that must be satisfied by a resource before actions will be taken.
166
+
167
+ Available condition types:
168
+ - [`date` condition](#date-condition)
169
+ - [`milestone` condition](#milestone-condition)
170
+ - [`iteration` condition](#iteration-condition)
171
+ - [`state` condition](#state-condition)
172
+ - [`votes` condition](#votes-condition)
173
+ - [`labels` condition](#labels-condition)
174
+ - [`forbidden_labels` condition](#forbidden-labels-condition)
175
+ - [`no_additional_labels` condition](#no-additional-labels-condition)
176
+ - [`author_member` condition](#author-member-condition)
177
+ - [`assignee_member` condition](#assignee-member-condition)
178
+ - [`draft` condition](#draft-condition)
179
+ - [`source_branch` condition](#source-branch-condition)
180
+ - [`target_branch` condition](#target-branch-condition)
181
+ - [`health_status` condition](#health-status-condition)
182
+ - [`weight` condition](#weight-condition)
183
+ - [`discussions` condition](#discussions-condition)
184
+ - [`protected` condition](#protected-condition)
185
+ - [`ruby` condition](#ruby-condition)
186
+ - [`reviewer_id` condition](#reviewer-id-condition)
187
+
188
+ ##### Date condition
189
+
190
+ Accepts a hash of fields.
191
+
192
+ | Field | Type | Values | Required |
193
+ | --------- | ---- |----------------------------------------------------------------------------| -------- |
194
+ | `attribute` | string | `created_at`, `updated_at`, `merged_at`, `authored_date`, `committed_date` | yes |
195
+ | `condition` | string | `older_than`, `newer_than` | yes |
196
+ | `interval_type` | string | `minutes`, `hours`, `days`, `weeks`, `months`, `years` | yes |
197
+ | `interval` | integer | integer | yes |
198
+ > **Note:**
199
+ > - `merged_at` only works on merge requests.
200
+ > - `closed_at` is not supported in the GitLab API, but can be used in a [`ruby` condition](#ruby-condition).
201
+ > - `committed_date` and `authored_date` only works for branches.
202
+
203
+ Example:
204
+
205
+ ```yml
206
+ conditions:
207
+ date:
208
+ attribute: updated_at
209
+ condition: older_than
210
+ interval_type: months
211
+ interval: 12
212
+ ```
213
+
214
+ > **Note:** If the GitLab server is giving 500 error with this option, it
215
+ > can mean that it's taking too much time to query this, and it's timing out.
216
+ > A workaround for this is that we can filter in Ruby. If you need this
217
+ > workaround, specify this with `filter_in_ruby: true`
218
+ >
219
+ > ```yaml
220
+ > conditions:
221
+ > date:
222
+ > attribute: updated_at
223
+ > condition: older_than
224
+ > interval_type: months
225
+ > interval: 12
226
+ > filter_in_ruby: true
227
+ > ```
228
+
229
+ ##### Milestone condition
230
+
231
+ Accepts the name of a milestone to filter upon. Also accepts the following timebox values:
232
+
233
+ - `none`
234
+ - `any`
235
+ - `upcoming`
236
+ - `started`
237
+
238
+ See the [`milestone_id` API field documentation](https://docs.gitlab.com/ee/api/issues.html) for their meaning.
239
+
240
+ Example:
241
+
242
+ ```yml
243
+ conditions:
244
+ milestone: v1
245
+ ```
246
+
247
+ ##### Iteration condition
248
+
249
+ Accepts the name of an iteration to filter upon. Also accepts the following
250
+ timebox values:
251
+
252
+ - `none`
253
+ - `any`
254
+
255
+ See the [`iteration_id` API field documentation](https://docs.gitlab.com/ee/api/issues.html) for their meaning.
256
+
257
+ Example:
258
+
259
+ ```yml
260
+ conditions:
261
+ iteration: none
262
+ ```
263
+
264
+ > **Note:** This query is not supported using GraphQL yet.
265
+
266
+ ##### State condition
267
+
268
+ Accepts a string.
269
+
270
+ | State | Type | Value |
271
+ | --------- | ---- | ------ |
272
+ | Closed issues/MRs | string | `closed` |
273
+ | Open issues/MRs | string | `opened` |
274
+ | Locked issues | string | `locked` |
275
+ | Merged merge requests | string | `merged` |
276
+
277
+ Example:
278
+
279
+ ```yml
280
+ conditions:
281
+ state: opened
282
+ ```
283
+
284
+ ##### Votes condition
285
+
286
+ Accepts a hash of fields.
287
+
288
+ | Field | Type | Values | Required |
289
+ | --------- | ---- | ---- | -------- |
290
+ | `attribute` | string | `upvotes`, `downvotes` | yes |
291
+ | `condition` | string | `less_than`, `greater_than` | yes |
292
+ | `threshold` | integer | integer | yes |
293
+
294
+ Example:
295
+
296
+ ```yml
297
+ conditions:
298
+ votes:
299
+ attribute: upvotes
300
+ condition: less_than
301
+ threshold: 10
302
+ ```
303
+
304
+ ##### Labels condition
305
+
306
+ Accepts an array of strings. Each element in the array represents the name of a label to filter on.
307
+
308
+ > **Note:** **All** specified labels must be present on the resource for the condition to be satisfied
309
+
310
+ Example:
311
+
312
+ ```yml
313
+ conditions:
314
+ labels:
315
+ - feature proposal
316
+ ```
317
+
318
+ ###### Predefined special label names
319
+
320
+ Basing on the [issues API](https://docs.gitlab.com/ee/api/issues.html), there
321
+ are two special predefined label names we can use here:
322
+
323
+ * `None`: This indicates that no labels were present
324
+ * `Any`: This indicates that any labels were presented
325
+
326
+ Example:
327
+
328
+ ```yml
329
+ conditions:
330
+ labels:
331
+ - None
332
+ ```
333
+
334
+ ###### Labels brace expansion
335
+
336
+ We could expand the labels by using brace expansion, which is a pattern
337
+ surrounded by using braces: `{}`. For now, we support 2 kinds of brace
338
+ expansion:
339
+
340
+ 1. List: `{ apple, orange }`
341
+ 2. Sequence: `{1..4}`
342
+
343
+ > **Note:**
344
+ > - Spaces around the items are ignored.
345
+ > - Do not rely on the expansion ordering. This is subject to change.
346
+
347
+ ###### List
348
+
349
+ The name of a label can contain a list of items, written like
350
+ `{ apple, orange }`. For each item, the rule will be duplicated with the new
351
+ label name.
352
+
353
+ Example:
354
+
355
+ ```yml
356
+ resource_rules:
357
+ issues:
358
+ rules:
359
+ - name: Add missing ~Quality label
360
+ conditions:
361
+ labels:
362
+ - Quality:test-{ gap, infra }
363
+ actions:
364
+ labels:
365
+ - Quality
366
+ ```
367
+
368
+ Which will be expanded into:
369
+
370
+ ```yml
371
+ resource_rules:
372
+ issues:
373
+ rules:
374
+ - name: Add missing ~Quality label
375
+ conditions:
376
+ labels:
377
+ - Quality:test-gap
378
+ actions:
379
+ labels:
380
+ - Quality
381
+
382
+ - name: Add missing ~Quality label
383
+ conditions:
384
+ labels:
385
+ - Quality:test-infra
386
+ actions:
387
+ labels:
388
+ - Quality
389
+ ```
390
+
391
+ > **Note:**
392
+ > If you want to define a full label expansion, you'll need to [force string](https://yaml.org/YAML_for_ruby.html#forcing_strings) or [quote string](https://yaml.org/YAML_for_ruby.html#single-quoted_strings) because otherwise it won't be considered a string due to the YAML parser.
393
+ > For example, we can quote the expression like `'{ apple, orange }'`, which will create 2 rules, for the two specified labels.
394
+
395
+ ###### Sequence
396
+
397
+ The name of a label can contain one or more sequence conditions, written
398
+ like `{0..9}`, which means `0`, `1`, `2`, and so on up to `9`. For each
399
+ number, the rule will be duplicated with the new label name.
400
+
401
+ Example:
402
+
403
+ ```yml
404
+ resource_rules:
405
+ issues:
406
+ rules:
407
+ - name: Add missing ~"missed\-deliverable" label
408
+ conditions:
409
+ labels:
410
+ - missed:{10..11}.{0..1}
411
+ - deliverable
412
+ actions:
413
+ labels:
414
+ - missed deliverable
415
+ ```
416
+
417
+ Which will be expanded into:
418
+
419
+ ```yml
420
+ resource_rules:
421
+ issues:
422
+ rules:
423
+ - name: Add missing ~"missed\-deliverable" label
424
+ conditions:
425
+ labels:
426
+ - missed:10.0
427
+ - deliverable
428
+ actions:
429
+ labels:
430
+ - missed deliverable
431
+
432
+ - name: Add missing ~"missed\-deliverable" label
433
+ conditions:
434
+ labels:
435
+ - missed:10.1
436
+ - deliverable
437
+ actions:
438
+ labels:
439
+ - missed deliverable
440
+
441
+ - name: Add missing ~"missed\-deliverable" label
442
+ conditions:
443
+ labels:
444
+ - missed:11.0
445
+ - deliverable
446
+ actions:
447
+ labels:
448
+ - missed deliverable
449
+
450
+ - name: Add missing ~"missed\-deliverable" label
451
+ conditions:
452
+ labels:
453
+ - missed:11.1
454
+ - deliverable
455
+ actions:
456
+ labels:
457
+ - missed deliverable
458
+ ```
459
+
460
+ ##### Forbidden labels condition
461
+
462
+ Accepts an array of strings. Each element in the array represents the name of a label to filter on.
463
+
464
+ > **Note:** **All** specified labels must be absent on the resource for the condition to be satisfied
465
+
466
+ Example:
467
+
468
+ ```yml
469
+ conditions:
470
+ forbidden_labels:
471
+ - awaiting feedback
472
+ ```
473
+
474
+ ##### No additional labels condition
475
+
476
+ Accepts a boolean. If `true` the resource cannot have more labels than those specified by the `labels` condition.
477
+
478
+ Example:
479
+
480
+ ```yml
481
+ conditions:
482
+ labels:
483
+ - feature proposal
484
+ no_additional_labels: true
485
+ ```
486
+
487
+ ##### Author Member condition
488
+
489
+ This condition determines whether the author of a resource is a member of the specified group or project.
490
+
491
+ This is useful for determining whether Issues or Merge Requests have been raised by a Community Contributor.
492
+
493
+ Accepts a hash of fields.
494
+
495
+ | Field | Type | Values | Required |
496
+ | --------- | ---- | ---- | -------- |
497
+ | `source` | string | `group`, `project` | yes |
498
+ | `condition` | string | `member_of`, `not_member_of` | yes |
499
+ | `source_id` | integer or string | gitlab-org/gitlab | yes |
500
+
501
+ Example:
502
+
503
+ ```yml
504
+ conditions:
505
+ author_member:
506
+ source: group
507
+ condition: not_member_of
508
+ source_id: 9970
509
+ ```
510
+
511
+ ##### Assignee member condition
512
+
513
+ This condition determines whether the assignee of a resource is a member of the specified group or project.
514
+
515
+ Accepts a hash of fields.
516
+
517
+ | Field | Type | Values | Required |
518
+ | --------- | ---- | ---- | -------- |
519
+ | `source` | string | `group`, `project` | yes |
520
+ | `condition` | string | `member_of`, `not_member_of` | yes |
521
+ | `source_id` | integer or string | gitlab-org/gitlab | yes |
522
+
523
+ Example:
524
+
525
+ ```yml
526
+ conditions:
527
+ assignee_member:
528
+ source: group
529
+ condition: not_member_of
530
+ source_id: 9970
531
+ ```
532
+
533
+ ##### Draft condition
534
+
535
+ **This condition is only applicable for merge requests.**
536
+
537
+ Accepts a boolean. If `true`, only draft MRs are returned. If `false`, only non-draft MRs are returned.
538
+
539
+ Example:
540
+
541
+ ```yml
542
+ conditions:
543
+ draft: true
544
+ ```
545
+
546
+ ##### Source branch condition
547
+
548
+ **This condition is only applicable for merge requests.**
549
+
550
+ Accepts the name of a source branch to filter upon.
551
+
552
+ Example:
553
+
554
+ ```yml
555
+ conditions:
556
+ source_branch: 'feature-branch'
557
+ ```
558
+
559
+ ##### Target branch condition
560
+
561
+ **This condition is only applicable for merge requests.**
562
+
563
+ Accepts the name of a target branch to filter upon.
564
+
565
+ Example:
566
+
567
+ ```yml
568
+ conditions:
569
+ target_branch: 'master'
570
+ ```
571
+
572
+ ##### Health Status condition
573
+
574
+ **This condition is only applicable for issues.**
575
+
576
+ Accepts a string per the [API documentation](https://docs.gitlab.com/ee/api/issues.html#list-issues).
577
+
578
+ | State | Type | Value |
579
+ | --------- | ---- | ------ |
580
+ | Any health status | string | `Any` |
581
+ | No health status | string | `None` |
582
+ | Specific health status | string | One of `on_track`, `needs_attention` or `at_risk` |
583
+
584
+ Example:
585
+
586
+ ```yml
587
+ conditions:
588
+ health_status: Any
589
+
590
+ > **Note:** This query is not supported using GraphQL yet.
591
+
592
+ ##### Weight condition
593
+
594
+ **This condition is only applicable for issues.**
595
+
596
+ Accepts a string per the [API documentation](https://docs.gitlab.com/ee/api/issues.html#list-issues).
597
+
598
+ | State | Type | Value |
599
+ | --------- | ---- | ------ |
600
+ | Any weight | string | `Any` |
601
+ | No weight | string | `None` |
602
+ | Specific weight | integer | integer |
603
+
604
+ Example:
605
+
606
+ ```yml
607
+ conditions:
608
+ weight: Any
609
+ ```
610
+
611
+ ##### Discussions condition
612
+
613
+ Accepts a hash of fields.
614
+
615
+ | Field | Type | Values | Required |
616
+ | --------- | ---- | ---- | -------- |
617
+ | `attribute` | string | `threads`, `notes` | yes |
618
+ | `condition` | string | `less_than`, `greater_than` | yes |
619
+ | `threshold` | integer | integer | yes |
620
+
621
+ Example:
622
+
623
+ ```yml
624
+ conditions:
625
+ discussions:
626
+ attribute: threads
627
+ condition: greater_than
628
+ threshold: 15
629
+ ```
630
+
631
+ ##### Protected condition
632
+
633
+ ** This condition is only applicable for branches**
634
+
635
+ Accept a boolean.
636
+ If not specified, default to `false` to filter out protected branches.
637
+
638
+ ##### Ruby condition
639
+
640
+ This condition allows users to write a Ruby expression to be evaluated for
641
+ each resource. If it evaluates to a truthy value, it satisfies the condition.
642
+ If it evaluates to a falsey value, it does not satisfy the condition.
643
+
644
+ Accepts a string as the Ruby expression.
645
+
646
+ Example:
647
+
648
+ ```yml
649
+ conditions:
650
+ ruby: Date.today > milestone.succ.start_date
651
+ ```
652
+
653
+ In the above example, this describes that we want to act on the resources
654
+ which passed the next active milestone's starting date.
655
+
656
+ Here `milestone` will return a `Gitlab::Triage::Resource::Milestone` object,
657
+ representing the milestone of the questioning resource. `Milestone#succ` would
658
+ return the next active milestone, based on the `start_date` of all milestones
659
+ along with the representing milestone. If the milestone was coming from a
660
+ project, then it's based on all active milestones in that project. If the
661
+ milestone was coming from a group, then it's based on all active milestones
662
+ in the group.
663
+
664
+ If we also want to handle some edge cases, for example, a resource might not
665
+ have a milestone, and a milestone might not be active, and there might not
666
+ have a next milestone. We could instead write something like:
667
+
668
+ ```yml
669
+ conditions:
670
+ ruby: milestone&.active? && milestone&.succ && Date.today > milestone.succ.start_date
671
+ ```
672
+
673
+ This will make it only act on resources which have active milestones and
674
+ there exists next milestone which has already started.
675
+
676
+ Since `closed_at` is not a queryable attribute in the GitLab API, we can use a Ruby expression to filter resources like:
677
+
678
+ ```yml
679
+ conditions:
680
+ ruby: resource[:closed_at] > 7.days.ago.strftime('%Y-%m-%dT00:00:00.000Z')
681
+ ```
682
+
683
+ See [Ruby expression API](#ruby-expression-api) for the list of currently
684
+ available API.
685
+
686
+ #### Limits field
687
+
688
+ Limits restrict the number of resources on which an action is carried out. They
689
+ can be useful when combined with conditions that return a large number of
690
+ resources. For example, if the conditions are satisfied by thousands of issues a
691
+ limit can be configured to process only fifty of them to avoid making an
692
+ overwhelming number of changes at once.
693
+
694
+ Accepts a key and value pair where the key is `most_recent` or `oldest`and the
695
+ value is the number of resources to act on. The following table outlines how
696
+ each key affects the sorting and order of resources that it limits.
697
+
698
+ | Name / Key | Sorted by | Order |
699
+ | --------- | ---- | ------ |
700
+ | `most_recent` | `created_at` | descending |
701
+ | `oldest` | `created_at` | ascending |
702
+
703
+ Example:
704
+
705
+ ```yml
706
+ limits:
707
+ most_recent: 50
708
+ ```
709
+
710
+ ##### Reviewer id condition
711
+
712
+ **This condition is only applicable for merge requests.**
713
+
714
+ Accepts the id of a user to filter on. Also accepts `none` or `any`.
715
+
716
+ Example:
717
+
718
+ ```yml
719
+ conditions:
720
+ reviewer_id: any
721
+ ```
722
+
723
+ #### Actions field
724
+
725
+ Used to declare an action to be carried out on a resource if **all** conditions are satisfied.
726
+
727
+ Available action types:
728
+ - [`labels` action](#labels-action)
729
+ - [`remove_labels` action](#remove-labels-action)
730
+ - [`status` action](#status-action)
731
+ - [`mention` action](#mention-action)
732
+ - [`move` action](#move-action)
733
+ - [`comment` action](#comment-action)
734
+ - [`comment_type` action option](#comment-type-action-option)
735
+ - [`summarize` action](#summarize-action)
736
+ - [`comment_on_summary` action](#comment-on-summary-action)
737
+ - [`issue` action](#create-a-new-issue-from-each-resource)
738
+ - [`delete` action](#delete-action)
739
+
740
+ ##### Labels action
741
+
742
+ Adds a number of labels to the resource.
743
+
744
+ Accepts an array of strings. Each element is the name of a label to add.
745
+
746
+ If any of the labels doesn't exist, the automation will stop immediately so
747
+ that if a label is renamed or deleted, you'll have to explicitly update or remove
748
+ it in your policy file.
749
+
750
+ Example:
751
+
752
+ ```yml
753
+ actions:
754
+ labels:
755
+ - feature proposal
756
+ - awaiting feedback
757
+ ```
758
+
759
+ ##### Remove labels action
760
+
761
+ Removes a number of labels from the resource.
762
+
763
+ Accepts an array of strings. Each element is the name of a label to remove.
764
+
765
+ If any of the labels doesn't exist, the automation will stop immediately so
766
+ that if a label is renamed or deleted, you'll have to explicitly update or remove
767
+ it in your policy file.
768
+
769
+ Example:
770
+
771
+ ```yml
772
+ actions:
773
+ remove_labels:
774
+ - feature proposal
775
+ - awaiting feedback
776
+ ```
777
+
778
+ ##### Status action
779
+
780
+ Changes the status of the resource.
781
+
782
+ Accepts a string.
783
+
784
+ | State transition | Type | Value |
785
+ | --------- | ---- | ------ |
786
+ | Close the resource | string | `close` |
787
+ | Reopen the resource | string | `reopen` |
788
+
789
+ Example:
790
+
791
+ ```yml
792
+ actions:
793
+ status: close
794
+ ```
795
+
796
+ ##### Mention action
797
+
798
+ Mentions a number of users.
799
+
800
+ Accepts an array of strings. Each element is the username of a user to mention.
801
+
802
+ Example:
803
+
804
+ ```yml
805
+ actions:
806
+ mention:
807
+ - rymai
808
+ - markglenfletcher
809
+ ```
810
+
811
+ ##### Move action
812
+
813
+ Moves an issue (merge request is not supported yet) to the specified project.
814
+
815
+ Accepts a string containing the target project path.
816
+
817
+ Example:
818
+
819
+ ```yml
820
+ actions:
821
+ move: target/project_path
822
+ ```
823
+
824
+ ##### Comment action
825
+
826
+ Adds a comment to the resource.
827
+
828
+ Accepts a string, and placeholders. Placeholders should be wrapped in double
829
+ curly braces, e.g. `{{author}}`.
830
+
831
+ The following placeholders are supported:
832
+
833
+ - `created_at`: the resource's creation date
834
+ - `updated_at`: the resource's last update date
835
+ - `closed_at`: the resource's closed date (if applicable)
836
+ - `merged_at`: the resource's merged date (if applicable)
837
+ - `state`: the resources's current state: `opened`, `closed`, `merged`
838
+ - `author`: the username of the resource's author as `@user1`
839
+ - `assignee`: the username of the resource's assignee as `@user1`
840
+ - `assignees`: the usernames of the resource's assignees as `@user1, @user2`
841
+ - `closed_by`: the user that closed the resource as `@user1` (if applicable)
842
+ - `merged_by`: the user that merged the resource as `@user1` (if applicable)
843
+ - `milestone`: the resource's current milestone
844
+ - `labels`: the resource's labels as `~label1, ~label2`
845
+ - `upvotes`: the resources's upvotes count
846
+ - `downvotes`: the resources's downvotes count
847
+ - `title`: the resource's title
848
+ - `web_url`: the web URL pointing to the resource
849
+ - `full_reference`: the full reference of the resource as `namespace/project#12`, `namespace/project!42`, `namespace/project&72`
850
+ - `type`: the type of the resources. For now, only `issues`, `merge_requests`, and `epics` are supported.
851
+
852
+ If the resource doesn't respond to the placeholder, or if the field is `nil`,
853
+ the placeholder is not replaced.
854
+
855
+ Example without placeholders:
856
+
857
+ ```yml
858
+ actions:
859
+ comment: |
860
+ Closing this issue automatically
861
+ ```
862
+
863
+ Example with placeholders:
864
+
865
+ ```yml
866
+ actions:
867
+ comment: |
868
+ {{author}} Are you still interested in finishing this merge request?
869
+ ```
870
+
871
+ ##### Comment type action option
872
+
873
+ Determines the type of comment to be added to the resource.
874
+
875
+ The following comment types are supported:
876
+
877
+ - `comment` (default): creates a regular comment on the resource
878
+ - `thread`: starts a resolvable thread (discussion) on the resource
879
+
880
+ For merge requests, if `comment_type` is set to `thread`, we can also configure that [all threads should be resolved before merging](https://docs.gitlab.com/ee/user/discussions/#only-allow-merge-requests-to-be-merged-if-all-threads-are-resolved), therefore this comment can prevent it from merging.
881
+
882
+ Example:
883
+
884
+ ```yml
885
+ actions:
886
+ comment_type: thread
887
+ comment: |
888
+ {{author}} Are you still interested in finishing this merge request?
889
+ ```
890
+
891
+ ###### Harnessing Quick Actions
892
+
893
+ [GitLab's quick actions feature](https://docs.gitlab.com/ce/user/project/quick_actions.html) is available in Core.
894
+ All of the operations supported by executing a quick action can be carried out via the comment action.
895
+
896
+ If GitLab triage does not support an operation natively, it may be possible via a quick action in a comment.
897
+
898
+ For example:
899
+ - Flagging an issue as [confidential](https://docs.gitlab.com/ce/user/project/issues/confidential_issues.html)
900
+ - [Locking issue discussion](https://docs.gitlab.com/ce/user/discussions/#lock-discussions)
901
+
902
+ ```yml
903
+ resource_rules:
904
+ issues:
905
+ rules:
906
+ - name: Mark bugs as confidential
907
+ conditions:
908
+ state: opened
909
+ ruby: !resource[:confidential]
910
+ labels:
911
+ - bug
912
+ actions:
913
+ comment: |
914
+ /confidential
915
+ ```
916
+
917
+ ###### Ruby expression
918
+
919
+ The comment can also contain Ruby expression, using Ruby's own string
920
+ interpolation syntax: `#{ expression }`. This gives you the most flexibility.
921
+ Suppose you want to mention the next active milestone relative to the one
922
+ associated with the resource, you can write:
923
+
924
+ ```yml
925
+ actions:
926
+ comment: |
927
+ Please move this to %"#{milestone.succ.title}".
928
+ ```
929
+
930
+ See [Ruby expression API](#ruby-expression-api) for the list of currently
931
+ available API.
932
+
933
+ > **Note:** If you get a syntax error due to stray braces (`{` or `}`), use `\`
934
+ to escape it. For example:
935
+ >
936
+ > ```yml
937
+ > actions:
938
+ > comment: |
939
+ > If \} comes first and/or following \{, you'll need to escape them. If it's just { wrapping something } then you don't need to, but it's also fine to escape them like \{ this \} if you prefer.
940
+ > ```
941
+
942
+ ##### Summarize action
943
+
944
+ Generates an issue summarizing what was triaged.
945
+
946
+ Accepts a hash of fields.
947
+
948
+ | Field | Type | Description | Required | Placeholders | Ruby expression | Default |
949
+ | ---- | ---- | ---- | ---- | ---- | ---- | ---- |
950
+ | `title` | string | The title of the generated issue | yes | yes | yes | |
951
+ | `destination` | integer or string | The project ID or path to create the generated issue in | no | no | no | source project |
952
+ | `item` | string | Template representing each triaged resource | no | yes | yes | |
953
+ | `summary` | string | The description of the generated issue | no | Only `{{title}}`, `{{items}}`, `{{type}}` | yes | |
954
+ | `redact_confidential_resources` | boolean | Whether redact fields for confidential resources | no | no | no | true |
955
+
956
+ The following placeholders are supported for `summary`:
957
+
958
+ - `title`: The title of the generated issue
959
+ - `items`: Concatenated markdown separated by a newline for each `item`
960
+ - `type`: The resource type for the summary. For now `issues`, `merge_requests`, or `epics`,
961
+
962
+ > **Note:**
963
+ > - Both `item` and `summary` fields act like a [comment action](#comment-action),
964
+ > therefore [Ruby expression](#ruby-expression) is supported.
965
+ > - Placeholders work regularly for `item`, but for `summary` only `{{title}}`,
966
+ > `{{items}}`, `{{type}}` are supported because it's not tied to a particular
967
+ > resource like the comment action.
968
+ > - No issues will be created if:
969
+ > - the specific policy doesn't yield any resources; or
970
+ > - the source type is a group and `destination` is not set.
971
+ > - `redact_confidential_resources` defaults to `true`, so fields on
972
+ > confidential resources will be converted to `(confidential)` except for
973
+ > `{{web_url}}`. Setting it to `false` will reveal the confidential fields.
974
+ > This will be useful if the summary is confidential itself (not implemented
975
+ > yet), or if we're posting to another private project (not implemented yet).
976
+
977
+ Example:
978
+
979
+ ```yml
980
+ resource_rules:
981
+ issues:
982
+ rules:
983
+ - name: Issues require labels
984
+ limits:
985
+ most_recent: 15
986
+ actions:
987
+ summarize:
988
+ title: |
989
+ #{resource[:type].capitalize} require labels
990
+ item: |
991
+ - [ ] [{{title}}]({{web_url}}) {{labels}}
992
+ summary: |
993
+ The following {{type}} require labels:
994
+
995
+ {{items}}
996
+
997
+ Please take care of them before the end of #{7.days.from_now.strftime('%Y-%m-%d')}
998
+
999
+ /label ~"needs attention"
1000
+ ```
1001
+
1002
+ Which could generate an issue like:
1003
+
1004
+ * Title:
1005
+ ```
1006
+ Issues require labels
1007
+ ```
1008
+ * Description:
1009
+ ``` markdown
1010
+ The following issues require labels:
1011
+
1012
+ - [ ] [An example issue](http://example.com/group/project/issues/1) ~"label A", ~"label B"
1013
+ - [ ] [Another issue](http://example.com/group/project/issues/2) ~"label B", ~"label C"
1014
+
1015
+ Please take care of them before the end of 2000-01-01
1016
+
1017
+ /label ~"needs attention"
1018
+ ```
1019
+
1020
+ ##### Comment on summary action
1021
+
1022
+ Generates one comment for each resource, attaching these comments to the summary
1023
+ created by the [`summarize` action](#summarize-action).
1024
+
1025
+ The use case for this is wanting to create a summary with an overview, and then
1026
+ a threaded discussion for each resource, with a header comment starting each
1027
+ discussion.
1028
+
1029
+ Accepts a single string value: the template used to generate the comments. For
1030
+ details of the syntax of this template, see the [comment action](#comment-action).
1031
+
1032
+ Since this action depends on the summary, it is invalid to supply a
1033
+ `comment_on_summary` action without an accompanying `summarize` sibling action.
1034
+ The `summarize` action will always be completed first.
1035
+
1036
+ Just like for [comment action](#comment-action), setting `comment_type` in the
1037
+ `actions` set controls whether the comment must be resolved for merge requests.
1038
+ See: [`comment_type` action option](#comment-type-action-option).
1039
+
1040
+ Example:
1041
+
1042
+ ```yml
1043
+ resource_rules:
1044
+ issues:
1045
+ rules:
1046
+ - name: List of issues to discuss
1047
+ limits:
1048
+ most_recent: 15
1049
+ actions:
1050
+ comment_type: thread
1051
+ comment_on_summary: |
1052
+ # {{title}}
1053
+
1054
+ author: {{author}}
1055
+ summarize:
1056
+ title: |
1057
+ #{resource[:type].capitalize} require labels
1058
+ item: |
1059
+ - [ ] [{{title}}]({{web_url}}) {{labels}}
1060
+ summary: |
1061
+ The following {{type}} require labels:
1062
+
1063
+ {{items}}
1064
+
1065
+ Please take care of them before the end of #{7.days.from_now.strftime('%Y-%m-%d')}
1066
+
1067
+ /label ~"needs attention"
1068
+ ```
1069
+
1070
+ ##### Create a new issue from each resource
1071
+
1072
+ Generates one issue for each resource, by default in the same project as the resource.
1073
+
1074
+ The use case for this is, for example, creating test issues in the same (or different)
1075
+ project for issues labeled "extended-testing"; or automatically splitting one issue with a
1076
+ certain label into multiple ones.
1077
+
1078
+ Accepts a hash of fields.
1079
+
1080
+ | Field | Type | Description | Required | Placeholders | Ruby expression | Default |
1081
+ | ---- | ---- | ---- | ---- | ---- | ---- | ---- |
1082
+ | `title` | string | The title of the generated issue | yes | yes | yes | |
1083
+ | `destination` | integer or string | The project ID or path to create the generated issue in | no | no | no | source project |
1084
+ | `description` | string | The description of the generated issue | no | yes | yes | |
1085
+ | `redact_confidential_resources` | boolean | Whether redact fields for confidential resources | no | no | no | true |
1086
+
1087
+ The placeholders available in `title` and `destination` are the properties of the resource being used to generate the issue.
1088
+
1089
+ Example
1090
+
1091
+ ```yml
1092
+ resource_rules:
1093
+ issues:
1094
+ rules:
1095
+ - name: Issues requiring extra testing
1096
+ labels:
1097
+ - needs-testing
1098
+ actions:
1099
+ issue:
1100
+ title: |
1101
+ Testing: {{ title }}
1102
+ description: |
1103
+ The issue {{ full_reference }} needs testing.
1104
+
1105
+ Please take care of them before the end of #{7.days.from_now.strftime('%Y-%m-%d')}
1106
+
1107
+ /label ~"needs attention"
1108
+ ```
1109
+
1110
+ ##### Delete action
1111
+
1112
+ **This action is only applicable for branches.**
1113
+
1114
+ Delete the resource.
1115
+
1116
+ Accept a boolean. Set to `true` to enable.
1117
+
1118
+ Example :
1119
+ ```yaml
1120
+ resource_rules:
1121
+ branches:
1122
+ rules:
1123
+ - name: My branch policy
1124
+ conditions:
1125
+ date:
1126
+ attribute: committed_date
1127
+ condition: older_than
1128
+ interval_type: months
1129
+ interval: 30
1130
+ actions:
1131
+ delete: true
1132
+ ```
1133
+
1134
+ ### Summary policies
1135
+
1136
+ Summary policies are special policies that join multiple rule policies together
1137
+ to create a summary issue with all the sub-policies' summaries.
1138
+ They have the same structure as Rule policies that define `actions.summarize`.
1139
+
1140
+ One key difference is that the `{{items}}` placeholder represents the array of
1141
+ sub-policies' summary.
1142
+
1143
+ Note that only the `summarize` keys in the sub-policies' `actions` is used. Any
1144
+ other keys (e.g. `mention`, `comment`, `labels` etc.) are ignored.
1145
+
1146
+ You can define such policy as follows:
1147
+
1148
+ ```yml
1149
+ resource_rules:
1150
+ issues:
1151
+ summaries:
1152
+ - name: Newest and oldest issues summary
1153
+ rules:
1154
+ - name: New issues
1155
+ conditions:
1156
+ state: opened
1157
+ limits:
1158
+ most_recent: 2
1159
+ actions:
1160
+ summarize:
1161
+ item: "- [ ] [{{title}}]({{web_url}}) {{labels}}"
1162
+ summary: |
1163
+ Please triage the following new {{type}}:
1164
+
1165
+ {{items}}
1166
+ - name: Old issues
1167
+ conditions:
1168
+ state: opened
1169
+ limits:
1170
+ oldest: 2
1171
+ actions:
1172
+ summarize:
1173
+ item: "- [ ] [{{title}}]({{web_url}}) {{labels}}"
1174
+ summary: |
1175
+ Please triage the following old {{type}}:
1176
+
1177
+ {{items}}
1178
+ actions:
1179
+ summarize:
1180
+ title: "Newest and oldest {{type}} summary"
1181
+ summary: |
1182
+ Please triage the following {{type}}:
1183
+
1184
+ {{items}}
1185
+
1186
+ Please take care of them before the end of #{7.days.from_now.strftime('%Y-%m-%d')}
1187
+
1188
+ /label ~"needs attention"
1189
+ ```
1190
+
1191
+ Which could generate an issue like:
1192
+
1193
+ * Title:
1194
+ ```
1195
+ Newest and oldest issues summary
1196
+ ```
1197
+ * Description:
1198
+ ``` markdown
1199
+ Please triage the following issues:
1200
+
1201
+ Please triage the following new issues:
1202
+
1203
+ - [ ] [A new issue](http://example.com/group/project/issues/4)
1204
+ - [ ] [Another new issue](http://example.com/group/project/issues/3) ~"label B", ~"label C"
1205
+
1206
+ Please triage the following old issues:
1207
+
1208
+ - [ ] [An old issue](http://example.com/group/project/issues/1) ~"label A", ~"label B"
1209
+ - [ ] [Another old issue](http://example.com/group/project/issues/2) ~"label C"
1210
+
1211
+ Please take care of them before the end of 2000-01-01
1212
+
1213
+ /label ~"needs attention"
1214
+ ```
1215
+
1216
+ > **Note:** If a specific policy doesn't yield any resources, it will not
1217
+ > generate the corresponding description. If all policies yield no resources,
1218
+ > then no issues will be created.
1219
+
1220
+ ### Ruby expression API
1221
+
1222
+ Here's a list of currently available Ruby expression API:
1223
+
1224
+ ##### Methods for `Issue` and `MergeRequest` (the context)
1225
+
1226
+ | Name | Return type | Description |
1227
+ | ---- | ---- | ---- |
1228
+ | resource | Hash | The hash containing the raw data of the resource. Note that `resource[:type]` is the type of the policy (`issues`, `merge_requests`, or `epics`), not the API `type` field. |
1229
+ | author | String | The username of the resource author |
1230
+ | state | String | The state of the resource |
1231
+ | milestone | Milestone | The milestone attached to the resource |
1232
+ | labels | [Label] | A list of labels, having only names |
1233
+ | labels_with_details | [Label] | A list of labels which has more information loaded from another API request |
1234
+ | labels_chronologically | [Label] | Same as `labels_with_details` but sorted chronologically |
1235
+ | label_events | [LabelEvent] | A list of label events on the resource |
1236
+ | instance_version | InstanceVersion | The version for the GitLab instance we're triaging with |
1237
+ | project_path | String | The path with namespace to the issues or merge requests project |
1238
+ | full_resource_reference | String | A full reference including project path to the issue or merge request |
1239
+
1240
+ ##### Methods for `Issue` and `LinkedIssue` (issue context)
1241
+
1242
+ | Name | Return type | Description |
1243
+ | ---- | ---- | ---- |
1244
+ | merge_requests_count | Integer | The number of merge requests related to the issue |
1245
+ | related_merge_requests | [MergeRequest] | The list of merge requests related to the issue |
1246
+ | closed_by | [MergeRequest] | The list of merge requests that close the issue |
1247
+ | linked_issues | [LinkedIssue] | The list of issues that are linked to the issue |
1248
+ | due_date | Date | The due date of the issue. Could be `nil` |
1249
+
1250
+ ##### Methods for `LinkedIssue`
1251
+
1252
+ | Method | Return type | Description |
1253
+ | ---- | ---- | ---- |
1254
+ | link_type | String | The link type of the linked issue (`blocks`, `is_blocked_by`, or `relates_to`) |
1255
+
1256
+ ##### Methods for `MergeRequest` (merge request context)
1257
+
1258
+ | Method | Return type | Description |
1259
+ | ---- | ---- | ---- |
1260
+ | first_contribution? | Boolean | `true` if it's the author's first contribution to the project; `false` otherwise. This API requires an additional API request for the merge request, thus would be slower. |
1261
+
1262
+ ##### Methods for `Milestone`
1263
+
1264
+ | Method | Return type | Description |
1265
+ | ---- | ---- | ---- |
1266
+ | id | Integer | The id of the milestone |
1267
+ | iid | Integer | The iid of the milestone |
1268
+ | project_id | Integer | The project id of the milestone if available |
1269
+ | group_id | Integer | The group id of the milestone if available |
1270
+ | title | String | The title of the milestone |
1271
+ | description | String | The description of the milestone |
1272
+ | state | String | The state of the milestone. Could be `active` or `closed` |
1273
+ | due_date | Date | The due date of the milestone. Could be `nil` |
1274
+ | start_date | Date | The start date of the milestone. Could be `nil` |
1275
+ | updated_at | Time | The updated timestamp of the milestone |
1276
+ | created_at | Time | The created timestamp of the milestone |
1277
+ | succ | Milestone | The next active milestone beside this milestone |
1278
+ | active? | Boolean | `true` if `state` is `active`; `false` otherwise |
1279
+ | closed? | Boolean | `true` if `state` is `closed`; `false` otherwise |
1280
+ | started? | Boolean | `true` if `start_date` exists and in the past; `false` otherwise |
1281
+ | expired? | Boolean | `true` if `due_date` exists and in the past; `false` otherwise |
1282
+ | in_progress?| Boolean | `true` if `started?` and `!expired`; `false` otherwise |
1283
+
1284
+ ##### Methods for `Label`
1285
+
1286
+ | Method | Return type | Description |
1287
+ | ---- | ---- | ---- |
1288
+ | id | Integer | The id of the label |
1289
+ | project_id | Integer | The project id of the label if available |
1290
+ | group_id | Integer | The group id of the label if available |
1291
+ | name | String | The name of the label |
1292
+ | description | String | The description of the label |
1293
+ | color | String | The color of the label in RGB |
1294
+ | priority | Integer | The priority of the label |
1295
+ | added_at | Time | When the label was added to the resource |
1296
+
1297
+ ##### Methods for `LabelEvent`
1298
+
1299
+ | Method | Return type | Description |
1300
+ | ---- | ---- | ---- |
1301
+ | id | Integer | The id of the label event |
1302
+ | resource_type | String | The resource type of the event. Could be `Issue` or `MergeRequest` |
1303
+ | resource_id | Integer | The id of the resource |
1304
+ | action | String | The action of the event. Could be `add` or `remove` |
1305
+ | created_at | Time | When the event happened |
1306
+
1307
+ ##### Methods for `InstanceVersion`
1308
+
1309
+ | Method | Return type | Description |
1310
+ | ---- | ---- | ---- |
1311
+ | version | String | The full string of version. e.g. `11.3.0-rc11-ee` |
1312
+ | version_short | String | The short string of version. e.g. `11.3` |
1313
+ | revision | String | The revision of GitLab. e.g. `231b0c7` |
1314
+
1315
+ ### Installation
1316
+
1317
+ gem install gitlab-triage
1318
+
1319
+ ### Usage
1320
+
1321
+ gitlab-triage --help
1322
+
1323
+ Will show:
1324
+
1325
+ ```
1326
+ Usage: gitlab-triage [options]
1327
+
1328
+ -n, --dry-run Don't actually update anything, just print
1329
+ -f, --policies-file [string] A valid policies YML file
1330
+ --all-projects Process all projects the token has access to
1331
+ -s, --source [type] The source type between [ projects or groups ], default value: projects
1332
+ -i, --source-id [string] Source ID or path
1333
+ -p, --project-id [string] [Deprecated] A project ID or path, please use `--source-id`
1334
+ --resource-reference [string]
1335
+ Resource short-reference, e.g. #42, !33, or &99
1336
+ -t, --token [string] A valid API token
1337
+ -H, --host-url [string] A valid host url
1338
+ -r, --require [string] Require a file before performing
1339
+ -d, --debug Print debug information
1340
+ -h, --help Print help message
1341
+ -v, --version Print version
1342
+ --init Initialize the project with a policy file
1343
+ --init-ci Initialize the project with a .gitlab-ci.yml file
1344
+ ```
1345
+
1346
+ #### Running with the installed gem
1347
+
1348
+ Triaging against a specific project:
1349
+
1350
+ ```
1351
+ gitlab-triage --dry-run --token $GITLAB_API_TOKEN --source-id gitlab-org/triage
1352
+ ```
1353
+
1354
+ Triaging against a whole group:
1355
+
1356
+ ```
1357
+ gitlab-triage --dry-run --token $GITLAB_API_TOKEN --source-id gitlab-org --source groups
1358
+ ```
1359
+
1360
+ Triaging against an entire instance:
1361
+
1362
+ ```
1363
+ gitlab-triage --dry-run --token $GITLAB_API_TOKEN --all-projects
1364
+ ```
1365
+
1366
+ > **Note:** The `--all-projects` option will process all resources for all projects visible to the specified `$GITLAB_API_TOKEN`
1367
+
1368
+ #### Running from source
1369
+
1370
+ Execute the `gitlab-triage` script from the `./bin` directory.
1371
+
1372
+ For example- after cloning this project, from the root `gitlab-triage` directory:
1373
+
1374
+ ```
1375
+ bundle exec bin/gitlab-triage --dry-run --token $GITLAB_API_TOKEN --source-id gitlab-org/triage
1376
+ ```
1377
+
1378
+ Triaging against specific resource:
1379
+
1380
+ ```
1381
+ gitlab-triage --dry-run --token $API_TOKEN --source-id gitlab-org/triage --resource-reference '#42'
1382
+ gitlab-triage --dry-run --token $API_TOKEN --source-id gitlab-org/triage --resource-reference '!33'
1383
+ gitlab-triage --dry-run --token $API_TOKEN --source groups --source-id gitlab-org --resource-reference '&99'
1384
+ ```
1385
+
1386
+ #### Running on GitLab CI pipeline
1387
+
1388
+ You can enforce policies using a scheduled pipeline:
1389
+
1390
+ ```yml
1391
+ run:triage:triage:
1392
+ stage: triage
1393
+ script:
1394
+ - gem install gitlab-triage
1395
+ - gitlab-triage --token $GITLAB_API_TOKEN --source-id $CI_PROJECT_PATH
1396
+ rules:
1397
+ - if: $CI_PIPELINE_SOURCE == "schedule"
1398
+ ```
1399
+
1400
+ > **Note:** You can use the [`--init-ci`](#usage) option to add an example [`.gitlab-ci.yml` file](support/.gitlab-ci.example.yml) to your project
1401
+
1402
+ #### Can I use gitlab-triage for my self-hosted GitLab instance?
1403
+
1404
+ Yes, you can override the host url using the following options:
1405
+
1406
+ ##### CLI
1407
+
1408
+ ```
1409
+ gitlab-triage --dry-run --token $GITLAB_API_TOKEN --source-id gitlab-org/triage --host-url https://gitlab.host.com
1410
+ ```
1411
+
1412
+ ##### Policy file
1413
+
1414
+ ```yml
1415
+ host_url: https://gitlab.host.com
1416
+ resource_rules:
1417
+ ```
1418
+
1419
+ #### Can I customize?
1420
+
1421
+ You can take the advantage of command line option `-r` or `--require` to
1422
+ load a Ruby file before performing the actions. This allows you to do
1423
+ whatever you want. For example, you can put this in a file like `my_plugin.rb`:
1424
+
1425
+ ```ruby
1426
+ module MyPlugin
1427
+ def has_severity_label?
1428
+ labels.grep(/^S\d+$/).any?
1429
+ end
1430
+
1431
+ def has_priority_label?
1432
+ labels.grep(/^P\d+$/).any?
1433
+ end
1434
+
1435
+ def labels
1436
+ resource[:labels]
1437
+ end
1438
+ end
1439
+
1440
+ Gitlab::Triage::Resource::Context.include MyPlugin
1441
+ ```
1442
+
1443
+ And then run it with:
1444
+
1445
+ ```shell
1446
+ gitlab-triage -r ./my_plugin.rb --token $GITLAB_API_TOKEN --source-id gitlab-org/triage
1447
+ ```
1448
+
1449
+ This allows you to use `has_severity_label?` in the Ruby condition:
1450
+
1451
+ ```yml
1452
+ resource_rules:
1453
+ issues:
1454
+ rules:
1455
+ - name: Apply default severity or priority labels
1456
+ conditions:
1457
+ ruby: |
1458
+ !has_severity_label? || !has_priority_label?
1459
+ actions:
1460
+ comment: |
1461
+ #{'/label ~S3' unless has_severity_label?}
1462
+ #{'/label ~P3' unless has_priority_label?}
1463
+ ```
1464
+
1465
+ ### Contributing
1466
+
1467
+ Please refer to the [Contributing Guide](CONTRIBUTING.md).
1468
+
1469
+ ## Release Process
1470
+
1471
+ We release `gitlab-triage` on an ad-hoc basis. There is no regularity to when
1472
+ we release, we just release when we make a change - no matter the size of the
1473
+ change.
1474
+
1475
+ To release a new version:
1476
+
1477
+ 1. Create a Merge Request.
1478
+ 1. Use Merge Request template [Release.md](https://gitlab.com/gitlab-org/ruby/gems/gitlab-triage/-/blob/master/.gitlab/merge_request_templates/Release.md).
1479
+ 1. Follow the instructions.
1480
+ 1. After the Merge Request has been merged, a new gem version is [published automatically](https://gitlab.com/gitlab-org/quality/pipeline-common/-/blob/master/ci/gem-release.yml)