gitlab-triage 1.9.0 → 1.13.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d17d4b0574943a4b6dc8419c28fe0d8d09577adebe135e6aafe6cdd06a2ebd12
4
- data.tar.gz: 7e937ca82cec7feec0e7223d7a6e4a967cd0d0a65d54a26b807f32cad3bf8669
3
+ metadata.gz: 68fbfe16d2db2547d8b262ff52cb7065860d13822a92b38d6d505234aafa0855
4
+ data.tar.gz: 99dc42b1125665a331b8dd6afe576e1c0b8b0abbd0cf8239d5be44184e900c52
5
5
  SHA512:
6
- metadata.gz: 7041a271066e0b933dfc3d3fa47b7150592746c3a0f25352b363cfc4f6de9c48556ede940394e72c5054e7076244e3e87cc4c2e068755a43e66bbf3d1934f5ed
7
- data.tar.gz: bf26c4395bc081ac3930f001448f33d4342dcb2f3a0aac8f74cff84aabe2f665675be8adf5578a2ef3a39d573c5d6f7dbcfeafa7a88339b389ab839a5c7918aa
6
+ metadata.gz: 37e60f6230d1467d18246aa4dc52f439c08939f5a7e2278ed543090c08d5c08b39bffc2840543cbd0a702480d8fbeeb65dc7932fe90a98c2d26a88c8b19f3805
7
+ data.tar.gz: 8f82804d8431b08791f3e37974a0cc47aacec887af2969f3e612cba8ac8212e0ac6a25f4235424801b01f6eb0d5bc6db72535d0fed1f962658270164613034cd
@@ -2,7 +2,7 @@ stages:
2
2
  - prepare
3
3
  - test
4
4
  - triage
5
- - release
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 $API_TOKEN --source-id $CI_PROJECT_PATH
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
- ## 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
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 scenarios and scenario updates
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 (CI, backstage)
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 $API_TOKEN --source-id gitlab-org/triage
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 $API_TOKEN --source-id gitlab-org --source groups
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 $API_TOKEN --all-projects
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 `$API_TOKEN`
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 $API_TOKEN --source-id $CI_PROJECT_PATH
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 $API_TOKEN --source-id gitlab-org/triage --host-url https://gitlab.host.com
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 $API_TOKEN --source-id gitlab-org/triage
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 @items.any?
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
- @items.map do |item|
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
 
@@ -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("Processing rule: **#{rule[:name]}**", char: '-')
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 << case resource[:type]
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 'issuable_date_conditions_filter'
1
+ require_relative 'base_conditions_filter'
2
2
 
3
3
  module Gitlab
4
4
  module Triage
5
5
  module Filters
6
- class MergeRequestDateConditionsFilter < IssuableDateConditionsFilter
7
- ATTRIBUTES = %w[updated_at created_at merged_at].freeze
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
- super if @resource[@attribute]
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
- super
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
@@ -15,7 +15,7 @@ module Gitlab
15
15
  type: type,
16
16
  policy_spec: policy_spec,
17
17
  action: action,
18
- resources: resources.resources,
18
+ resources: resources,
19
19
  network: network)
20
20
  end
21
21
  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.build_issues do |inner_policy_spec, inner_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
- class RuleResources
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
- class SummaryResources
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: resource[:iid],
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}/#{CGI.escape(@source_id.to_s)}" unless @all
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 ArgumentError, "#{param[:name]} is a required parameter" unless value[param[:name]]
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 ArgumentError, "#{param[:name]} must be of type #{param[:type]}" unless param_types.any? { |type| value[param[:name]].is_a?(type) }
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 ArgumentError, "#{param[:name]} must be of one of #{param[:values].join(',')}" unless param[:values].include?(value[param[:name]])
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
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Gitlab
4
4
  module Triage
5
- VERSION = '1.9.0'
5
+ VERSION = '1.13.0'
6
6
  end
7
7
  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 $API_TOKEN --source projects --source-id $CI_PROJECT_PATH
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 $API_TOKEN --source projects --source-id $CI_PROJECT_PATH
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.9.0
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-06-15 00:00:00.000000000 Z
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