gitlab-triage 1.9.0 → 1.13.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/.gitlab-ci.yml +6 -25
- data/.gitlab/merge_request_templates/Release.md +3 -3
- data/Guardfile +1 -1
- data/README.md +34 -7
- data/lib/gitlab/triage/action/comment.rb +2 -2
- data/lib/gitlab/triage/api_query_builders/date_query_param_builder.rb +78 -0
- data/lib/gitlab/triage/command_builders/base_command_builder.rb +7 -3
- data/lib/gitlab/triage/command_builders/label_command_builder.rb +17 -0
- data/lib/gitlab/triage/command_builders/text_content_builder.rb +1 -5
- data/lib/gitlab/triage/engine.rb +17 -16
- data/lib/gitlab/triage/filters/merge_request_date_conditions_filter.rb +51 -5
- data/lib/gitlab/triage/policies/rule_policy.rb +1 -1
- data/lib/gitlab/triage/policies/summary_policy.rb +1 -1
- data/lib/gitlab/triage/policies_resources/rule_resources.rb +3 -13
- data/lib/gitlab/triage/policies_resources/summary_resources.rb +3 -13
- data/lib/gitlab/triage/resource/base.rb +5 -1
- data/lib/gitlab/triage/resource/label.rb +15 -0
- data/lib/gitlab/triage/url_builders/url_builder.rb +7 -3
- data/lib/gitlab/triage/validators/params_validator.rb +5 -3
- data/lib/gitlab/triage/version.rb +1 -1
- data/support/.gitlab-ci.example.yml +2 -2
- metadata +3 -4
- data/lib/gitlab/triage/filters/forbidden_labels_conditions_filter.rb +0 -32
- data/lib/gitlab/triage/filters/issuable_date_conditions_filter.rb +0 -65
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 68fbfe16d2db2547d8b262ff52cb7065860d13822a92b38d6d505234aafa0855
|
|
4
|
+
data.tar.gz: 99dc42b1125665a331b8dd6afe576e1c0b8b0abbd0cf8239d5be44184e900c52
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 37e60f6230d1467d18246aa4dc52f439c08939f5a7e2278ed543090c08d5c08b39bffc2840543cbd0a702480d8fbeeb65dc7932fe90a98c2d26a88c8b19f3805
|
|
7
|
+
data.tar.gz: 8f82804d8431b08791f3e37974a0cc47aacec887af2969f3e612cba8ac8212e0ac6a25f4235424801b01f6eb0d5bc6db72535d0fed1f962658270164613034cd
|
data/.gitlab-ci.yml
CHANGED
|
@@ -2,7 +2,7 @@ stages:
|
|
|
2
2
|
- prepare
|
|
3
3
|
- test
|
|
4
4
|
- triage
|
|
5
|
-
-
|
|
5
|
+
- deploy
|
|
6
6
|
|
|
7
7
|
default:
|
|
8
8
|
image: ruby:2.7
|
|
@@ -38,6 +38,7 @@ workflow:
|
|
|
38
38
|
services:
|
|
39
39
|
- docker:${DOCKER_VERSION}-dind
|
|
40
40
|
variables:
|
|
41
|
+
DOCKER_VERSION: "19.03.0"
|
|
41
42
|
DOCKER_DRIVER: overlay2
|
|
42
43
|
DOCKER_HOST: tcp://docker:2375
|
|
43
44
|
DOCKER_TLS_CERTDIR: ""
|
|
@@ -118,7 +119,7 @@ dry-run:gitlab-triage:
|
|
|
118
119
|
- gitlab-triage --version
|
|
119
120
|
- gitlab-triage --help
|
|
120
121
|
- gitlab-triage --init
|
|
121
|
-
- gitlab-triage --dry-run --debug --token $
|
|
122
|
+
- gitlab-triage --dry-run --debug --token $GITLAB_API_TOKEN --source-id $CI_PROJECT_PATH
|
|
122
123
|
|
|
123
124
|
# This job requires allows to override the `CI_PROJECT_PATH` variable when triggered.
|
|
124
125
|
dry-run:custom:
|
|
@@ -127,26 +128,6 @@ dry-run:custom:
|
|
|
127
128
|
- when: manual
|
|
128
129
|
allow_failure: true
|
|
129
130
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
release:
|
|
134
|
-
stage: release
|
|
135
|
-
rules:
|
|
136
|
-
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $CI_PIPELINE_SOURCE == "push"'
|
|
137
|
-
changes: ["lib/gitlab/triage/version.rb"]
|
|
138
|
-
- if: '$CI_MERGE_REQUEST_TITLE =~ /RELEASE/'
|
|
139
|
-
when: manual
|
|
140
|
-
before_script: []
|
|
141
|
-
script:
|
|
142
|
-
- version=$(ruby -r ./lib/gitlab/triage/version -e 'puts Gitlab::Triage::VERSION' | tr -d "\n")
|
|
143
|
-
- tag="v${version}"
|
|
144
|
-
- message="Version ${version}."
|
|
145
|
-
# TODO: Add release notes from the Release MR?
|
|
146
|
-
- 'curl --request POST --header "PRIVATE-TOKEN: ${API_TOKEN}" -d "tag_name=${tag}" -d "ref=${CI_COMMIT_SHA}" -d "message=${message}" "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/repository/tags"'
|
|
147
|
-
- gem build gitlab-triage.gemspec
|
|
148
|
-
- gem push "gitlab-triage-${version}.gem"
|
|
149
|
-
artifacts:
|
|
150
|
-
paths:
|
|
151
|
-
- gitlab-triage*.gem
|
|
152
|
-
expire_in: 30 days
|
|
131
|
+
include:
|
|
132
|
+
- project: 'gitlab-org/quality/pipeline-common'
|
|
133
|
+
file: '/ci/gem-release.yml'
|
|
@@ -7,7 +7,7 @@ with the latest commit from https://gitlab.com/gitlab-org/gitlab-triage/commits/
|
|
|
7
7
|
<!-- Keep the sections order but remove the empty sections -->
|
|
8
8
|
|
|
9
9
|
```markdown
|
|
10
|
-
### New
|
|
10
|
+
### New features and features updates
|
|
11
11
|
|
|
12
12
|
- !aaa <Title of the aaa MR>.
|
|
13
13
|
|
|
@@ -19,7 +19,7 @@ with the latest commit from https://gitlab.com/gitlab-org/gitlab-triage/commits/
|
|
|
19
19
|
|
|
20
20
|
- !ccc <Title of the ccc MR>.
|
|
21
21
|
|
|
22
|
-
### Other changes (
|
|
22
|
+
### Other changes (tooling, technical debt)
|
|
23
23
|
|
|
24
24
|
- !ddd <Title of the ddd MR>.
|
|
25
25
|
```
|
|
@@ -32,4 +32,4 @@ with the latest commit from https://gitlab.com/gitlab-org/gitlab-triage/commits/
|
|
|
32
32
|
- Checklist after merging:
|
|
33
33
|
- [ ] [Update the release notes for the newly created tag](docs/release_process.md#how-to).
|
|
34
34
|
|
|
35
|
-
/label ~"Engineering Productivity" ~"ep::triage"
|
|
35
|
+
/label ~"Engineering Productivity" ~"ep::triage" ~"tooling::workflow"
|
data/Guardfile
CHANGED
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
# * zeus: 'zeus rspec' (requires the server to be started separately)
|
|
25
25
|
# * 'just' rspec: 'rspec'
|
|
26
26
|
|
|
27
|
-
guard :rspec, cmd: "bundle exec rspec" do
|
|
27
|
+
guard :rspec, cmd: "bundle exec rspec -f doc" do
|
|
28
28
|
require "guard/rspec/dsl"
|
|
29
29
|
dsl = Guard::RSpec::Dsl.new(self)
|
|
30
30
|
|
data/README.md
CHANGED
|
@@ -141,6 +141,7 @@ Available condition types:
|
|
|
141
141
|
- [`assignee_member` condition](#assignee-member-condition)
|
|
142
142
|
- [`source_branch` condition](#source-branch-condition)
|
|
143
143
|
- [`target_branch` condition](#target-branch-condition)
|
|
144
|
+
- [`weight` condition](#weight-condition)
|
|
144
145
|
- [`ruby` condition](#ruby-condition)
|
|
145
146
|
|
|
146
147
|
##### Date condition
|
|
@@ -467,6 +468,24 @@ conditions:
|
|
|
467
468
|
target_branch: 'master'
|
|
468
469
|
```
|
|
469
470
|
|
|
471
|
+
##### Weight condition
|
|
472
|
+
|
|
473
|
+
Accepts a string per the [API documentation](https://docs.gitlab.com/ee/api/issues.html#list-issues).
|
|
474
|
+
This condition is only applicable for issues (not merge requests).
|
|
475
|
+
|
|
476
|
+
| State | Type | Value |
|
|
477
|
+
| --------- | ---- | ------ |
|
|
478
|
+
| Any weight | string | `Any` |
|
|
479
|
+
| No weight | string | `None` |
|
|
480
|
+
| Specific weight | integer | integer |
|
|
481
|
+
|
|
482
|
+
Example:
|
|
483
|
+
|
|
484
|
+
```yml
|
|
485
|
+
conditions:
|
|
486
|
+
weight: Any
|
|
487
|
+
```
|
|
488
|
+
|
|
470
489
|
##### Ruby condition
|
|
471
490
|
|
|
472
491
|
This condition allows users to write a Ruby expression to be evaluated for
|
|
@@ -552,6 +571,10 @@ Adds a number of labels to the resource.
|
|
|
552
571
|
|
|
553
572
|
Accepts an array of strings. Each element is the name of a label to add.
|
|
554
573
|
|
|
574
|
+
If any of the labels doesn't exist, the automation will stop immediately so
|
|
575
|
+
that if a label is renamed or deleted, you'll have to explicitly update or remove
|
|
576
|
+
it in your policy file.
|
|
577
|
+
|
|
555
578
|
Example:
|
|
556
579
|
|
|
557
580
|
```yml
|
|
@@ -567,6 +590,10 @@ Removes a number of labels from the resource.
|
|
|
567
590
|
|
|
568
591
|
Accepts an array of strings. Each element is the name of a label to remove.
|
|
569
592
|
|
|
593
|
+
If any of the labels doesn't exist, the automation will stop immediately so
|
|
594
|
+
that if a label is renamed or deleted, you'll have to explicitly update or remove
|
|
595
|
+
it in your policy file.
|
|
596
|
+
|
|
570
597
|
Example:
|
|
571
598
|
|
|
572
599
|
```yml
|
|
@@ -1016,22 +1043,22 @@ Usage: gitlab-triage [options]
|
|
|
1016
1043
|
Triaging against a specific project:
|
|
1017
1044
|
|
|
1018
1045
|
```
|
|
1019
|
-
gitlab-triage --dry-run --token $
|
|
1046
|
+
gitlab-triage --dry-run --token $GITLAB_API_TOKEN --source-id gitlab-org/triage
|
|
1020
1047
|
```
|
|
1021
1048
|
|
|
1022
1049
|
Triaging against a whole group:
|
|
1023
1050
|
|
|
1024
1051
|
```
|
|
1025
|
-
gitlab-triage --dry-run --token $
|
|
1052
|
+
gitlab-triage --dry-run --token $GITLAB_API_TOKEN --source-id gitlab-org --source groups
|
|
1026
1053
|
```
|
|
1027
1054
|
|
|
1028
1055
|
Triaging against an entire instance:
|
|
1029
1056
|
|
|
1030
1057
|
```
|
|
1031
|
-
gitlab-triage --dry-run --token $
|
|
1058
|
+
gitlab-triage --dry-run --token $GITLAB_API_TOKEN --all-projects
|
|
1032
1059
|
```
|
|
1033
1060
|
|
|
1034
|
-
> **Note:** The `--all-projects` option will process all resources for all projects visible to the specified `$
|
|
1061
|
+
> **Note:** The `--all-projects` option will process all resources for all projects visible to the specified `$GITLAB_API_TOKEN`
|
|
1035
1062
|
|
|
1036
1063
|
#### Running on GitLab CI pipeline
|
|
1037
1064
|
|
|
@@ -1042,7 +1069,7 @@ run:triage:triage:
|
|
|
1042
1069
|
stage: triage
|
|
1043
1070
|
script:
|
|
1044
1071
|
- gem install gitlab-triage
|
|
1045
|
-
- gitlab-triage --token $
|
|
1072
|
+
- gitlab-triage --token $GITLAB_API_TOKEN --source-id $CI_PROJECT_PATH
|
|
1046
1073
|
only:
|
|
1047
1074
|
- schedules
|
|
1048
1075
|
```
|
|
@@ -1056,7 +1083,7 @@ Yes, you can override the host url using the following options:
|
|
|
1056
1083
|
##### CLI
|
|
1057
1084
|
|
|
1058
1085
|
```
|
|
1059
|
-
gitlab-triage --dry-run --token $
|
|
1086
|
+
gitlab-triage --dry-run --token $GITLAB_API_TOKEN --source-id gitlab-org/triage --host-url https://gitlab.host.com
|
|
1060
1087
|
```
|
|
1061
1088
|
|
|
1062
1089
|
##### Policy file
|
|
@@ -1093,7 +1120,7 @@ Gitlab::Triage::Resource::Context.include MyPlugin
|
|
|
1093
1120
|
And then run it with:
|
|
1094
1121
|
|
|
1095
1122
|
```shell
|
|
1096
|
-
gitlab-triage -r ./my_plugin.rb --token $
|
|
1123
|
+
gitlab-triage -r ./my_plugin.rb --token $GITLAB_API_TOKEN --source-id gitlab-org/triage
|
|
1097
1124
|
```
|
|
1098
1125
|
|
|
1099
1126
|
This allows you to use `has_severity_label?` in the Ruby condition:
|
|
@@ -41,8 +41,8 @@ module Gitlab
|
|
|
41
41
|
CommandBuilders::CommentCommandBuilder.new(
|
|
42
42
|
[
|
|
43
43
|
CommandBuilders::TextContentBuilder.new(policy.actions[:comment], resource: resource, network: network).build_command,
|
|
44
|
-
CommandBuilders::LabelCommandBuilder.new(policy.actions[:labels]).build_command,
|
|
45
|
-
CommandBuilders::RemoveLabelCommandBuilder.new(policy.actions[:remove_labels]).build_command,
|
|
44
|
+
CommandBuilders::LabelCommandBuilder.new(policy.actions[:labels], resource: resource, network: network).build_command,
|
|
45
|
+
CommandBuilders::RemoveLabelCommandBuilder.new(policy.actions[:remove_labels], resource: resource, network: network).build_command,
|
|
46
46
|
CommandBuilders::CcCommandBuilder.new(policy.actions[:mention]).build_command,
|
|
47
47
|
CommandBuilders::MoveCommandBuilder.new(policy.actions[:move]).build_command,
|
|
48
48
|
CommandBuilders::StatusCommandBuilder.new(policy.actions[:status]).build_command
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
require_relative '../validators/params_validator'
|
|
2
|
+
|
|
3
|
+
module Gitlab
|
|
4
|
+
module Triage
|
|
5
|
+
module APIQueryBuilders
|
|
6
|
+
class DateQueryParamBuilder
|
|
7
|
+
ATTRIBUTES = %w[updated_at created_at].freeze
|
|
8
|
+
CONDITIONS = %w[older_than newer_than].freeze
|
|
9
|
+
INTERVAL_TYPES = %w[days weeks months years].freeze
|
|
10
|
+
|
|
11
|
+
def self.filter_parameters
|
|
12
|
+
[
|
|
13
|
+
{
|
|
14
|
+
name: :attribute,
|
|
15
|
+
type: String,
|
|
16
|
+
values: ATTRIBUTES
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
name: :condition,
|
|
20
|
+
type: String,
|
|
21
|
+
values: CONDITIONS
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
name: :interval_type,
|
|
25
|
+
type: String,
|
|
26
|
+
values: INTERVAL_TYPES
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
name: :interval,
|
|
30
|
+
type: Numeric
|
|
31
|
+
}
|
|
32
|
+
]
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def self.applicable?(condition)
|
|
36
|
+
ATTRIBUTES.include?(condition[:attribute].to_s)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def initialize(condition_hash)
|
|
40
|
+
@attribute = condition_hash[:attribute].to_s
|
|
41
|
+
@interval_condition = condition_hash[:condition].to_sym
|
|
42
|
+
@interval_type = condition_hash[:interval_type]
|
|
43
|
+
@interval = condition_hash[:interval]
|
|
44
|
+
validate_condition(condition_hash)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def validate_condition(condition)
|
|
48
|
+
ParamsValidator.new(self.class.filter_parameters, condition).validate!
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def param_name
|
|
52
|
+
prefix = attribute.sub(/_at\z/, '')
|
|
53
|
+
suffix =
|
|
54
|
+
case interval_condition
|
|
55
|
+
when :older_than
|
|
56
|
+
'before'
|
|
57
|
+
when :newer_than
|
|
58
|
+
'after'
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
"#{prefix}_#{suffix}"
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def param_content
|
|
65
|
+
interval.public_send(interval_type).ago.to_date # rubocop:disable GitlabSecurity/PublicSend
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def build_param
|
|
69
|
+
"&#{param_name}=#{param_content.strip}"
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
private
|
|
73
|
+
|
|
74
|
+
attr_reader :condition_hash, :attribute, :interval_condition, :interval_type, :interval
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -2,13 +2,15 @@ module Gitlab
|
|
|
2
2
|
module Triage
|
|
3
3
|
module CommandBuilders
|
|
4
4
|
class BaseCommandBuilder
|
|
5
|
-
def initialize(items)
|
|
5
|
+
def initialize(items, resource: nil, network: nil)
|
|
6
6
|
@items = Array.wrap(items)
|
|
7
7
|
@items.delete('')
|
|
8
|
+
@resource = resource&.with_indifferent_access
|
|
9
|
+
@network = network
|
|
8
10
|
end
|
|
9
11
|
|
|
10
12
|
def build_command
|
|
11
|
-
if
|
|
13
|
+
if items.any?
|
|
12
14
|
[slash_command_string, content_string].compact.join(separator)
|
|
13
15
|
else
|
|
14
16
|
""
|
|
@@ -17,6 +19,8 @@ module Gitlab
|
|
|
17
19
|
|
|
18
20
|
private
|
|
19
21
|
|
|
22
|
+
attr_reader :items, :resource, :network
|
|
23
|
+
|
|
20
24
|
def separator
|
|
21
25
|
' '
|
|
22
26
|
end
|
|
@@ -26,7 +30,7 @@ module Gitlab
|
|
|
26
30
|
end
|
|
27
31
|
|
|
28
32
|
def content_string
|
|
29
|
-
|
|
33
|
+
items.map do |item|
|
|
30
34
|
format_item(item)
|
|
31
35
|
end.join(separator)
|
|
32
36
|
end
|
|
@@ -4,8 +4,25 @@ module Gitlab
|
|
|
4
4
|
module Triage
|
|
5
5
|
module CommandBuilders
|
|
6
6
|
class LabelCommandBuilder < BaseCommandBuilder
|
|
7
|
+
def build_command
|
|
8
|
+
ensure_labels_exist!
|
|
9
|
+
|
|
10
|
+
super
|
|
11
|
+
end
|
|
12
|
+
|
|
7
13
|
private
|
|
8
14
|
|
|
15
|
+
def ensure_labels_exist!
|
|
16
|
+
items.each do |label|
|
|
17
|
+
label_opts = { project_id: resource[:project_id], name: label }
|
|
18
|
+
|
|
19
|
+
unless Resource::Label.new(label_opts, network: network).exist?
|
|
20
|
+
raise Resource::Label::LabelDoesntExistError,
|
|
21
|
+
"Label `#{label}` doesn't exist!"
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
9
26
|
def slash_command_string
|
|
10
27
|
"/label"
|
|
11
28
|
end
|
|
@@ -34,13 +34,9 @@ module Gitlab
|
|
|
34
34
|
}.freeze
|
|
35
35
|
PLACEHOLDER_REGEX = /{{([\w\.]+)}}/.freeze
|
|
36
36
|
|
|
37
|
-
attr_reader :resource, :network
|
|
38
|
-
|
|
39
37
|
def initialize(
|
|
40
38
|
items, resource: nil, network: nil, redact_confidentials: true)
|
|
41
|
-
super(items)
|
|
42
|
-
@resource = resource&.with_indifferent_access
|
|
43
|
-
@network = network
|
|
39
|
+
super(items, resource: resource, network: network)
|
|
44
40
|
@redact_confidentials = redact_confidentials
|
|
45
41
|
end
|
|
46
42
|
|
data/lib/gitlab/triage/engine.rb
CHANGED
|
@@ -2,10 +2,8 @@ require 'active_support/all'
|
|
|
2
2
|
require 'active_support/inflector'
|
|
3
3
|
|
|
4
4
|
require_relative 'expand_condition'
|
|
5
|
-
require_relative 'filters/issuable_date_conditions_filter'
|
|
6
5
|
require_relative 'filters/merge_request_date_conditions_filter'
|
|
7
6
|
require_relative 'filters/votes_conditions_filter'
|
|
8
|
-
require_relative 'filters/forbidden_labels_conditions_filter'
|
|
9
7
|
require_relative 'filters/no_additional_labels_conditions_filter'
|
|
10
8
|
require_relative 'filters/author_member_conditions_filter'
|
|
11
9
|
require_relative 'filters/assignee_member_conditions_filter'
|
|
@@ -16,6 +14,7 @@ require_relative 'policies/rule_policy'
|
|
|
16
14
|
require_relative 'policies/summary_policy'
|
|
17
15
|
require_relative 'policies_resources/rule_resources'
|
|
18
16
|
require_relative 'policies_resources/summary_resources'
|
|
17
|
+
require_relative 'api_query_builders/date_query_param_builder'
|
|
19
18
|
require_relative 'api_query_builders/single_query_param_builder'
|
|
20
19
|
require_relative 'api_query_builders/multi_query_param_builder'
|
|
21
20
|
require_relative 'url_builders/url_builder'
|
|
@@ -153,7 +152,7 @@ module Gitlab
|
|
|
153
152
|
end
|
|
154
153
|
|
|
155
154
|
def resources_for_rule(resource_type, rule)
|
|
156
|
-
puts Gitlab::Triage::UI.header("
|
|
155
|
+
puts Gitlab::Triage::UI.header("Gathering resources for rule: **#{rule[:name]}**", char: '-')
|
|
157
156
|
|
|
158
157
|
ExpandCondition.perform(rule_conditions(rule)) do |conditions|
|
|
159
158
|
# retrieving the resources for every rule is inefficient
|
|
@@ -193,26 +192,15 @@ module Gitlab
|
|
|
193
192
|
resources.select do |resource|
|
|
194
193
|
results = []
|
|
195
194
|
|
|
195
|
+
# rubocop:disable Style/IfUnlessModifier
|
|
196
196
|
if conditions[:date]
|
|
197
|
-
results <<
|
|
198
|
-
when 'issues'
|
|
199
|
-
Filters::IssuableDateConditionsFilter.new(resource, conditions[:date]).calculate
|
|
200
|
-
when 'merge_requests'
|
|
201
|
-
Filters::MergeRequestDateConditionsFilter.new(resource, conditions[:date]).calculate
|
|
202
|
-
else
|
|
203
|
-
raise "Unknown resource type: #{resource[:type]}"
|
|
204
|
-
end
|
|
197
|
+
results << Filters::MergeRequestDateConditionsFilter.new(resource, conditions[:date]).calculate
|
|
205
198
|
end
|
|
206
199
|
|
|
207
|
-
# rubocop:disable Style/IfUnlessModifier
|
|
208
200
|
if conditions[:upvotes]
|
|
209
201
|
results << Filters::VotesConditionsFilter.new(resource, conditions[:upvotes]).calculate
|
|
210
202
|
end
|
|
211
203
|
|
|
212
|
-
if conditions[:forbidden_labels]
|
|
213
|
-
results << Filters::ForbiddenLabelsConditionsFilter.new(resource, conditions[:forbidden_labels]).calculate
|
|
214
|
-
end
|
|
215
|
-
|
|
216
204
|
if conditions[:no_additional_labels]
|
|
217
205
|
results << Filters::NoAdditionalLabelsConditionsFilter.new(resource, conditions.fetch(:labels) { [] }).calculate
|
|
218
206
|
end
|
|
@@ -251,11 +239,24 @@ module Gitlab
|
|
|
251
239
|
|
|
252
240
|
condition_builders = []
|
|
253
241
|
condition_builders << APIQueryBuilders::MultiQueryParamBuilder.new('labels', conditions[:labels], ',') if conditions[:labels]
|
|
242
|
+
|
|
243
|
+
if conditions[:forbidden_labels]
|
|
244
|
+
condition_builders << APIQueryBuilders::MultiQueryParamBuilder.new('not[labels]', conditions[:forbidden_labels], ',')
|
|
245
|
+
end
|
|
246
|
+
|
|
254
247
|
condition_builders << APIQueryBuilders::SingleQueryParamBuilder.new('state', conditions[:state]) if conditions[:state]
|
|
255
248
|
condition_builders << APIQueryBuilders::SingleQueryParamBuilder.new('milestone', Array(conditions[:milestone])[0]) if conditions[:milestone]
|
|
256
249
|
condition_builders << APIQueryBuilders::SingleQueryParamBuilder.new('source_branch', conditions[:source_branch]) if conditions[:source_branch]
|
|
257
250
|
condition_builders << APIQueryBuilders::SingleQueryParamBuilder.new('target_branch', conditions[:target_branch]) if conditions[:target_branch]
|
|
258
251
|
|
|
252
|
+
if conditions[:date] && APIQueryBuilders::DateQueryParamBuilder.applicable?(conditions[:date])
|
|
253
|
+
condition_builders << APIQueryBuilders::DateQueryParamBuilder.new(conditions.delete(:date))
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
if conditions[:weight] && resource_type.to_sym == :issues
|
|
257
|
+
condition_builders << APIQueryBuilders::SingleQueryParamBuilder.new('weight', conditions[:weight])
|
|
258
|
+
end
|
|
259
|
+
|
|
259
260
|
condition_builders.each do |condition_builder|
|
|
260
261
|
params[condition_builder.param_name] = condition_builder.param_content
|
|
261
262
|
end
|
|
@@ -1,21 +1,67 @@
|
|
|
1
|
-
require_relative '
|
|
1
|
+
require_relative 'base_conditions_filter'
|
|
2
2
|
|
|
3
3
|
module Gitlab
|
|
4
4
|
module Triage
|
|
5
5
|
module Filters
|
|
6
|
-
class MergeRequestDateConditionsFilter <
|
|
7
|
-
ATTRIBUTES = %w[
|
|
6
|
+
class MergeRequestDateConditionsFilter < BaseConditionsFilter
|
|
7
|
+
ATTRIBUTES = %w[merged_at].freeze
|
|
8
|
+
CONDITIONS = %w[older_than newer_than].freeze
|
|
9
|
+
INTERVAL_TYPES = %w[days weeks months years].freeze
|
|
10
|
+
|
|
11
|
+
def self.allowed_attributes
|
|
12
|
+
self::ATTRIBUTES
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def self.filter_parameters
|
|
16
|
+
[
|
|
17
|
+
{
|
|
18
|
+
name: :attribute,
|
|
19
|
+
type: String,
|
|
20
|
+
values: allowed_attributes
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
name: :condition,
|
|
24
|
+
type: String,
|
|
25
|
+
values: CONDITIONS
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
name: :interval_type,
|
|
29
|
+
type: String,
|
|
30
|
+
values: INTERVAL_TYPES
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
name: :interval,
|
|
34
|
+
type: Numeric
|
|
35
|
+
}
|
|
36
|
+
]
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def initialize_variables(condition)
|
|
40
|
+
@attribute = condition[:attribute].to_sym
|
|
41
|
+
@condition = condition[:condition].to_sym
|
|
42
|
+
@interval_type = condition[:interval_type].to_sym
|
|
43
|
+
@interval = condition[:interval]
|
|
44
|
+
end
|
|
8
45
|
|
|
9
46
|
# Guard against merge requests with no merged_at values
|
|
10
47
|
def resource_value
|
|
11
|
-
|
|
48
|
+
@resource[@attribute]&.to_date
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def condition_value
|
|
52
|
+
@interval.public_send(@interval_type).ago.to_date # rubocop:disable GitlabSecurity/PublicSend
|
|
12
53
|
end
|
|
13
54
|
|
|
14
55
|
# Guard against merge requests with no merged_at values
|
|
15
56
|
def calculate
|
|
16
57
|
return false unless resource_value
|
|
17
58
|
|
|
18
|
-
|
|
59
|
+
case @condition
|
|
60
|
+
when :older_than
|
|
61
|
+
resource_value < condition_value
|
|
62
|
+
when :newer_than
|
|
63
|
+
resource_value > condition_value
|
|
64
|
+
end
|
|
19
65
|
end
|
|
20
66
|
end
|
|
21
67
|
end
|
|
@@ -10,7 +10,7 @@ module Gitlab
|
|
|
10
10
|
# Build an issue from several rules policies
|
|
11
11
|
def build_issue
|
|
12
12
|
action = actions[:summarize]
|
|
13
|
-
issues = resources.
|
|
13
|
+
issues = resources.map do |inner_policy_spec, inner_resources|
|
|
14
14
|
Policies::RulePolicy.new(
|
|
15
15
|
type, inner_policy_spec, inner_resources, network)
|
|
16
16
|
.build_issue
|
|
@@ -1,21 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'delegate'
|
|
4
|
+
|
|
3
5
|
module Gitlab
|
|
4
6
|
module Triage
|
|
5
7
|
module PoliciesResources
|
|
6
|
-
|
|
7
|
-
attr_reader :resources
|
|
8
|
-
|
|
9
|
-
def initialize(new_resources)
|
|
10
|
-
@resources = new_resources
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
def each
|
|
14
|
-
resources.each do |resource|
|
|
15
|
-
yield(resource)
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
end
|
|
8
|
+
RuleResources = Class.new(SimpleDelegator)
|
|
19
9
|
end
|
|
20
10
|
end
|
|
21
11
|
end
|
|
@@ -1,21 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'delegate'
|
|
4
|
+
|
|
3
5
|
module Gitlab
|
|
4
6
|
module Triage
|
|
5
7
|
module PoliciesResources
|
|
6
|
-
|
|
7
|
-
attr_reader :rule_to_resources
|
|
8
|
-
|
|
9
|
-
def initialize(new_rule_to_resources)
|
|
10
|
-
@rule_to_resources = new_rule_to_resources
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
def build_issues
|
|
14
|
-
rule_to_resources.map do |inner_policy_spec, inner_resources|
|
|
15
|
-
yield(inner_policy_spec, inner_resources)
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
end
|
|
8
|
+
SummaryResources = Class.new(SimpleDelegator)
|
|
19
9
|
end
|
|
20
10
|
end
|
|
21
11
|
end
|
|
@@ -58,11 +58,15 @@ module Gitlab
|
|
|
58
58
|
build_url(params: params)
|
|
59
59
|
end
|
|
60
60
|
|
|
61
|
+
def resource_id
|
|
62
|
+
resource[:iid]
|
|
63
|
+
end
|
|
64
|
+
|
|
61
65
|
def resource_url(params: {}, sub_resource_type: nil)
|
|
62
66
|
build_url(
|
|
63
67
|
params: params,
|
|
64
68
|
options: {
|
|
65
|
-
resource_id:
|
|
69
|
+
resource_id: resource_id,
|
|
66
70
|
sub_resource_type: sub_resource_type
|
|
67
71
|
}
|
|
68
72
|
)
|
|
@@ -8,6 +8,8 @@ module Gitlab
|
|
|
8
8
|
module Triage
|
|
9
9
|
module Resource
|
|
10
10
|
class Label < Base
|
|
11
|
+
LabelDoesntExistError = Class.new(StandardError)
|
|
12
|
+
|
|
11
13
|
FIELDS = %i[
|
|
12
14
|
id
|
|
13
15
|
project_id
|
|
@@ -35,6 +37,19 @@ module Gitlab
|
|
|
35
37
|
Time.parse(value) if value
|
|
36
38
|
end
|
|
37
39
|
end
|
|
40
|
+
|
|
41
|
+
def exist?
|
|
42
|
+
label = network.query_api_cached(resource_url).first
|
|
43
|
+
return false unless label
|
|
44
|
+
|
|
45
|
+
label[:name] == name
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
private
|
|
49
|
+
|
|
50
|
+
def resource_id
|
|
51
|
+
name
|
|
52
|
+
end
|
|
38
53
|
end
|
|
39
54
|
end
|
|
40
55
|
end
|
|
@@ -17,7 +17,7 @@ module Gitlab
|
|
|
17
17
|
|
|
18
18
|
def build
|
|
19
19
|
url = base_url
|
|
20
|
-
url << "/#{@resource_id}" if @resource_id
|
|
20
|
+
url << "/#{percent_encode(@resource_id.to_s)}" if @resource_id
|
|
21
21
|
url << "/#{@sub_resource_type}" if @sub_resource_type
|
|
22
22
|
url << params_string if @params
|
|
23
23
|
url
|
|
@@ -31,16 +31,20 @@ module Gitlab
|
|
|
31
31
|
|
|
32
32
|
def base_url
|
|
33
33
|
url = host_with_api_url
|
|
34
|
-
url << "/#{@source}/#{
|
|
34
|
+
url << "/#{@source}/#{percent_encode(@source_id.to_s)}" unless @all
|
|
35
35
|
url << "/#{@resource_type}" if @resource_type
|
|
36
36
|
url
|
|
37
37
|
end
|
|
38
38
|
|
|
39
39
|
def params_string
|
|
40
40
|
"?" << @params.map do |k, v|
|
|
41
|
-
"#{k}=#{v}"
|
|
41
|
+
"#{percent_encode(k.to_s)}=#{percent_encode(v.to_s)}"
|
|
42
42
|
end.join("&")
|
|
43
43
|
end
|
|
44
|
+
|
|
45
|
+
def percent_encode(str)
|
|
46
|
+
CGI.escape(str).gsub('+', '%20')
|
|
47
|
+
end
|
|
44
48
|
end
|
|
45
49
|
end
|
|
46
50
|
end
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
module Gitlab
|
|
2
2
|
module Triage
|
|
3
3
|
class ParamsValidator
|
|
4
|
+
InvalidParameter = Class.new(ArgumentError)
|
|
5
|
+
|
|
4
6
|
def initialize(parameter_definitions, value)
|
|
5
7
|
@parameter_definitions = parameter_definitions
|
|
6
8
|
@value = value
|
|
@@ -16,7 +18,7 @@ module Gitlab
|
|
|
16
18
|
|
|
17
19
|
def validate_required_parameters(value)
|
|
18
20
|
@parameter_definitions.each do |param|
|
|
19
|
-
raise
|
|
21
|
+
raise InvalidParameter, "#{param[:name]} is a required parameter" unless value[param[:name]]
|
|
20
22
|
end
|
|
21
23
|
end
|
|
22
24
|
|
|
@@ -24,7 +26,7 @@ module Gitlab
|
|
|
24
26
|
@parameter_definitions.each do |param|
|
|
25
27
|
if value.has_key?(param[:name])
|
|
26
28
|
param_types = Array(param[:type]).flatten
|
|
27
|
-
raise
|
|
29
|
+
raise InvalidParameter, "#{param[:name]} must be of type #{param[:type]}" unless param_types.any? { |type| value[param[:name]].is_a?(type) }
|
|
28
30
|
end
|
|
29
31
|
end
|
|
30
32
|
end
|
|
@@ -32,7 +34,7 @@ module Gitlab
|
|
|
32
34
|
def validate_parameter_content(value)
|
|
33
35
|
@parameter_definitions.each do |param|
|
|
34
36
|
if param[:values]
|
|
35
|
-
raise
|
|
37
|
+
raise InvalidParameter, "#{param[:name]} must be of one of #{param[:values].join(',')}" unless param[:values].include?(value[param[:name]])
|
|
36
38
|
end
|
|
37
39
|
end
|
|
38
40
|
end
|
|
@@ -8,7 +8,7 @@ dry-run:triage:
|
|
|
8
8
|
script:
|
|
9
9
|
- gem install gitlab-triage
|
|
10
10
|
- gitlab-triage --help
|
|
11
|
-
- gitlab-triage --dry-run --token $
|
|
11
|
+
- gitlab-triage --dry-run --token $GITLAB_API_TOKEN --source projects --source-id $CI_PROJECT_PATH
|
|
12
12
|
when: manual
|
|
13
13
|
except:
|
|
14
14
|
- schedules
|
|
@@ -17,6 +17,6 @@ run:triage:
|
|
|
17
17
|
stage: triage
|
|
18
18
|
script:
|
|
19
19
|
- gem install gitlab-triage
|
|
20
|
-
- gitlab-triage --token $
|
|
20
|
+
- gitlab-triage --token $GITLAB_API_TOKEN --source projects --source-id $CI_PROJECT_PATH
|
|
21
21
|
only:
|
|
22
22
|
- schedules
|
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.13.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- GitLab
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2020-
|
|
11
|
+
date: 2020-08-26 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activesupport
|
|
@@ -136,6 +136,7 @@ files:
|
|
|
136
136
|
- lib/gitlab/triage/action/comment.rb
|
|
137
137
|
- lib/gitlab/triage/action/summarize.rb
|
|
138
138
|
- lib/gitlab/triage/api_query_builders/base_query_param_builder.rb
|
|
139
|
+
- lib/gitlab/triage/api_query_builders/date_query_param_builder.rb
|
|
139
140
|
- lib/gitlab/triage/api_query_builders/multi_query_param_builder.rb
|
|
140
141
|
- lib/gitlab/triage/api_query_builders/single_query_param_builder.rb
|
|
141
142
|
- lib/gitlab/triage/command_builders/base_command_builder.rb
|
|
@@ -157,8 +158,6 @@ files:
|
|
|
157
158
|
- lib/gitlab/triage/filters/assignee_member_conditions_filter.rb
|
|
158
159
|
- lib/gitlab/triage/filters/author_member_conditions_filter.rb
|
|
159
160
|
- lib/gitlab/triage/filters/base_conditions_filter.rb
|
|
160
|
-
- lib/gitlab/triage/filters/forbidden_labels_conditions_filter.rb
|
|
161
|
-
- lib/gitlab/triage/filters/issuable_date_conditions_filter.rb
|
|
162
161
|
- lib/gitlab/triage/filters/member_conditions_filter.rb
|
|
163
162
|
- lib/gitlab/triage/filters/merge_request_date_conditions_filter.rb
|
|
164
163
|
- lib/gitlab/triage/filters/name_conditions_filter.rb
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
require_relative 'base_conditions_filter'
|
|
2
|
-
|
|
3
|
-
module Gitlab
|
|
4
|
-
module Triage
|
|
5
|
-
module Filters
|
|
6
|
-
class ForbiddenLabelsConditionsFilter < BaseConditionsFilter
|
|
7
|
-
def validate_condition(condition)
|
|
8
|
-
raise ArgumentError, 'condition must be an array containing forbidden label values' unless condition.is_a?(Array)
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
def initialize_variables(forbidden_labels)
|
|
12
|
-
@attribute = :labels
|
|
13
|
-
@forbidden_labels = forbidden_labels
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def resource_value
|
|
17
|
-
@resource[@attribute]
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
def calculate
|
|
21
|
-
label_intersection.empty?
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
private
|
|
25
|
-
|
|
26
|
-
def label_intersection
|
|
27
|
-
resource_value & @forbidden_labels
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
end
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
require_relative 'base_conditions_filter'
|
|
2
|
-
|
|
3
|
-
module Gitlab
|
|
4
|
-
module Triage
|
|
5
|
-
module Filters
|
|
6
|
-
class IssuableDateConditionsFilter < BaseConditionsFilter
|
|
7
|
-
ATTRIBUTES = %w[updated_at created_at].freeze
|
|
8
|
-
CONDITIONS = %w[older_than newer_than].freeze
|
|
9
|
-
INTERVAL_TYPES = %w[days weeks months years].freeze
|
|
10
|
-
|
|
11
|
-
def self.allowed_attributes
|
|
12
|
-
self::ATTRIBUTES
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def self.filter_parameters
|
|
16
|
-
[
|
|
17
|
-
{
|
|
18
|
-
name: :attribute,
|
|
19
|
-
type: String,
|
|
20
|
-
values: allowed_attributes
|
|
21
|
-
},
|
|
22
|
-
{
|
|
23
|
-
name: :condition,
|
|
24
|
-
type: String,
|
|
25
|
-
values: CONDITIONS
|
|
26
|
-
},
|
|
27
|
-
{
|
|
28
|
-
name: :interval_type,
|
|
29
|
-
type: String,
|
|
30
|
-
values: INTERVAL_TYPES
|
|
31
|
-
},
|
|
32
|
-
{
|
|
33
|
-
name: :interval,
|
|
34
|
-
type: Numeric
|
|
35
|
-
}
|
|
36
|
-
]
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
def initialize_variables(condition)
|
|
40
|
-
@attribute = condition[:attribute].to_sym
|
|
41
|
-
@condition = condition[:condition].to_sym
|
|
42
|
-
@interval_type = condition[:interval_type].to_sym
|
|
43
|
-
@interval = condition[:interval]
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
def resource_value
|
|
47
|
-
@resource[@attribute].to_date
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
def condition_value
|
|
51
|
-
@interval.public_send(@interval_type).ago.to_date # rubocop:disable GitlabSecurity/PublicSend
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
def calculate
|
|
55
|
-
case @condition
|
|
56
|
-
when :older_than
|
|
57
|
-
resource_value < condition_value
|
|
58
|
-
when :newer_than
|
|
59
|
-
resource_value > condition_value
|
|
60
|
-
end
|
|
61
|
-
end
|
|
62
|
-
end
|
|
63
|
-
end
|
|
64
|
-
end
|
|
65
|
-
end
|