gitlab-triage 1.4.2 → 1.5.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: 0a3ad1de83211c86782bec839652791e4adaa7aa34e8b4a27d10c1f9216f54bc
4
- data.tar.gz: 33e4c17d4f11d4987ce54792145631e1364785d6f69e59cda1ec9f4c07b7ac7f
3
+ metadata.gz: 9187a7efe616ce28b479744eea6e43478dd680e33c026db5994a031b36432102
4
+ data.tar.gz: 89e49562453a05254b5734d735849db38ab5ad4a6e0fc38b9f3d159011f264af
5
5
  SHA512:
6
- metadata.gz: d0753dc463f49da2ebdcecaceb1cd9719303fe4996a0d8e45a1a22677a9540f1abbce33506e400578cc3e77cf48e4aa9f016c64e7403d45f6eb01d1ca9d7f0c9
7
- data.tar.gz: 22b466f912d990e290941b2d36c89b1c4c3f2136e620ac522bf688fb2325c816cc6ece5334813e2da83b1aff38781d579c1fe7de11ee661896742b8a0cb07f6b
6
+ metadata.gz: 5486b57cda76c1943e85ecab08a4613ba4a139874602abc034983d967a18fbe48f876607f7d0f26c8f7109538754c4e0f868b07c96c486ac6b370c2586bb1e0a
7
+ data.tar.gz: ef43a5344601f546c8c634da223c4d36cfec219a3fd85f98a3f56cff7f88df917bf1a5d100d0524745941db98d2bbb12fce31a941a65940dc0675dbda6c375dc
data/.gitlab-ci.yml CHANGED
@@ -14,7 +14,7 @@ stages:
14
14
 
15
15
  .default-before_script:
16
16
  before_script:
17
- - gem install bundler --no-document
17
+ - gem install bundler --no-document --version 2.0.2
18
18
  - bundle install --jobs $(nproc) --retry 3 --quiet
19
19
 
20
20
  ###################
data/.rubocop.yml CHANGED
@@ -2,5 +2,12 @@ inherit_gem:
2
2
  gitlab-styles:
3
3
  - rubocop-default.yml
4
4
 
5
+ AllCops:
6
+ TargetRubyVersion: 2.6
7
+ Exclude:
8
+ - 'vendor/**/*'
9
+ - 'tmp/**/*'
10
+ CacheRootDirectory: tmp
11
+
5
12
  Rails/Output:
6
13
  Enabled: false
data/Gemfile CHANGED
@@ -4,7 +4,5 @@ source 'https://rubygems.org'
4
4
  gemspec
5
5
 
6
6
  group :test do
7
- # Pin these dependencies, otherwise a new rule could break the CI pipelines
8
- gem 'rubocop', '0.69.0'
9
- gem 'rubocop-rspec', '1.35.0'
7
+ gem 'gitlab-styles', '~> 3.0'
10
8
  end
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  # GitLab Triage Project
4
4
 
5
- This project contains the library and pipeline definition to enable automated triaging of issues in the [GitLab-CE Project](https://gitlab.com/gitlab-org/gitlab-ce).
5
+ This project contains the library and pipeline definition to enable automated triaging of issues in the [GitLab Project](https://gitlab.com/gitlab-org/gitlab).
6
6
 
7
7
  ## gitlab-triage gem
8
8
 
@@ -33,7 +33,7 @@ create a summary issue with all the sub-policies' summaries, see
33
33
  Policies are defined in a policy file (by default `./.triage-policies.yml`).
34
34
  The format of the file is [YAML](https://en.wikipedia.org/wiki/YAML).
35
35
 
36
- > Note: You can use the [`--init`](#usage) option to add an example
36
+ > **Note:** You can use the [`--init`](#usage) option to add an example
37
37
  [`.triage-policies.yml` file](support/.triage-policies.example.yml) to your
38
38
  project.
39
39
 
@@ -69,6 +69,7 @@ resource_rules:
69
69
  comment: |
70
70
  {{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
71
  summarize:
72
+ destination: gitlab-org/gitlab-triage
72
73
  title: |
73
74
  #{resource[:type].capitalize} require labels
74
75
  item: |
@@ -127,12 +128,14 @@ Available condition types:
127
128
 
128
129
  Accepts a hash of fields.
129
130
 
130
- | Field | Type | Values | Required |
131
- | --------- | ---- | ---- | -------- |
132
- | `attribute` | string | `created_at`, `updated_at` | yes |
133
- | `condition` | string | `older_than`, `newer_than` | yes |
134
- | `interval_type` | string | `days`, `weeks`, `months`, `years` | yes |
135
- | `interval` | integer | integer | yes |
131
+ | Field | Type | Values | Required |
132
+ | --------- | ---- | ---- | -------- |
133
+ | `attribute` | string | `created_at`, `updated_at`, `merged_at` | yes |
134
+ | `condition` | string | `older_than`, `newer_than` | yes |
135
+ | `interval_type` | string | `days`, `weeks`, `months`, `years` | yes |
136
+ | `interval` | integer | integer | yes |
137
+
138
+ > **Note:** `merged_at` only works on merge requests.
136
139
 
137
140
  Example:
138
141
 
@@ -197,7 +200,7 @@ conditions:
197
200
 
198
201
  Accepts an array of strings. Each element in the array represents the name of a label to filter on.
199
202
 
200
- > Note: **All** specified labels must be present on the resource for the condition to be satisfied
203
+ > **Note:** **All** specified labels must be present on the resource for the condition to be satisfied
201
204
 
202
205
  Example:
203
206
 
@@ -216,7 +219,7 @@ expansion:
216
219
  1. List: `{ apple, orange }`
217
220
  2. Sequence: `{1..4}`
218
221
 
219
- > Note:
222
+ > **Note:**
220
223
  > - Spaces around the items are ignored.
221
224
  > - Do not rely on the expansion ordering. This is subject to change.
222
225
 
@@ -264,7 +267,7 @@ resource_rules:
264
267
  - Quality
265
268
  ```
266
269
 
267
- > Note:
270
+ > **Note:**
268
271
  > If you want to define a full label expansion, you'll need to [force string](https://yaml.org/YAML_for_ruby.html#forcing_strings) or [quote string](https://yaml.org/YAML_for_ruby.html#single-quoted_strings) because otherwise it won't be considered a string due to the YAML parser.
269
272
  > For example, we can quote the expression like `'{ apple, orange }'`, which will create 2 rules, for the two specified labels.
270
273
 
@@ -337,7 +340,7 @@ resource_rules:
337
340
 
338
341
  Accepts an array of strings. Each element in the array represents the name of a label to filter on.
339
342
 
340
- > Note: **All** specified labels must be absent on the resource for the condition to be satisfied
343
+ > **Note:** **All** specified labels must be absent on the resource for the condition to be satisfied
341
344
 
342
345
  Example:
343
346
 
@@ -373,7 +376,7 @@ Accepts a hash of fields.
373
376
  | --------- | ---- | ---- | -------- |
374
377
  | `source` | string | `group`, `project` | yes |
375
378
  | `condition` | string | `member_of`, `not_member_of` | yes |
376
- | `source_id` | integer or string | gitlab-org/gitlab-ce | yes |
379
+ | `source_id` | integer or string | gitlab-org/gitlab | yes |
377
380
 
378
381
  Example:
379
382
 
@@ -395,7 +398,7 @@ Accepts a hash of fields.
395
398
  | --------- | ---- | ---- | -------- |
396
399
  | `source` | string | `group`, `project` | yes |
397
400
  | `condition` | string | `member_of`, `not_member_of` | yes |
398
- | `source_id` | integer or string | gitlab-org/gitlab-ce | yes |
401
+ | `source_id` | integer or string | gitlab-org/gitlab | yes |
399
402
 
400
403
  Example:
401
404
 
@@ -658,14 +661,14 @@ actions:
658
661
  See [Ruby expression API](#ruby-expression-api) for the list of currently
659
662
  available API.
660
663
 
661
- **Note:** If you get a syntax error due to stray braces (`{` or `}`), use `\`
664
+ > **Note:** If you get a syntax error due to stray braces (`{` or `}`), use `\`
662
665
  to escape it. For example:
663
-
664
- ```yml
665
- actions:
666
- comment: |
667
- If \} comes first and/or following \{, you'll need to escape them. If it's just { wrapping something } then you don't need to, but it's also fine to escape them like \{ this \} if you prefer.
668
- ```
666
+ >
667
+ > ```yml
668
+ > actions:
669
+ > comment: |
670
+ > If \} comes first and/or following \{, you'll need to escape them. If it's just { wrapping something } then you don't need to, but it's also fine to escape them like \{ this \} if you prefer.
671
+ > ```
669
672
 
670
673
  ##### Summarize action
671
674
 
@@ -673,29 +676,14 @@ Generates an issue summarizing what was triaged.
673
676
 
674
677
  Accepts a hash of fields.
675
678
 
676
- | Field | Type | Description | Required | Placeholders | Ruby expression | Default |
677
- | ---- | ---- | ---- | ---- | ---- | ---- | ---- |
678
- | `title` | string | The title of the generated issue | yes | yes | no | |
679
- | `item` | string | Template representing each triaged resource | no | yes | yes | |
680
- | `summary` | string | The description of the generated issue | no | Only `{{title}}`, `{{items}}`, `{{type}}` | yes | |
679
+ | Field | Type | Description | Required | Placeholders | Ruby expression | Default |
680
+ | ---- | ---- | ---- | ---- | ---- | ---- | ---- |
681
+ | `title` | string | The title of the generated issue | yes | yes | no | |
682
+ | `destination` | integer or string | The project ID or path to create the generated issue in | no | no | no | source project |
683
+ | `item` | string | Template representing each triaged resource | no | yes | yes | |
684
+ | `summary` | string | The description of the generated issue | no | Only `{{title}}`, `{{items}}`, `{{type}}` | yes | |
681
685
  | `redact_confidential_resources` | boolean | Whether redact fields for confidential resources | no | no | no | true |
682
686
 
683
- **Note:**: Both `item` and `summary` fields act like a
684
- [comment action](#comment-action), therefore
685
- [Ruby expression](#ruby-expression) is supported.
686
- Placeholders work regularly for `item`, but for `summary` only
687
- `{{title}}`, `{{items}}`, `{{type}}` are supported because it's not tied to a
688
- particular resource like the comment action.
689
-
690
- **Note:**: No issues will be created if the specific policy doesn't yield
691
- any resources.
692
-
693
- **Note:**: `redact_confidential_resources` defaults to `true`, so fields on
694
- confidential resources will be converted to `(confidential)` except for
695
- `{{web_url}}`. Setting it to `false` will reveal the confidential fields.
696
- This will be useful if the summary is confidential itself (not implemented
697
- yet), or if we're posting to another private project (not implemented yet).
698
-
699
687
  The following placeholders are supported for `summary`:
700
688
 
701
689
  - `title`: The title of the generated issue
@@ -703,6 +691,21 @@ The following placeholders are supported for `summary`:
703
691
  - `type`: The resource type for the summary. For now `issues` or
704
692
  `merge_requests`
705
693
 
694
+ > **Note:**
695
+ > - Both `item` and `summary` fields act like a [comment action](#comment-action),
696
+ > therefore [Ruby expression](#ruby-expression) is supported.
697
+ > - Placeholders work regularly for `item`, but for `summary` only `{{title}}`,
698
+ > `{{items}}`, `{{type}}` are supported because it's not tied to a particular
699
+ > resource like the comment action.
700
+ > - No issues will be created if:
701
+ > - the specific policy doesn't yield any resources; or
702
+ > - the source type is a group and `destination` is not set.
703
+ > - `redact_confidential_resources` defaults to `true`, so fields on
704
+ > confidential resources will be converted to `(confidential)` except for
705
+ > `{{web_url}}`. Setting it to `false` will reveal the confidential fields.
706
+ > This will be useful if the summary is confidential itself (not implemented
707
+ > yet), or if we're posting to another private project (not implemented yet).
708
+
706
709
  Example:
707
710
 
708
711
  ```yml
@@ -828,9 +831,9 @@ Which could generate an issue like:
828
831
  /label ~"needs attention"
829
832
  ```
830
833
 
831
- **Note:**: If a specific policy doesn't yield any resources, it will not generate
832
- the corresponding description. If all policies yield no resources, then
833
- no issues will be created.
834
+ > **Note:** If a specific policy doesn't yield any resources, it will not
835
+ > generate the corresponding description. If all policies yield no resources,
836
+ > then no issues will be created.
834
837
 
835
838
  ### Ruby expression API
836
839
 
@@ -865,6 +868,10 @@ Here's a list of currently available Ruby expression API:
865
868
  | created_at | Time | The created timestamp of the milestone |
866
869
  | succ | Milestone | The next active milestone beside this milestone |
867
870
  | active? | Boolean | `true` if `state` is `active`; `false` otherwise |
871
+ | closed? | Boolean | `true` if `state` is `closed`; `false` otherwise |
872
+ | started? | Boolean | `true` if `start_date` exists and in the past; `false` otherwise |
873
+ | expired? | Boolean | `true` if `due_date` exists and in the past; `false` otherwise |
874
+ | in_progress?| Boolean | `true` if `started?` and `!expired`; `false` otherwise |
868
875
 
869
876
  ##### Methods for `Label`
870
877
 
@@ -952,7 +959,7 @@ run:triage:triage:
952
959
  - schedules
953
960
  ```
954
961
 
955
- > Note: You can use the [`--init-ci`](#usage) option to add an example [`.gitlab-ci.yml` file](support/.gitlab-ci.example.yml) to your project
962
+ > **Note:** You can use the [`--init-ci`](#usage) option to add an example [`.gitlab-ci.yml` file](support/.gitlab-ci.example.yml) to your project
956
963
 
957
964
  #### Can I use gitlab-triage for my self-hosted GitLab instance?
958
965
 
@@ -6,7 +6,7 @@ Gem::Specification.new do |spec|
6
6
  spec.name = 'gitlab-triage'
7
7
  spec.version = Gitlab::Triage::VERSION
8
8
  spec.authors = ['GitLab']
9
- spec.email = ['remy@rymai.me']
9
+ spec.email = ['gitlab_rubygems@gitlab.com']
10
10
 
11
11
  spec.summary = 'GitLab triage automation project.'
12
12
  spec.homepage = 'https://gitlab.com/gitlab-org/gitlab-triage'
@@ -10,7 +10,12 @@ module Gitlab
10
10
  private
11
11
 
12
12
  def perform
13
- puts "The following issue would be created for the rule **#{policy.name}**:\n\n"
13
+ if group_summary_without_destination?
14
+ puts Gitlab::Triage::UI.warn("No issue will be created: No summary destination specified when source is 'groups'.")
15
+ return
16
+ end
17
+
18
+ puts "The following issue would be created in project `#{destination}` for the rule **#{policy.name}**:\n\n"
14
19
  puts ">>>"
15
20
  puts "* Title: #{issue.title}"
16
21
  puts "* Description: #{issue.description}"
@@ -25,6 +30,11 @@ module Gitlab
25
30
  private
26
31
 
27
32
  def perform
33
+ if group_summary_without_destination?
34
+ puts Gitlab::Triage::UI.warn("Issue was not created: No summary destination specified when source is 'groups'.")
35
+ return
36
+ end
37
+
28
38
  network.post_api(post_issue_url, post_issue_body)
29
39
  end
30
40
 
@@ -32,12 +42,20 @@ module Gitlab
32
42
  @issue ||= policy.build_issue
33
43
  end
34
44
 
45
+ def destination
46
+ issue.destination || network.options.source_id
47
+ end
48
+
49
+ def group_summary_without_destination?
50
+ network.options.source == :groups && !issue.destination
51
+ end
52
+
35
53
  def post_issue_url
36
54
  # POST /projects/:id/issues
37
55
  # https://docs.gitlab.com/ee/api/issues.html#new-issue
38
56
  post_url = UrlBuilders::UrlBuilder.new(
39
57
  network_options: network.options,
40
- source_id: network.options.source_id,
58
+ source_id: destination,
41
59
  resource_type: 'issues'
42
60
  ).build
43
61
 
@@ -2,7 +2,8 @@ require 'active_support/all'
2
2
  require 'active_support/inflector'
3
3
 
4
4
  require_relative 'expand_condition'
5
- require_relative 'filters/date_conditions_filter'
5
+ require_relative 'filters/issuable_date_conditions_filter'
6
+ require_relative 'filters/merge_request_date_conditions_filter'
6
7
  require_relative 'filters/votes_conditions_filter'
7
8
  require_relative 'filters/forbidden_labels_conditions_filter'
8
9
  require_relative 'filters/no_additional_labels_conditions_filter'
@@ -185,7 +186,16 @@ module Gitlab
185
186
  resources.select do |resource|
186
187
  results = []
187
188
 
188
- results << Filters::DateConditionsFilter.new(resource, conditions[:date]).calculate if conditions[:date]
189
+ if conditions[:date]
190
+ results << case resource[:type]
191
+ when 'issues'
192
+ Filters::IssuableDateConditionsFilter.new(resource, conditions[:date]).calculate
193
+ when 'merge_requests'
194
+ Filters::MergeRequestDateConditionsFilter.new(resource, conditions[:date]).calculate
195
+ else
196
+ raise "Unknown resource type: #{resource[:type]}"
197
+ end
198
+ end
189
199
  results << Filters::VotesConditionsFilter.new(resource, conditions[:upvotes]).calculate if conditions[:upvotes]
190
200
  results << Filters::ForbiddenLabelsConditionsFilter.new(resource, conditions[:forbidden_labels]).calculate if conditions[:forbidden_labels]
191
201
  results << Filters::NoAdditionalLabelsConditionsFilter.new(resource, conditions.fetch(:labels) { [] }).calculate if conditions[:no_additional_labels]
@@ -14,6 +14,7 @@ module Gitlab
14
14
  @item_template = action[:item]
15
15
  @title_template = action[:title]
16
16
  @summary_template = action[:summary]
17
+ @summary_destination = action[:destination]
17
18
  @redact_confidentials =
18
19
  action[:redact_confidential_resources] != false
19
20
  @resources = resources
@@ -29,6 +30,10 @@ module Gitlab
29
30
  @description ||= build_text(description_resource, @summary_template)
30
31
  end
31
32
 
33
+ def destination
34
+ @summary_destination
35
+ end
36
+
32
37
  def valid?
33
38
  title =~ /\S+/ && any_resources?
34
39
  end
@@ -3,17 +3,21 @@ require_relative 'base_conditions_filter'
3
3
  module Gitlab
4
4
  module Triage
5
5
  module Filters
6
- class DateConditionsFilter < BaseConditionsFilter
6
+ class IssuableDateConditionsFilter < BaseConditionsFilter
7
7
  ATTRIBUTES = %w[updated_at created_at].freeze
8
8
  CONDITIONS = %w[older_than newer_than].freeze
9
9
  INTERVAL_TYPES = %w[days weeks months years].freeze
10
10
 
11
+ def self.allowed_attributes
12
+ self::ATTRIBUTES
13
+ end
14
+
11
15
  def self.filter_parameters
12
16
  [
13
17
  {
14
18
  name: :attribute,
15
19
  type: String,
16
- values: ATTRIBUTES
20
+ values: allowed_attributes
17
21
  },
18
22
  {
19
23
  name: :condition,
@@ -0,0 +1,23 @@
1
+ require_relative 'issuable_date_conditions_filter'
2
+
3
+ module Gitlab
4
+ module Triage
5
+ module Filters
6
+ class MergeRequestDateConditionsFilter < IssuableDateConditionsFilter
7
+ ATTRIBUTES = %w[updated_at created_at merged_at].freeze
8
+
9
+ # Guard against merge requests with no merged_at values
10
+ def resource_value
11
+ super if @resource[@attribute]
12
+ end
13
+
14
+ # Guard against merge requests with no merged_at values
15
+ def calculate
16
+ return false unless resource_value
17
+
18
+ super
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -11,6 +11,7 @@ module Gitlab
11
11
  class LabelEvent < Base
12
12
  FIELDS = %i[
13
13
  id
14
+ user
14
15
  resource_type
15
16
  resource_id
16
17
  action
@@ -58,6 +58,22 @@ module Gitlab
58
58
  state == 'active'
59
59
  end
60
60
 
61
+ def closed?
62
+ state == 'closed'
63
+ end
64
+
65
+ def started?(now = Time.now)
66
+ start_date && start_date <= now
67
+ end
68
+
69
+ def expired?(now = Time.now)
70
+ due_date && due_date <= now
71
+ end
72
+
73
+ def in_progress?(now = Time.now)
74
+ started?(now) && !expired?(now)
75
+ end
76
+
61
77
  private
62
78
 
63
79
  def current_index
@@ -13,7 +13,7 @@ module Gitlab
13
13
  @tries += 1
14
14
  result = yield
15
15
  break
16
- rescue exception_type # rubocop:disable Naming/RescuedExceptionsVariableName
16
+ rescue exception_type
17
17
  raise if maximum_retries_reached?
18
18
  end
19
19
  end
@@ -1,5 +1,5 @@
1
1
  module Gitlab
2
2
  module Triage
3
- VERSION = '1.4.2'.freeze
3
+ VERSION = '1.5.0'.freeze
4
4
  end
5
5
  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.2
4
+ version: 1.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - GitLab
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-10-22 00:00:00.000000000 Z
11
+ date: 2020-01-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -110,7 +110,7 @@ dependencies:
110
110
  version: '3.4'
111
111
  description:
112
112
  email:
113
- - remy@rymai.me
113
+ - gitlab_rubygems@gitlab.com
114
114
  executables:
115
115
  - gitlab-triage
116
116
  extensions: []
@@ -153,9 +153,10 @@ files:
153
153
  - lib/gitlab/triage/filters/assignee_member_conditions_filter.rb
154
154
  - lib/gitlab/triage/filters/author_member_conditions_filter.rb
155
155
  - lib/gitlab/triage/filters/base_conditions_filter.rb
156
- - lib/gitlab/triage/filters/date_conditions_filter.rb
157
156
  - lib/gitlab/triage/filters/forbidden_labels_conditions_filter.rb
157
+ - lib/gitlab/triage/filters/issuable_date_conditions_filter.rb
158
158
  - lib/gitlab/triage/filters/member_conditions_filter.rb
159
+ - lib/gitlab/triage/filters/merge_request_date_conditions_filter.rb
159
160
  - lib/gitlab/triage/filters/name_conditions_filter.rb
160
161
  - lib/gitlab/triage/filters/no_additional_labels_conditions_filter.rb
161
162
  - lib/gitlab/triage/filters/ruby_conditions_filter.rb