gitlab-triage 1.7.0 → 1.10.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.
- checksums.yaml +4 -4
- data/.gitignore +0 -1
- data/.gitlab-ci.yml +75 -40
- data/.gitlab/merge_request_templates/Release.md +35 -0
- data/.rubocop.yml +3 -0
- data/Gemfile +1 -1
- data/README.md +92 -3
- data/gitlab-triage.gemspec +1 -1
- data/lib/gitlab/triage/action/comment.rb +14 -1
- data/lib/gitlab/triage/api_query_builders/date_query_param_builder.rb +78 -0
- data/lib/gitlab/triage/command_builders/move_command_builder.rb +19 -0
- data/lib/gitlab/triage/command_builders/text_content_builder.rb +17 -1
- data/lib/gitlab/triage/engine.rb +41 -16
- data/lib/gitlab/triage/errors.rb +1 -1
- data/lib/gitlab/triage/filters/merge_request_date_conditions_filter.rb +51 -5
- data/lib/gitlab/triage/network.rb +2 -1
- data/lib/gitlab/triage/network_adapters/httparty_adapter.rb +13 -1
- data/lib/gitlab/triage/option_parser.rb +10 -0
- data/lib/gitlab/triage/options.rb +2 -0
- 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 +5 -6
- data/lib/gitlab/triage/policies_resources/summary_resources.rb +5 -6
- data/lib/gitlab/triage/resource/base.rb +5 -0
- data/lib/gitlab/triage/resource/merge_request.rb +9 -0
- data/lib/gitlab/triage/url_builders/url_builder.rb +10 -9
- data/lib/gitlab/triage/validators/limiter_validator.rb +3 -1
- data/lib/gitlab/triage/validators/params_validator.rb +5 -3
- data/lib/gitlab/triage/version.rb +3 -1
- data/support/.triage-policies.example.yml +2 -2
- metadata +6 -4
- 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: 1242b945b940e1378f6bb8f66eb5f08f3adb387245c0425954aa7a6cc3e98f25
|
4
|
+
data.tar.gz: 925cbb79cd61b2c5f4eeb87eed0596c674902aa6fd44bfe679b9740d660aede6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1caedc0d489bc0e45e66399aa9529cf3eaf9812a78cb99fddba5cc5a078b10ab748e763d2407e6911da9ba2cadbc56453040366c8bad1757a0ae07fbcbf25b1d
|
7
|
+
data.tar.gz: 12de27a31f013916beee14fe3da467e1ee316774e8fea019c0735c68c81f0e5694a79cdcb5d4bc94522b620a94c4c4989c4367f51fd28d400f19a1dca63d48dc
|
data/.gitignore
CHANGED
data/.gitlab-ci.yml
CHANGED
@@ -1,49 +1,67 @@
|
|
1
|
-
image: ruby:2.6
|
2
|
-
|
3
1
|
stages:
|
4
2
|
- prepare
|
5
3
|
- test
|
6
4
|
- triage
|
5
|
+
- release
|
7
6
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
7
|
+
default:
|
8
|
+
image: ruby:2.7
|
9
|
+
tags:
|
10
|
+
- gitlab-org
|
11
|
+
cache:
|
12
|
+
key:
|
13
|
+
files:
|
14
|
+
- Gemfile
|
15
|
+
- gitlab-triage.gemspec
|
16
|
+
paths:
|
17
|
+
- vendor/ruby
|
18
|
+
- Gemfile.lock
|
19
|
+
policy: pull
|
16
20
|
before_script:
|
21
|
+
- ruby --version
|
17
22
|
- gem install bundler --no-document --version 2.0.2
|
18
|
-
- bundle
|
23
|
+
- bundle --version
|
24
|
+
- bundle install --jobs $(nproc) --path=vendor --retry 3 --quiet
|
25
|
+
- bundle check
|
26
|
+
|
27
|
+
workflow:
|
28
|
+
rules:
|
29
|
+
# For merge requests, create a pipeline.
|
30
|
+
- if: '$CI_MERGE_REQUEST_IID'
|
31
|
+
# For `master` branch, create a pipeline (this includes on schedules, pushes, merges, etc.).
|
32
|
+
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
|
33
|
+
# For tags, create a pipeline.
|
34
|
+
- if: '$CI_COMMIT_TAG'
|
35
|
+
|
36
|
+
.use-docker-in-docker:
|
37
|
+
image: docker:${DOCKER_VERSION}
|
38
|
+
services:
|
39
|
+
- docker:${DOCKER_VERSION}-dind
|
40
|
+
variables:
|
41
|
+
DOCKER_DRIVER: overlay2
|
42
|
+
DOCKER_HOST: tcp://docker:2375
|
43
|
+
DOCKER_TLS_CERTDIR: ""
|
44
|
+
tags:
|
45
|
+
# See https://gitlab.com/gitlab-com/www-gitlab-com/-/issues/7019 for tag descriptions
|
46
|
+
- gitlab-org-docker
|
19
47
|
|
20
48
|
###################
|
21
49
|
## Prepare stage ##
|
22
50
|
###################
|
23
51
|
setup-test-env:
|
24
|
-
extends: .default-only
|
25
52
|
stage: prepare
|
26
53
|
script:
|
27
|
-
-
|
28
|
-
- gem install bundler --no-document
|
29
|
-
- bundle --version
|
30
|
-
- bundle install --clean --jobs $(nproc) --path=vendor --retry=3 --quiet
|
31
|
-
- bundle check
|
54
|
+
- echo "Setup done!"
|
32
55
|
cache:
|
33
|
-
|
34
|
-
paths:
|
35
|
-
- vendor/ruby
|
36
|
-
- Gemfile.lock
|
56
|
+
policy: pull-push
|
37
57
|
artifacts:
|
38
58
|
paths:
|
39
|
-
- vendor/ruby
|
40
59
|
- Gemfile.lock
|
41
60
|
|
42
61
|
################
|
43
62
|
## Test stage ##
|
44
63
|
################
|
45
64
|
rubocop:
|
46
|
-
extends: [".default-only", ".default-before_script"]
|
47
65
|
stage: test
|
48
66
|
needs: ["setup-test-env"]
|
49
67
|
dependencies: ["setup-test-env"]
|
@@ -55,20 +73,15 @@ rubocop:
|
|
55
73
|
- .cache/rubocop_cache/
|
56
74
|
|
57
75
|
# We need to copy this job's definition from the Code-Quality.gitlab-ci.yml
|
58
|
-
# template because `only` is set without `refs`, so it takes precedence over
|
76
|
+
# template because `only` is set without `refs`, so it takes precedence over default workflow rules.
|
59
77
|
# See https://gitlab.com/gitlab-org/gitlab-ce/issues/66767.
|
60
78
|
code_quality:
|
61
|
-
extends: .
|
62
|
-
needs: ["setup-test-env"]
|
63
|
-
dependencies: ["setup-test-env"]
|
79
|
+
extends: .use-docker-in-docker
|
64
80
|
stage: test
|
65
|
-
image: docker:stable
|
66
81
|
allow_failure: true
|
67
|
-
services:
|
68
|
-
- docker:stable-dind
|
69
82
|
variables:
|
70
|
-
DOCKER_DRIVER: overlay2
|
71
83
|
DOCKER_TLS_CERTDIR: ""
|
84
|
+
before_script: []
|
72
85
|
script:
|
73
86
|
- |
|
74
87
|
if ! docker info &>/dev/null; then
|
@@ -85,14 +98,9 @@ code_quality:
|
|
85
98
|
reports:
|
86
99
|
codequality: gl-code-quality-report.json
|
87
100
|
expire_in: 1 week
|
88
|
-
except:
|
89
|
-
variables:
|
90
|
-
- $CODE_QUALITY_DISABLED
|
91
101
|
|
92
102
|
specs:
|
93
|
-
extends: [".default-only", ".default-before_script"]
|
94
103
|
needs: ["setup-test-env"]
|
95
|
-
dependencies: ["setup-test-env"]
|
96
104
|
stage: test
|
97
105
|
script:
|
98
106
|
- bundle exec rake spec
|
@@ -101,12 +109,13 @@ specs:
|
|
101
109
|
## Triage stage ##
|
102
110
|
##################
|
103
111
|
dry-run:gitlab-triage:
|
104
|
-
extends: [".default-only", ".default-before_script"]
|
105
112
|
needs: ["setup-test-env"]
|
106
|
-
dependencies: ["setup-test-env"]
|
107
113
|
stage: triage
|
108
114
|
script:
|
109
|
-
- bundle exec rake
|
115
|
+
- bundle exec rake build
|
116
|
+
- gem install pkg/*.gem
|
117
|
+
- which gitlab-triage
|
118
|
+
- gitlab-triage --version
|
110
119
|
- gitlab-triage --help
|
111
120
|
- gitlab-triage --init
|
112
121
|
- gitlab-triage --dry-run --debug --token $API_TOKEN --source-id $CI_PROJECT_PATH
|
@@ -114,4 +123,30 @@ dry-run:gitlab-triage:
|
|
114
123
|
# This job requires allows to override the `CI_PROJECT_PATH` variable when triggered.
|
115
124
|
dry-run:custom:
|
116
125
|
extends: dry-run:gitlab-triage
|
117
|
-
|
126
|
+
rules:
|
127
|
+
- when: manual
|
128
|
+
allow_failure: true
|
129
|
+
|
130
|
+
###################
|
131
|
+
## Release stage ##
|
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
|
@@ -0,0 +1,35 @@
|
|
1
|
+
<!-- Replace `v4.5.0` with the previous release here, and `e18d76b309e42888759c1effe96767f13e34ae55`
|
2
|
+
with the latest commit from https://gitlab.com/gitlab-org/gitlab-triage/commits/master that will be included in the release. -->
|
3
|
+
- Diff: https://gitlab.com/gitlab-org/gitlab-triage/compare/v4.5.0...e18d76b309e42888759c1effe96767f13e34ae55
|
4
|
+
|
5
|
+
- Release notes:
|
6
|
+
|
7
|
+
<!-- Keep the sections order but remove the empty sections -->
|
8
|
+
|
9
|
+
```markdown
|
10
|
+
### New features and features updates
|
11
|
+
|
12
|
+
- !aaa <Title of the aaa MR>.
|
13
|
+
|
14
|
+
### Fixes
|
15
|
+
|
16
|
+
- !bbb <Title of the bbb MR>.
|
17
|
+
|
18
|
+
### Doc changes
|
19
|
+
|
20
|
+
- !ccc <Title of the ccc MR>.
|
21
|
+
|
22
|
+
### Other changes (tooling, technical debt)
|
23
|
+
|
24
|
+
- !ddd <Title of the ddd MR>.
|
25
|
+
```
|
26
|
+
|
27
|
+
- Checklist before merging:
|
28
|
+
- [ ] Diff link is up-to-date.
|
29
|
+
- [ ] Based on the diff, `lib/gitlab/triage/version.rb` is updated, according to [SemVer](https://semver.org).
|
30
|
+
- [ ] Release notes are accurate.
|
31
|
+
|
32
|
+
- Checklist after merging:
|
33
|
+
- [ ] [Update the release notes for the newly created tag](docs/release_process.md#how-to).
|
34
|
+
|
35
|
+
/label ~"Engineering Productivity" ~"ep::triage" ~"tooling::workflow"
|
data/.rubocop.yml
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -58,7 +58,7 @@ resource_rules:
|
|
58
58
|
interval: 5
|
59
59
|
state: opened
|
60
60
|
labels:
|
61
|
-
-
|
61
|
+
- None
|
62
62
|
limits:
|
63
63
|
most_recent: 50
|
64
64
|
actions:
|
@@ -66,6 +66,7 @@ resource_rules:
|
|
66
66
|
- needs attention
|
67
67
|
mention:
|
68
68
|
- markglenfletcher
|
69
|
+
move: gitlab-org/backlog
|
69
70
|
comment: |
|
70
71
|
{{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')}
|
71
72
|
summarize:
|
@@ -85,9 +86,27 @@ resource_rules:
|
|
85
86
|
/label ~"needs attention"
|
86
87
|
merge_requests:
|
87
88
|
rules:
|
88
|
-
|
89
|
+
- name: My policy
|
90
|
+
conditions:
|
91
|
+
state: opened
|
92
|
+
labels:
|
93
|
+
- None
|
94
|
+
limits:
|
95
|
+
most_recent: 50
|
96
|
+
actions:
|
97
|
+
labels:
|
98
|
+
- needs attention
|
99
|
+
comment_type: thread
|
100
|
+
comment: |
|
101
|
+
{{author}} This issue is unlabelled. Please add one or more labels.
|
89
102
|
```
|
90
103
|
|
104
|
+
### Real world example
|
105
|
+
|
106
|
+
We're enforcing multiple polices with pipeline schedules at [triage-ops](
|
107
|
+
https://gitlab.com/gitlab-org/quality/triage-ops), where we're also
|
108
|
+
extensively utilizing the [plugins system](#can-i-customize).
|
109
|
+
|
91
110
|
### Fields
|
92
111
|
|
93
112
|
A policy consists of the following fields:
|
@@ -210,6 +229,22 @@ conditions:
|
|
210
229
|
- feature proposal
|
211
230
|
```
|
212
231
|
|
232
|
+
###### Predefined special label names
|
233
|
+
|
234
|
+
Basing on the [issues API](https://docs.gitlab.com/ee/api/issues.html), there
|
235
|
+
are two special predefined label names we can use here:
|
236
|
+
|
237
|
+
* `None`: This indicates that no labels were present
|
238
|
+
* `Any`: This indicates that any labels were presented
|
239
|
+
|
240
|
+
Example:
|
241
|
+
|
242
|
+
```yml
|
243
|
+
conditions:
|
244
|
+
labels:
|
245
|
+
- None
|
246
|
+
```
|
247
|
+
|
213
248
|
###### Labels brace expansion
|
214
249
|
|
215
250
|
We could expand the labels by using brace expansion, which is a pattern
|
@@ -506,7 +541,9 @@ Available action types:
|
|
506
541
|
- [`remove_labels` action](#remove-labels-action)
|
507
542
|
- [`status` action](#status-action)
|
508
543
|
- [`mention` action](#mention-action)
|
544
|
+
- [`move` action](#move-action)
|
509
545
|
- [`comment` action](#comment-action)
|
546
|
+
- [`comment_type` action option](#comment-type-action-option)
|
510
547
|
- [`summarize` action](#summarize-action)
|
511
548
|
|
512
549
|
##### Labels action
|
@@ -572,6 +609,19 @@ actions:
|
|
572
609
|
- markglenfletcher
|
573
610
|
```
|
574
611
|
|
612
|
+
##### Move action
|
613
|
+
|
614
|
+
Moves an issue (merge request is not supported yet) to the specified project.
|
615
|
+
|
616
|
+
Accepts a string containing the target project path.
|
617
|
+
|
618
|
+
Example:
|
619
|
+
|
620
|
+
```yml
|
621
|
+
actions:
|
622
|
+
move: target/project_path
|
623
|
+
```
|
624
|
+
|
575
625
|
##### Comment action
|
576
626
|
|
577
627
|
Adds a comment to the resource.
|
@@ -619,6 +669,26 @@ actions:
|
|
619
669
|
{{author}} Are you still interested in finishing this merge request?
|
620
670
|
```
|
621
671
|
|
672
|
+
##### Comment type action option
|
673
|
+
|
674
|
+
Determines the type of comment to be added to the resource.
|
675
|
+
|
676
|
+
The following comment types are supported:
|
677
|
+
|
678
|
+
- `comment` (default): creates a regular comment on the resource
|
679
|
+
- `thread`: starts a resolvable thread (discussion) on the resource
|
680
|
+
|
681
|
+
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.
|
682
|
+
|
683
|
+
Example:
|
684
|
+
|
685
|
+
```yml
|
686
|
+
actions:
|
687
|
+
comment_type: thread
|
688
|
+
comment: |
|
689
|
+
{{author}} Are you still interested in finishing this merge request?
|
690
|
+
```
|
691
|
+
|
622
692
|
###### Harnessing Quick Actions
|
623
693
|
|
624
694
|
[GitLab's quick actions feature](https://docs.gitlab.com/ce/user/project/quick_actions.html) is available in Core.
|
@@ -839,7 +909,7 @@ Which could generate an issue like:
|
|
839
909
|
|
840
910
|
Here's a list of currently available Ruby expression API:
|
841
911
|
|
842
|
-
#####
|
912
|
+
##### Methods for `Issue` and `MergeRequest` (the context)
|
843
913
|
|
844
914
|
| Name | Return type | Description |
|
845
915
|
| ---- | ---- | ---- |
|
@@ -854,6 +924,12 @@ Here's a list of currently available Ruby expression API:
|
|
854
924
|
| project_path | String | The path with namespace to the issues or merge requests project |
|
855
925
|
| full_resource_reference | String | A full reference incuding project path to the issue or merge request |
|
856
926
|
|
927
|
+
##### Methods for `MergeRequest` (merge request context)
|
928
|
+
|
929
|
+
| Method | Return type | Description |
|
930
|
+
| ---- | ---- | ---- |
|
931
|
+
| 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. |
|
932
|
+
|
857
933
|
##### Methods for `Milestone`
|
858
934
|
|
859
935
|
| Method | Return type | Description |
|
@@ -930,6 +1006,7 @@ Usage: gitlab-triage [options]
|
|
930
1006
|
-r, --require [string] Require a file before performing
|
931
1007
|
-d, --debug Print debug information
|
932
1008
|
-h, --help Print help message
|
1009
|
+
--all-projects Process all projects visible to `--token`
|
933
1010
|
--init Initialize the project with a policy file
|
934
1011
|
--init-ci Initialize the project with a .gitlab-ci.yml file
|
935
1012
|
```
|
@@ -948,6 +1025,14 @@ Triaging against a whole group:
|
|
948
1025
|
gitlab-triage --dry-run --token $API_TOKEN --source-id gitlab-org --source groups
|
949
1026
|
```
|
950
1027
|
|
1028
|
+
Triaging against an entire instance:
|
1029
|
+
|
1030
|
+
```
|
1031
|
+
gitlab-triage --dry-run --token $API_TOKEN --all-projects
|
1032
|
+
```
|
1033
|
+
|
1034
|
+
> **Note:** The `--all-projects` option will process all resources for all projects visible to the specified `$API_TOKEN`
|
1035
|
+
|
951
1036
|
#### Running on GitLab CI pipeline
|
952
1037
|
|
953
1038
|
You can enforce policies using a scheduled pipeline:
|
@@ -1030,3 +1115,7 @@ resource_rules:
|
|
1030
1115
|
### Contributing
|
1031
1116
|
|
1032
1117
|
Please refer to the [Contributing Guide](CONTRIBUTING.md).
|
1118
|
+
|
1119
|
+
## Release Process
|
1120
|
+
|
1121
|
+
Please refer to the [Release Process](docs/release_process.md).
|
data/gitlab-triage.gemspec
CHANGED
@@ -13,7 +13,7 @@ Gem::Specification.new do |spec|
|
|
13
13
|
spec.license = 'MIT'
|
14
14
|
|
15
15
|
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
16
|
-
f.match(%r{^(test|spec|features)/})
|
16
|
+
f.match(%r{^(docs|test|spec|features)/})
|
17
17
|
end
|
18
18
|
spec.bindir = 'bin'
|
19
19
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
@@ -7,6 +7,7 @@ require_relative '../command_builders/label_command_builder'
|
|
7
7
|
require_relative '../command_builders/remove_label_command_builder'
|
8
8
|
require_relative '../command_builders/cc_command_builder'
|
9
9
|
require_relative '../command_builders/status_command_builder'
|
10
|
+
require_relative '../command_builders/move_command_builder'
|
10
11
|
|
11
12
|
module Gitlab
|
12
13
|
module Triage
|
@@ -43,6 +44,7 @@ module Gitlab
|
|
43
44
|
CommandBuilders::LabelCommandBuilder.new(policy.actions[:labels]).build_command,
|
44
45
|
CommandBuilders::RemoveLabelCommandBuilder.new(policy.actions[:remove_labels]).build_command,
|
45
46
|
CommandBuilders::CcCommandBuilder.new(policy.actions[:mention]).build_command,
|
47
|
+
CommandBuilders::MoveCommandBuilder.new(policy.actions[:move]).build_command,
|
46
48
|
CommandBuilders::StatusCommandBuilder.new(policy.actions[:status]).build_command
|
47
49
|
]
|
48
50
|
).build_command
|
@@ -61,13 +63,24 @@ module Gitlab
|
|
61
63
|
source_id: resource[:project_id],
|
62
64
|
resource_type: policy.type,
|
63
65
|
resource_id: resource['iid'],
|
64
|
-
sub_resource_type:
|
66
|
+
sub_resource_type: sub_resource_type
|
65
67
|
).build
|
66
68
|
|
67
69
|
puts Gitlab::Triage::UI.debug "post_url: #{post_url}" if network.options.debug
|
68
70
|
|
69
71
|
post_url
|
70
72
|
end
|
73
|
+
|
74
|
+
def sub_resource_type
|
75
|
+
case type = policy.actions[:comment_type]
|
76
|
+
when 'comment', nil # nil is default
|
77
|
+
'notes'
|
78
|
+
when 'thread'
|
79
|
+
'discussions'
|
80
|
+
else
|
81
|
+
raise ArgumentError, "Unknown comment type: #{type}"
|
82
|
+
end
|
83
|
+
end
|
71
84
|
end
|
72
85
|
end
|
73
86
|
end
|
@@ -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
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require_relative 'base_command_builder'
|
2
|
+
|
3
|
+
module Gitlab
|
4
|
+
module Triage
|
5
|
+
module CommandBuilders
|
6
|
+
class MoveCommandBuilder < BaseCommandBuilder
|
7
|
+
private
|
8
|
+
|
9
|
+
def slash_command_string
|
10
|
+
"/move"
|
11
|
+
end
|
12
|
+
|
13
|
+
def format_item(item)
|
14
|
+
item
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'active_support/core_ext/array/wrap'
|
4
|
+
require 'cgi'
|
4
5
|
|
5
6
|
require_relative 'base_command_builder'
|
6
7
|
require_relative '../resource/context'
|
@@ -76,7 +77,22 @@ module Gitlab
|
|
76
77
|
template.sub(PLACEHOLDER_REGEX, attribute.to_s)
|
77
78
|
end.join(', ')
|
78
79
|
|
79
|
-
|
80
|
+
escaped_text =
|
81
|
+
case placeholder
|
82
|
+
when :items
|
83
|
+
# We don't need to escape it because it's recursive,
|
84
|
+
# which the contents should all be escaped already.
|
85
|
+
# Or put it another way, items isn't an attribute
|
86
|
+
# retrieved externally. It's a generated value which
|
87
|
+
# should be safe to begin with. At some point we
|
88
|
+
# may want to make this more distinguishable,
|
89
|
+
# separating values from API and values generated.
|
90
|
+
formatted_text
|
91
|
+
else
|
92
|
+
CGI.escape_html(formatted_text)
|
93
|
+
end
|
94
|
+
|
95
|
+
comment.gsub("{{#{placeholder}}}", escaped_text)
|
80
96
|
end
|
81
97
|
end
|
82
98
|
|
data/lib/gitlab/triage/engine.rb
CHANGED
@@ -2,7 +2,6 @@ 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
7
|
require_relative 'filters/forbidden_labels_conditions_filter'
|
@@ -16,6 +15,7 @@ require_relative 'policies/rule_policy'
|
|
16
15
|
require_relative 'policies/summary_policy'
|
17
16
|
require_relative 'policies_resources/rule_resources'
|
18
17
|
require_relative 'policies_resources/summary_resources'
|
18
|
+
require_relative 'api_query_builders/date_query_param_builder'
|
19
19
|
require_relative 'api_query_builders/single_query_param_builder'
|
20
20
|
require_relative 'api_query_builders/multi_query_param_builder'
|
21
21
|
require_relative 'url_builders/url_builder'
|
@@ -38,6 +38,7 @@ module Gitlab
|
|
38
38
|
@options = options
|
39
39
|
@network_adapter_class = network_adapter_class
|
40
40
|
|
41
|
+
assert_all!
|
41
42
|
assert_project_id!
|
42
43
|
assert_token!
|
43
44
|
require_ruby_files
|
@@ -66,6 +67,7 @@ module Gitlab
|
|
66
67
|
|
67
68
|
def assert_project_id!
|
68
69
|
return if options.source_id
|
70
|
+
return if options.all
|
69
71
|
|
70
72
|
raise ArgumentError, 'A project_id is needed (pass it with the `--source-id` option)!'
|
71
73
|
end
|
@@ -76,6 +78,11 @@ module Gitlab
|
|
76
78
|
raise ArgumentError, 'A token is needed (pass it with the `--token` option)!'
|
77
79
|
end
|
78
80
|
|
81
|
+
def assert_all!
|
82
|
+
raise ArgumentError, '--all-projects option cannot be used in conjunction with --source and --source-id option!' if
|
83
|
+
options.all && (options.source || options.source_id)
|
84
|
+
end
|
85
|
+
|
79
86
|
def require_ruby_files
|
80
87
|
options.require_files.each(&method(:require))
|
81
88
|
end
|
@@ -146,7 +153,7 @@ module Gitlab
|
|
146
153
|
end
|
147
154
|
|
148
155
|
def resources_for_rule(resource_type, rule)
|
149
|
-
puts Gitlab::Triage::UI.header("
|
156
|
+
puts Gitlab::Triage::UI.header("Gathering resources for rule: **#{rule[:name]}**", char: '-')
|
150
157
|
|
151
158
|
ExpandCondition.perform(rule_conditions(rule)) do |conditions|
|
152
159
|
# retrieving the resources for every rule is inefficient
|
@@ -186,22 +193,35 @@ module Gitlab
|
|
186
193
|
resources.select do |resource|
|
187
194
|
results = []
|
188
195
|
|
196
|
+
# rubocop:disable Style/IfUnlessModifier
|
189
197
|
if conditions[:date]
|
190
|
-
results <<
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
+
results << Filters::MergeRequestDateConditionsFilter.new(resource, conditions[:date]).calculate
|
199
|
+
end
|
200
|
+
|
201
|
+
if conditions[:upvotes]
|
202
|
+
results << Filters::VotesConditionsFilter.new(resource, conditions[:upvotes]).calculate
|
203
|
+
end
|
204
|
+
|
205
|
+
if conditions[:forbidden_labels]
|
206
|
+
results << Filters::ForbiddenLabelsConditionsFilter.new(resource, conditions[:forbidden_labels]).calculate
|
207
|
+
end
|
208
|
+
|
209
|
+
if conditions[:no_additional_labels]
|
210
|
+
results << Filters::NoAdditionalLabelsConditionsFilter.new(resource, conditions.fetch(:labels) { [] }).calculate
|
198
211
|
end
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
212
|
+
|
213
|
+
if conditions[:author_member]
|
214
|
+
results << Filters::AuthorMemberConditionsFilter.new(resource, conditions[:author_member], network).calculate
|
215
|
+
end
|
216
|
+
|
217
|
+
if conditions[:assignee_member]
|
218
|
+
results << Filters::AssigneeMemberConditionsFilter.new(resource, conditions[:assignee_member], network).calculate
|
219
|
+
end
|
220
|
+
|
221
|
+
if conditions[:ruby]
|
222
|
+
results << Filters::RubyConditionsFilter.new(resource, conditions, network).calculate
|
223
|
+
end
|
224
|
+
# rubocop:enable Style/IfUnlessModifier
|
205
225
|
|
206
226
|
results.all?
|
207
227
|
end
|
@@ -229,12 +249,17 @@ module Gitlab
|
|
229
249
|
condition_builders << APIQueryBuilders::SingleQueryParamBuilder.new('source_branch', conditions[:source_branch]) if conditions[:source_branch]
|
230
250
|
condition_builders << APIQueryBuilders::SingleQueryParamBuilder.new('target_branch', conditions[:target_branch]) if conditions[:target_branch]
|
231
251
|
|
252
|
+
if conditions[:date] && APIQueryBuilders::DateQueryParamBuilder.applicable?(conditions[:date])
|
253
|
+
condition_builders << APIQueryBuilders::DateQueryParamBuilder.new(conditions.delete(:date))
|
254
|
+
end
|
255
|
+
|
232
256
|
condition_builders.each do |condition_builder|
|
233
257
|
params[condition_builder.param_name] = condition_builder.param_content
|
234
258
|
end
|
235
259
|
|
236
260
|
UrlBuilders::UrlBuilder.new(
|
237
261
|
network_options: options,
|
262
|
+
all: options.all,
|
238
263
|
source: options.source,
|
239
264
|
source_id: options.source_id,
|
240
265
|
resource_type: resource_type,
|
data/lib/gitlab/triage/errors.rb
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
require_relative 'errors/network'
|
@@ -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
|
@@ -31,11 +31,12 @@ module Gitlab
|
|
31
31
|
|
32
32
|
begin
|
33
33
|
print '.'
|
34
|
+
url = response.fetch(:next_page_url) { url }
|
34
35
|
|
35
36
|
response = execute_with_retry([Net::ReadTimeout, Errors::Network::InternalServerError]) do
|
36
37
|
puts Gitlab::Triage::UI.debug "query_api: #{url}" if options.debug
|
37
38
|
|
38
|
-
@adapter.get(token,
|
39
|
+
@adapter.get(token, url)
|
39
40
|
end
|
40
41
|
|
41
42
|
results = response.delete(:results)
|
@@ -22,7 +22,7 @@ module Gitlab
|
|
22
22
|
|
23
23
|
{
|
24
24
|
more_pages: (response.headers["x-next-page"].to_s != ""),
|
25
|
-
next_page_url: url
|
25
|
+
next_page_url: next_page_url(url, response),
|
26
26
|
results: response.parsed_response,
|
27
27
|
ratelimit_remaining: response.headers["ratelimit-remaining"].to_i,
|
28
28
|
ratelimit_reset_at: Time.at(response.headers["ratelimit-reset"].to_i)
|
@@ -66,6 +66,18 @@ module Gitlab
|
|
66
66
|
|
67
67
|
raise Errors::Network::InternalServerError, 'Internal server error encountered!'
|
68
68
|
end
|
69
|
+
|
70
|
+
def next_page_url(url, response)
|
71
|
+
return unless response.headers['x-next-page'].present?
|
72
|
+
|
73
|
+
next_page = "&page=#{response.headers['x-next-page']}"
|
74
|
+
|
75
|
+
if url.include?('&page')
|
76
|
+
url.gsub(/&page=\d+/, next_page)
|
77
|
+
else
|
78
|
+
url + next_page
|
79
|
+
end
|
80
|
+
end
|
69
81
|
end
|
70
82
|
end
|
71
83
|
end
|
@@ -23,6 +23,10 @@ module Gitlab
|
|
23
23
|
options.policies_files << value
|
24
24
|
end
|
25
25
|
|
26
|
+
opts.on('--all-projects', 'Process all projects the token has access to') do |value|
|
27
|
+
options.all = value
|
28
|
+
end
|
29
|
+
|
26
30
|
opts.on('-s', '--source [type]', [:projects, :groups], 'The source type between [ projects or groups ], default value: projects') do |value|
|
27
31
|
options.source = value
|
28
32
|
end
|
@@ -59,6 +63,12 @@ module Gitlab
|
|
59
63
|
exit # rubocop:disable Rails/Exit
|
60
64
|
end
|
61
65
|
|
66
|
+
opts.on('-v', '--version', 'Print version') do
|
67
|
+
require_relative 'version'
|
68
|
+
$stdout.puts Gitlab::Triage::VERSION
|
69
|
+
exit # rubocop:disable Rails/Exit
|
70
|
+
end
|
71
|
+
|
62
72
|
opts.on('--init', 'Initialize the project with a policy file') do
|
63
73
|
example_path =
|
64
74
|
File.expand_path('../../../support/.triage-policies.example.yml', __dir__)
|
@@ -3,6 +3,7 @@ module Gitlab
|
|
3
3
|
Options = Struct.new(
|
4
4
|
:dry_run,
|
5
5
|
:policies_files,
|
6
|
+
:all,
|
6
7
|
:source,
|
7
8
|
:source_id,
|
8
9
|
:token,
|
@@ -17,6 +18,7 @@ module Gitlab
|
|
17
18
|
# Defaults
|
18
19
|
self.host_url ||= 'https://gitlab.com'
|
19
20
|
self.api_version ||= 'v4'
|
21
|
+
self.all ||= false
|
20
22
|
self.source ||= 'projects'
|
21
23
|
self.require_files ||= []
|
22
24
|
self.policies_files ||= Set.new
|
@@ -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,20 +1,19 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'forwardable'
|
4
|
+
|
3
5
|
module Gitlab
|
4
6
|
module Triage
|
5
7
|
module PoliciesResources
|
6
8
|
class RuleResources
|
7
|
-
|
9
|
+
include Enumerable
|
10
|
+
extend Forwardable
|
8
11
|
|
9
12
|
def initialize(new_resources)
|
10
13
|
@resources = new_resources
|
11
14
|
end
|
12
15
|
|
13
|
-
|
14
|
-
resources.each do |resource|
|
15
|
-
yield(resource)
|
16
|
-
end
|
17
|
-
end
|
16
|
+
def_delegator :@resources, :each
|
18
17
|
end
|
19
18
|
end
|
20
19
|
end
|
@@ -1,20 +1,19 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'forwardable'
|
4
|
+
|
3
5
|
module Gitlab
|
4
6
|
module Triage
|
5
7
|
module PoliciesResources
|
6
8
|
class SummaryResources
|
7
|
-
|
9
|
+
include Enumerable
|
10
|
+
extend Forwardable
|
8
11
|
|
9
12
|
def initialize(new_rule_to_resources)
|
10
13
|
@rule_to_resources = new_rule_to_resources
|
11
14
|
end
|
12
15
|
|
13
|
-
|
14
|
-
rule_to_resources.map do |inner_policy_spec, inner_resources|
|
15
|
-
yield(inner_policy_spec, inner_resources)
|
16
|
-
end
|
17
|
-
end
|
16
|
+
def_delegator :@rule_to_resources, :each
|
18
17
|
end
|
19
18
|
end
|
20
19
|
end
|
@@ -41,6 +41,11 @@ module Gitlab
|
|
41
41
|
|
42
42
|
private
|
43
43
|
|
44
|
+
def expand_resource!(params: {})
|
45
|
+
resource.merge!(
|
46
|
+
network.query_api_cached(resource_url(params: params)).first)
|
47
|
+
end
|
48
|
+
|
44
49
|
def source_resource
|
45
50
|
@source_resource ||= network.query_api_cached(source_url).first
|
46
51
|
end
|
@@ -12,6 +12,15 @@ module Gitlab
|
|
12
12
|
def reference
|
13
13
|
'!'
|
14
14
|
end
|
15
|
+
|
16
|
+
def first_contribution?
|
17
|
+
if resource.key?(:first_contribution)
|
18
|
+
resource[:first_contribution]
|
19
|
+
else
|
20
|
+
expanded = expand_resource!
|
21
|
+
expanded[:first_contribution]
|
22
|
+
end
|
23
|
+
end
|
15
24
|
end
|
16
25
|
end
|
17
26
|
end
|
@@ -6,6 +6,7 @@ module Gitlab
|
|
6
6
|
@network_options = options.fetch(:network_options)
|
7
7
|
@host_url = @network_options.host_url
|
8
8
|
@api_version = @network_options.api_version
|
9
|
+
@all = options.fetch(:all, false)
|
9
10
|
@source = options.fetch(:source, 'projects')
|
10
11
|
@source_id = options.fetch(:source_id)
|
11
12
|
@resource_type = options.fetch(:resource_type, nil)
|
@@ -15,11 +16,11 @@ module Gitlab
|
|
15
16
|
end
|
16
17
|
|
17
18
|
def build
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
19
|
+
url = base_url
|
20
|
+
url << "/#{@resource_id}" if @resource_id
|
21
|
+
url << "/#{@sub_resource_type}" if @sub_resource_type
|
22
|
+
url << params_string if @params
|
23
|
+
url
|
23
24
|
end
|
24
25
|
|
25
26
|
private
|
@@ -29,10 +30,10 @@ module Gitlab
|
|
29
30
|
end
|
30
31
|
|
31
32
|
def base_url
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
33
|
+
url = host_with_api_url
|
34
|
+
url << "/#{@source}/#{CGI.escape(@source_id.to_s)}" unless @all
|
35
|
+
url << "/#{@resource_type}" if @resource_type
|
36
|
+
url
|
36
37
|
end
|
37
38
|
|
38
39
|
def params_string
|
@@ -12,7 +12,9 @@ module Gitlab
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def validate_required_parameters(value)
|
15
|
-
|
15
|
+
return if value.keys.one? { |key| params_limiter_names.include?(key.to_sym) }
|
16
|
+
|
17
|
+
raise ArgumentError, "For the limits field, please specify one of: `#{params_limiter_names.join('`, `')}`"
|
16
18
|
end
|
17
19
|
end
|
18
20
|
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
|
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.10.1
|
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-07-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -120,6 +120,7 @@ files:
|
|
120
120
|
- ".gitignore"
|
121
121
|
- ".gitlab-ci.yml"
|
122
122
|
- ".gitlab/CODEOWNERS"
|
123
|
+
- ".gitlab/merge_request_templates/Release.md"
|
123
124
|
- ".rubocop.yml"
|
124
125
|
- CONTRIBUTING.md
|
125
126
|
- Gemfile
|
@@ -135,12 +136,14 @@ files:
|
|
135
136
|
- lib/gitlab/triage/action/comment.rb
|
136
137
|
- lib/gitlab/triage/action/summarize.rb
|
137
138
|
- lib/gitlab/triage/api_query_builders/base_query_param_builder.rb
|
139
|
+
- lib/gitlab/triage/api_query_builders/date_query_param_builder.rb
|
138
140
|
- lib/gitlab/triage/api_query_builders/multi_query_param_builder.rb
|
139
141
|
- lib/gitlab/triage/api_query_builders/single_query_param_builder.rb
|
140
142
|
- lib/gitlab/triage/command_builders/base_command_builder.rb
|
141
143
|
- lib/gitlab/triage/command_builders/cc_command_builder.rb
|
142
144
|
- lib/gitlab/triage/command_builders/comment_command_builder.rb
|
143
145
|
- lib/gitlab/triage/command_builders/label_command_builder.rb
|
146
|
+
- lib/gitlab/triage/command_builders/move_command_builder.rb
|
144
147
|
- lib/gitlab/triage/command_builders/remove_label_command_builder.rb
|
145
148
|
- lib/gitlab/triage/command_builders/status_command_builder.rb
|
146
149
|
- lib/gitlab/triage/command_builders/text_content_builder.rb
|
@@ -156,7 +159,6 @@ files:
|
|
156
159
|
- lib/gitlab/triage/filters/author_member_conditions_filter.rb
|
157
160
|
- lib/gitlab/triage/filters/base_conditions_filter.rb
|
158
161
|
- lib/gitlab/triage/filters/forbidden_labels_conditions_filter.rb
|
159
|
-
- lib/gitlab/triage/filters/issuable_date_conditions_filter.rb
|
160
162
|
- lib/gitlab/triage/filters/member_conditions_filter.rb
|
161
163
|
- lib/gitlab/triage/filters/merge_request_date_conditions_filter.rb
|
162
164
|
- lib/gitlab/triage/filters/name_conditions_filter.rb
|
@@ -212,7 +214,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
212
214
|
- !ruby/object:Gem::Version
|
213
215
|
version: '0'
|
214
216
|
requirements: []
|
215
|
-
rubygems_version: 3.
|
217
|
+
rubygems_version: 3.1.2
|
216
218
|
signing_key:
|
217
219
|
specification_version: 4
|
218
220
|
summary: GitLab triage automation project.
|
@@ -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
|