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 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