gitlab-triage 1.4.2 → 1.5.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: 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