gitlab-triage 0.13.0 → 0.14.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: 587e71e912b7d8906ecbc081b1a07258aa6cfe80643ea34c38314256a97ab503
4
- data.tar.gz: a83dc6d31326079c8315d24af259d9015c13bb2d759684831633fd295dd0b8a1
3
+ metadata.gz: 636a4953fea53e7808b154e352c37d6a33c3cd9a57695f98d05fa90a44efd2cc
4
+ data.tar.gz: 82d61352bdd126d09650ed9f0efcbf1714783444f172a559571d33530000bef2
5
5
  SHA512:
6
- metadata.gz: ec66a05c1d691deb9eab031e69062762e492301a09fe27e2c3bf85f876b36459d715d2e6c82b6dd39706e568171643316a7558046347d07bb034740d5e0a4d32
7
- data.tar.gz: '0359fe4894503d53ba358687b66854d9153a53177ba04ebbadb9106d6d824ae0ad1bc3c2d570834b3ed81cb3ca90f2dd67555c3758ae7e254e1ca8555a825aa8'
6
+ metadata.gz: '069d55c96a5fac0989ced21614782c06b11ef8a56fb59e7bc457e73fa9bb77c223680ee1399f4854bc22697075880ef3233575a1a332ab75b934664a2a654d44'
7
+ data.tar.gz: 1521bc67e168f19d231112782f9d12457a422b93e86cfa10a4565eebb026bdbfb8e6401764ecb84a25bbbfe3687f7c189323e106de4ad2b6020618f75dde99fb
data/README.md CHANGED
@@ -6,9 +6,11 @@ This project contains the library and pipeline definition to enable automated tr
6
6
 
7
7
  ## gitlab-triage gem
8
8
 
9
- ### Summary
9
+ ### Abstract
10
10
 
11
- The `gitlab-triage` gem aims to enable project managers and maintainers to automatically triage Issues and Merge Requests in GitLab projects based on defined policies.
11
+ The `gitlab-triage` gem aims to enable project managers and maintainers to
12
+ automatically triage Issues and Merge Requests in GitLab projects based on
13
+ defined policies.
12
14
 
13
15
  ### What is a triage policy?
14
16
 
@@ -16,14 +18,21 @@ Triage policies are defined on a resource level basis, resources being:
16
18
  - Issues
17
19
  - Merge Requests
18
20
 
19
- Each policy can declare a number of conditions that must all be satisfied before a number of actions are carried out.
21
+ Each policy can declare a number of conditions that must all be satisfied before
22
+ a number of actions are carried out.
23
+
24
+ Summary policies are special policies that join multiple policies together to
25
+ create a summary issue with all the sub-policies' summaries, see
26
+ [Summary policies](#summary-policies).
20
27
 
21
28
  ### Defining a policy
22
29
 
23
30
  Policies are defined in a policy file (by default `./.triage-policies.yml`).
24
31
  The format of the file is [YAML](https://en.wikipedia.org/wiki/YAML).
25
32
 
26
- > Note: You can use the [`--init`](#usage) option to add an example [`.triage-policies.yml` file](support/.triage-policies.example.yml) to your project
33
+ > Note: You can use the [`--init`](#usage) option to add an example
34
+ [`.triage-policies.yml` file](support/.triage-policies.example.yml) to your
35
+ project.
27
36
 
28
37
  Select which resource to add the policy to:
29
38
  - `issues`
@@ -602,11 +611,11 @@ Generates an issue summarizing what was triaged.
602
611
 
603
612
  Accepts a hash of fields.
604
613
 
605
- | Field | Type | Description | Required | Placeholders | Ruby expression |
606
- | ---- | ---- | ---- | ---- | ---- | ---- |
607
- | `title` | string | The title of the generated issue | yes | no | no |
614
+ | Field | Type | Description | Required | Placeholders | Ruby expression |
615
+ | ---- | ---- | ---- | ---- | ---- | ---- |
616
+ | `title` | string | The title of the generated issue | yes | no | no |
608
617
  | `item` | string | Template representing each triaged resource | no | yes | yes |
609
- | `summary` | string | The description of the generated issue | no | Only `{{items}}` and `{{title}}` | yes |
618
+ | `summary` | string | The description of the generated issue | no | Only `{{items}}` and `{{title}}` | yes |
610
619
 
611
620
  **Note:**: Both `item` and `summary` fields act like a
612
621
  [comment action](#comment-action), therefore
@@ -658,6 +667,86 @@ Which could generate an issue like:
658
667
  /label ~"needs attention"
659
668
  ```
660
669
 
670
+ ### Summary policies
671
+
672
+ Summary policies are special policies that join multiple rule policies together
673
+ to create a summary issue with all the sub-policies' summaries.
674
+ They have the same structure as Rule policies that define `actions.summarize`.
675
+
676
+ One key difference is that the `{{items}}` placeholder represents the array of
677
+ sub-policies' summary.
678
+
679
+ Note that only the `item` and `summary` keys in the sub-policies' `actions` are
680
+ used. Any other keys (e.g. `mention`, `comment`, `labels` etc.) are ignored.
681
+
682
+ You can define such policy as follows:
683
+
684
+ ```yml
685
+ resource_rules:
686
+ issues:
687
+ summaries:
688
+ - name: Newest and oldest issues summary
689
+ actions:
690
+ summarize:
691
+ title: "Newest and oldest issues summary"
692
+ summary: |
693
+ Please triage the following issues:
694
+
695
+ {{items}}
696
+
697
+ Please take care of them before the end of #{7.days.from_now.strftime('%Y-%m-%d')}
698
+
699
+ /label ~"needs attention"
700
+ rules:
701
+ - name: New issues
702
+ conditions:
703
+ state: opened
704
+ limits:
705
+ most_recent: 2
706
+ actions:
707
+ item: "- [ ] [{{title}}]({{web_url}}) {{labels}}"
708
+ summary: |
709
+ Please triage the following new issues:
710
+
711
+ {{items}}
712
+ - name: Old issues
713
+ conditions:
714
+ state: opened
715
+ limits:
716
+ oldest: 2
717
+ actions:
718
+ item: "- [ ] [{{title}}]({{web_url}}) {{labels}}"
719
+ summary: |
720
+ Please triage the following old issues:
721
+
722
+ {{items}}
723
+ ```
724
+
725
+ Which could generate an issue like:
726
+
727
+ * Title:
728
+ ```
729
+ Newest and oldest issues summary
730
+ ```
731
+ * Description:
732
+ ``` markdown
733
+ Please triage the following issues:
734
+
735
+ Please triage the following new issues:
736
+
737
+ - [ ] [A new issue](http://example.com/group/project/issues/4)
738
+ - [ ] [Another new issue](http://example.com/group/project/issues/3) ~"label B", ~"label C"
739
+
740
+ Please triage the following old issues:
741
+
742
+ - [ ] [An old issue](http://example.com/group/project/issues/1) ~"label A", ~"label B"
743
+ - [ ] [Another old issue](http://example.com/group/project/issues/2) ~"label C"
744
+
745
+ Please take care of them before the end of 2000-01-01
746
+
747
+ /label ~"needs attention"
748
+ ```
749
+
661
750
  ### Ruby expression API
662
751
 
663
752
  Here's a list of currently available Ruby expression API:
@@ -741,11 +830,13 @@ run:triage:triage:
741
830
  Yes, you can override the host url using the following options:
742
831
 
743
832
  ##### CLI
833
+
744
834
  ```
745
835
  gitlab-triage --dry-run --token $API_TOKEN --project-id gitlab-org/triage --host-url https://gitlab.host.com
746
836
  ```
747
837
 
748
838
  ##### Policy file
839
+
749
840
  ```yml
750
841
  host_url: https://gitlab.host.com
751
842
  resource_rules:
@@ -753,4 +844,4 @@ resource_rules:
753
844
 
754
845
  ### Contributing
755
846
 
756
- Please refer to the [Contributing Guide](CONTRIBUTING.md)
847
+ Please refer to the [Contributing Guide](CONTRIBUTING.md).
@@ -4,15 +4,12 @@ require_relative 'action/comment'
4
4
  module Gitlab
5
5
  module Triage
6
6
  module Action
7
- def self.process(rules:, **args)
8
- summarize = rules.delete(:summarize)
9
- comment = rules.any? && rules
10
-
7
+ def self.process(policy:, **args)
11
8
  {
12
- Summarize => summarize,
13
- Comment => comment
14
- }.compact.each do |action, rule|
15
- act(action: action, rule: rule, **args) if rule
9
+ Summarize => policy.summarize?,
10
+ Comment => policy.comment?
11
+ }.compact.each do |action, active|
12
+ act(action: action, policy: policy, **args) if active
16
13
  end
17
14
  end
18
15
 
@@ -2,13 +2,10 @@ module Gitlab
2
2
  module Triage
3
3
  module Action
4
4
  class Base
5
- attr_reader :name, :type, :rule, :resources, :net
5
+ attr_reader :policy, :net
6
6
 
7
- def initialize(name:, type:, rule:, resources:, net:)
8
- @name = name
9
- @type = type
10
- @rule = rule
11
- @resources = resources
7
+ def initialize(policy:, net:)
8
+ @policy = policy
12
9
  @net = net
13
10
  end
14
11
  end
@@ -14,7 +14,7 @@ module Gitlab
14
14
  class Comment < Base
15
15
  class Dry < Comment
16
16
  def act
17
- puts "\nThe following comments would be posted for the rule **#{name}**:\n\n"
17
+ puts "The following comments would be posted for the rule **#{policy.name}**:\n\n"
18
18
 
19
19
  super
20
20
  end
@@ -27,7 +27,7 @@ module Gitlab
27
27
  end
28
28
 
29
29
  def act
30
- resources.each do |resource|
30
+ policy.resources.each do |resource|
31
31
  comment = build_comment(resource).strip
32
32
 
33
33
  perform(resource, comment) unless comment.empty?
@@ -39,11 +39,11 @@ module Gitlab
39
39
  def build_comment(resource)
40
40
  CommandBuilders::CommentCommandBuilder.new(
41
41
  [
42
- CommandBuilders::TextContentBuilder.new(rule[:comment], resource: resource, net: net).build_command,
43
- CommandBuilders::LabelCommandBuilder.new(rule[:labels]).build_command,
44
- CommandBuilders::RemoveLabelCommandBuilder.new(rule[:remove_labels]).build_command,
45
- CommandBuilders::CcCommandBuilder.new(rule[:mention]).build_command,
46
- CommandBuilders::StatusCommandBuilder.new(rule[:status]).build_command
42
+ CommandBuilders::TextContentBuilder.new(policy.actions[:comment], resource: resource, net: net).build_command,
43
+ CommandBuilders::LabelCommandBuilder.new(policy.actions[:labels]).build_command,
44
+ CommandBuilders::RemoveLabelCommandBuilder.new(policy.actions[:remove_labels]).build_command,
45
+ CommandBuilders::CcCommandBuilder.new(policy.actions[:mention]).build_command,
46
+ CommandBuilders::StatusCommandBuilder.new(policy.actions[:status]).build_command
47
47
  ]
48
48
  ).build_command
49
49
  end
@@ -61,7 +61,7 @@ module Gitlab
61
61
  host_url: net[:host_url],
62
62
  api_version: net[:api_version],
63
63
  source_id: net[:source_id],
64
- resource_type: type,
64
+ resource_type: policy.type,
65
65
  resource_id: resource['iid'],
66
66
  sub_resource_type: 'notes'
67
67
  ).build
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative 'base'
4
- require_relative 'summarize/issue_builder'
5
4
 
6
5
  module Gitlab
7
6
  module Triage
@@ -11,7 +10,7 @@ module Gitlab
11
10
  private
12
11
 
13
12
  def perform
14
- puts "\nThe following issue would be created for the rule **#{name}**:\n\n"
13
+ puts "The following issue would be created for the rule **#{policy.name}**:\n\n"
15
14
  puts ">>>"
16
15
  puts "* Title: #{issue.title}"
17
16
  puts "* Description: #{issue.description}"
@@ -20,7 +19,7 @@ module Gitlab
20
19
  end
21
20
 
22
21
  def act
23
- perform if resources.any? && issue.valid?
22
+ perform if policy.resources.any? && issue.valid?
24
23
  end
25
24
 
26
25
  private
@@ -30,7 +29,7 @@ module Gitlab
30
29
  end
31
30
 
32
31
  def issue
33
- @issue ||= IssueBuilder.new(rule, resources, net)
32
+ @issue ||= policy.build_issue
34
33
  end
35
34
 
36
35
  def post_issue_url
@@ -10,6 +10,8 @@ require_relative 'filters/assignee_member_conditions_filter'
10
10
  require_relative 'filters/ruby_conditions_filter'
11
11
  require_relative 'limiters/date_field_limiter'
12
12
  require_relative 'action'
13
+ require_relative 'policies/rule_policy'
14
+ require_relative 'policies/summary_policy'
13
15
  require_relative 'api_query_builders/single_query_param_builder'
14
16
  require_relative 'api_query_builders/multi_query_param_builder'
15
17
  require_relative 'url_builders/url_builder'
@@ -42,14 +44,12 @@ module Gitlab
42
44
  puts Gitlab::Triage::UI.header("Triaging the `#{options.project_id}` project", char: '=')
43
45
  puts
44
46
 
45
- resource_rules.each do |type, resource|
46
- puts Gitlab::Triage::UI.header("Processing rules for #{type}", char: '-')
47
+ resource_rules.each do |resource_type, resource|
48
+ puts Gitlab::Triage::UI.header("Processing rules for #{resource_type}", char: '-')
47
49
  puts
48
- resource[:rules].each do |rule|
49
- puts Gitlab::Triage::UI.header("Processing rule: **#{rule[:name]}**", char: '-')
50
- puts
51
- process_rule(type, rule)
52
- end
50
+
51
+ process_summaries(resource_type, resource[:summaries])
52
+ process_rules(resource_type, resource[:rules])
53
53
  end
54
54
  end
55
55
 
@@ -94,15 +94,45 @@ module Gitlab
94
94
  rule.fetch(:conditions) { {} }
95
95
  end
96
96
 
97
- def rule_actions(rule)
98
- rule.fetch(:actions) { {} }
99
- end
100
-
101
97
  def rule_limits(rule)
102
98
  rule.fetch(:limits) { {} }
103
99
  end
104
100
 
105
- def process_rule(resource_type, rule)
101
+ def process_summaries(resource_type, summaries)
102
+ return if summaries.blank?
103
+
104
+ summaries.each do |summary|
105
+ process_summary(resource_type, summary)
106
+ end
107
+ end
108
+
109
+ def process_rules(resource_type, rules)
110
+ return if rules.blank?
111
+
112
+ rules.each do |rule|
113
+ process_action(Policies::RulePolicy.new(resource_type, rule, resources_for_rule(resource_type, rule), net))
114
+ end
115
+ end
116
+
117
+ def process_summary(resource_type, summary)
118
+ puts Gitlab::Triage::UI.header("Processing summary: **#{summary[:name]}**", char: '~')
119
+ puts
120
+
121
+ resources = resources_for_rules(resource_type, summary[:rules])
122
+ # { summary_rule => resources }
123
+ summary_parts = Hash[summary[:rules].zip(resources)]
124
+
125
+ process_action(Policies::SummaryPolicy.new(resource_type, summary, summary_parts, net))
126
+ end
127
+
128
+ def resources_for_rules(resource_type, rules)
129
+ rules.map { |rule| resources_for_rule(resource_type, rule) }
130
+ end
131
+
132
+ def resources_for_rule(resource_type, rule)
133
+ puts Gitlab::Triage::UI.header("Processing rule: **#{rule[:name]}**", char: '-')
134
+ resources = []
135
+
106
136
  ExpandCondition.perform(rule_conditions(rule)) do |conditions|
107
137
  # retrieving the resources for every rule is inefficient
108
138
  # however, previous rules may affect those upcoming
@@ -114,14 +144,18 @@ module Gitlab
114
144
  print "* Limiting resources..."
115
145
  resources = limit_resources(resources, rule_limits(rule))
116
146
  puts "\n* Total after limiting: #{resources.count} resources"
117
- Action.process(
118
- name: rule[:name],
119
- type: resource_type,
120
- rules: rule_actions(rule),
121
- resources: resources,
122
- net: net,
123
- dry: options.dry_run)
147
+ puts
124
148
  end
149
+
150
+ resources
151
+ end
152
+
153
+ def process_action(policy)
154
+ Action.process(
155
+ policy: policy,
156
+ net: net,
157
+ dry: options.dry_run)
158
+ puts
125
159
  end
126
160
 
127
161
  def filter_resources(resources, conditions)
@@ -1,13 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative '../base'
4
- require_relative '../../command_builders/text_content_builder'
3
+ require_relative '../command_builders/text_content_builder'
5
4
 
6
5
  module Gitlab
7
6
  module Triage
8
- module Action
7
+ module EntityBuilders
9
8
  class IssueBuilder
10
9
  attr_reader :title
10
+ attr_writer :description, :items
11
11
 
12
12
  def initialize(action, resources, net)
13
13
  @title = action[:title]
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gitlab
4
+ module Triage
5
+ module Policies
6
+ BasePolicy = Struct.new(:type, :policy_spec, :resources, :net) do
7
+ def name
8
+ @name ||= (policy_spec[:name] || "#{type}-#{object_id}")
9
+ end
10
+
11
+ def actions
12
+ @actions ||= policy_spec.fetch(:actions) { {} }
13
+ end
14
+
15
+ def summarize?
16
+ actions.key?(:summarize)
17
+ end
18
+
19
+ def comment?
20
+ (actions.keys - [:summarize]).any?
21
+ end
22
+
23
+ def build_issue
24
+ raise NotImplementedError
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base_policy'
4
+ require_relative '../entity_builders/issue_builder'
5
+
6
+ module Gitlab
7
+ module Triage
8
+ module Policies
9
+ class RulePolicy < BasePolicy
10
+ # Build an issue from a single rule policy
11
+ def build_issue
12
+ EntityBuilders::IssueBuilder.new(actions, resources, net)
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base_policy'
4
+ require_relative 'rule_policy'
5
+ require_relative '../entity_builders/issue_builder'
6
+
7
+ module Gitlab
8
+ module Triage
9
+ module Policies
10
+ class SummaryPolicy < BasePolicy
11
+ # Build an issue from several rules policies
12
+ def build_issue
13
+ EntityBuilders::IssueBuilder.new(actions[:summarize].merge(item: "{{description}}\n\n"), [], net).tap do |issue|
14
+ issue.items =
15
+ resources.map do |inner_policy_spec, inner_resources|
16
+ Policies::RulePolicy.new(type, inner_policy_spec, inner_resources, net).build_issue.description
17
+ end.join("\n\n")
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -1,5 +1,5 @@
1
1
  module Gitlab
2
2
  module Triage
3
- VERSION = '0.13.0'.freeze
3
+ VERSION = '0.14.0'.freeze
4
4
  end
5
5
  end
@@ -14,6 +14,36 @@ resource_rules:
14
14
  actions:
15
15
  comment: |
16
16
  This issue has been open for one week and is unlabelled
17
+ summaries:
18
+ - name: Newest and oldest issues summary
19
+ actions:
20
+ summarize:
21
+ title: "Newest and oldest issues summary"
22
+ summary: |
23
+ Please triage the following issues:
24
+
25
+ {{items}}
26
+
27
+ Please take care of them before the end of #{7.days.from_now.strftime('%Y-%m-%d')}
28
+
29
+ /label ~"needs attention"
30
+ rules:
31
+ - name: New issues
32
+ conditions:
33
+ state: opened
34
+ limits:
35
+ most_recent: 2
36
+ actions:
37
+ item: "- [ ] [{{title}}]({{web_url}}) {{labels}}"
38
+ summary: "Please triage the following new issues:\n\n{{items}}"
39
+ - name: Old issues
40
+ conditions:
41
+ state: opened
42
+ limits:
43
+ oldest: 2
44
+ actions:
45
+ item: "- [ ] [{{title}}]({{web_url}}) {{labels}}"
46
+ summary: "Please triage the following old issues:\n\n{{items}}"
17
47
  merge_requests:
18
48
  rules:
19
49
  []
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: 0.13.0
4
+ version: 0.14.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - GitLab
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-11-12 00:00:00.000000000 Z
11
+ date: 2018-11-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -135,7 +135,6 @@ files:
135
135
  - lib/gitlab/triage/action/base.rb
136
136
  - lib/gitlab/triage/action/comment.rb
137
137
  - lib/gitlab/triage/action/summarize.rb
138
- - lib/gitlab/triage/action/summarize/issue_builder.rb
139
138
  - lib/gitlab/triage/api_query_builders/base_query_param_builder.rb
140
139
  - lib/gitlab/triage/api_query_builders/multi_query_param_builder.rb
141
140
  - lib/gitlab/triage/api_query_builders/single_query_param_builder.rb
@@ -147,6 +146,7 @@ files:
147
146
  - lib/gitlab/triage/command_builders/status_command_builder.rb
148
147
  - lib/gitlab/triage/command_builders/text_content_builder.rb
149
148
  - lib/gitlab/triage/engine.rb
149
+ - lib/gitlab/triage/entity_builders/issue_builder.rb
150
150
  - lib/gitlab/triage/expand_condition.rb
151
151
  - lib/gitlab/triage/expand_condition/expansion.rb
152
152
  - lib/gitlab/triage/expand_condition/list.rb
@@ -167,6 +167,9 @@ files:
167
167
  - lib/gitlab/triage/network_adapters/base_adapter.rb
168
168
  - lib/gitlab/triage/network_adapters/httparty_adapter.rb
169
169
  - lib/gitlab/triage/network_adapters/test_adapter.rb
170
+ - lib/gitlab/triage/policies/base_policy.rb
171
+ - lib/gitlab/triage/policies/rule_policy.rb
172
+ - lib/gitlab/triage/policies/summary_policy.rb
170
173
  - lib/gitlab/triage/resource/base.rb
171
174
  - lib/gitlab/triage/resource/context.rb
172
175
  - lib/gitlab/triage/resource/instance_version.rb