gitlab-triage 0.8.1 → 0.9.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: ff4171b6337da58a1c33a3cd9bc903e1d2c31292462117b1b479b1445948a603
4
- data.tar.gz: 219a8eac9342d358f4a6bccd2e1abc4338d5b10a766d3a7b81ab41a5ed797cbd
3
+ metadata.gz: 565a738248a7ded7917c1dd9f43962bc564b86a391083c93b91a8e1dc70b40f3
4
+ data.tar.gz: 2faa52c47be6f7823b9a70efa108bdea330b42a60defaa72ceba563cf7820a76
5
5
  SHA512:
6
- metadata.gz: 7123c4fc8ea9722acd47db48aafa651437e64a78bc5c5172aec35cf48a7714650d8385dd0842a4a7bc68a27bccf3af1d0275b29b139a4f9de14b8a36db99c9ec
7
- data.tar.gz: d9308ca1eed39ca94712203796015763c846a042db1a1865001d2046ef94b146696aa3f26a0ad4f6a3474f335b4947cf61659eae38294655a1c76ea662fee506
6
+ metadata.gz: a248b17fdaf0faf77e7462e2d69d29efdee698680398643bf575961860a06f996f2114856cc05b146570eac93872786db654c7496389f734084de89bbe129142
7
+ data.tar.gz: 16bcfc3e4ed9e2db7d52358d4630e94cc5bf4158b37a63000e19ce75a5ad9f5b0cb013ec4e8f43f52782e33632476eea25798fd7a7a86a9c13ab65f397a841b6
data/README.md CHANGED
@@ -54,7 +54,7 @@ resource_rules:
54
54
  mention:
55
55
  - markglenfletcher
56
56
  comment: |
57
- {{author}} This issue is unlabelled after 5 days. It needs attention.
57
+ {{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')}
58
58
  merge_requests:
59
59
  rules:
60
60
  []
@@ -358,31 +358,8 @@ conditions:
358
358
  This will make it only act on resources which have active milestones and
359
359
  there exists next milestone which has already started.
360
360
 
361
- Here's a list of currently available API:
362
-
363
- ##### API
364
-
365
- | Name | Return type | Description |
366
- | ---- | ---- | ---- |
367
- | milestone | Milestone | The milestone attached to the resource |
368
-
369
- ##### Methods for `Milestone`
370
-
371
- | Method | Return type | Description |
372
- | ---- | ---- | ---- |
373
- | id | Integer | The id of the milestone |
374
- | iid | Integer | The iid of the milestone |
375
- | project_id | Integer | The project id of the milestone if available |
376
- | group_id | Integer | The group id of the milestone if available |
377
- | title | String | The title of the milestone |
378
- | description | String | The description of the milestone |
379
- | state | String | The state of the milestone. Could be `active` or `closed` |
380
- | due_date | Date | The due date of the milestone. Could be `nil` |
381
- | start_date | Date | The start date of the milestone. Could be `nil` |
382
- | updated_at | Time | The updated timestamp of the milestone |
383
- | created_at | Time | The created timestamp of the milestone |
384
- | succ | Milestone | The next active milestone beside this milestone |
385
- | active? | Boolean | `true` if `state` is `active`; `false` otherwise |
361
+ See [Ruby expression API](#ruby-expression-api) for the list of currently
362
+ available API.
386
363
 
387
364
  #### Limits field
388
365
 
@@ -525,6 +502,60 @@ actions:
525
502
  @{{author}} Are you still interested in finishing this merge request?
526
503
  ```
527
504
 
505
+ ###### Ruby expression
506
+
507
+ The comment can also contain Ruby expression, using Ruby's own string
508
+ interpolation syntax: `#{ expression }`. This gives you the most flexibility.
509
+ Suppose you want to mention the next active milestone relative to the one
510
+ associated with the resource, you can write:
511
+
512
+ ```yml
513
+ actions:
514
+ comment: |
515
+ Please move this to %"#{milestone.succ.title}".
516
+ ```
517
+
518
+ See [Ruby expression API](#ruby-expression-api) for the list of currently
519
+ available API.
520
+
521
+ **Note:** If you get a syntax error due to stray braces (`{` or `}`), use `\`
522
+ to escape it. For example:
523
+
524
+ ```yml
525
+ actions:
526
+ comment: |
527
+ 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.
528
+ ```
529
+
530
+ ### Ruby expression API
531
+
532
+ Here's a list of currently available Ruby expression API:
533
+
534
+ ##### API
535
+
536
+ | Name | Return type | Description |
537
+ | ---- | ---- | ---- |
538
+ | resource | Hash | The hash containing the raw data of the resource |
539
+ | milestone | Milestone | The milestone attached to the resource |
540
+
541
+ ##### Methods for `Milestone`
542
+
543
+ | Method | Return type | Description |
544
+ | ---- | ---- | ---- |
545
+ | id | Integer | The id of the milestone |
546
+ | iid | Integer | The iid of the milestone |
547
+ | project_id | Integer | The project id of the milestone if available |
548
+ | group_id | Integer | The group id of the milestone if available |
549
+ | title | String | The title of the milestone |
550
+ | description | String | The description of the milestone |
551
+ | state | String | The state of the milestone. Could be `active` or `closed` |
552
+ | due_date | Date | The due date of the milestone. Could be `nil` |
553
+ | start_date | Date | The start date of the milestone. Could be `nil` |
554
+ | updated_at | Time | The updated timestamp of the milestone |
555
+ | created_at | Time | The created timestamp of the milestone |
556
+ | succ | Milestone | The next active milestone beside this milestone |
557
+ | active? | Boolean | `true` if `state` is `active`; `false` otherwise |
558
+
528
559
  ### Usage
529
560
 
530
561
  ```
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
9
9
  spec.email = ['remy@rymai.me']
10
10
 
11
11
  spec.summary = 'GitLab triage automation project.'
12
- spec.homepage = 'https://gitlab.com/gitlab-org/triage'
12
+ spec.homepage = 'https://gitlab.com/gitlab-org/gitlab-triage'
13
13
  spec.license = 'MIT'
14
14
 
15
15
  spec.files = `git ls-files -z`.split("\x0").reject do |f|
@@ -0,0 +1,28 @@
1
+ require_relative 'action/comment'
2
+
3
+ module Gitlab
4
+ module Triage
5
+ module Action
6
+ def self.process(rules:, **args)
7
+ comment = rules.any? && rules
8
+
9
+ {
10
+ Comment => comment
11
+ }.compact.each do |action, rule|
12
+ act(action: action, rule: rule, **args)
13
+ end
14
+ end
15
+
16
+ def self.act(action:, dry:, **args)
17
+ klass =
18
+ if dry
19
+ action.const_get(:Dry)
20
+ else
21
+ action
22
+ end
23
+
24
+ klass.new(**args).act
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,17 @@
1
+ module Gitlab
2
+ module Triage
3
+ module Action
4
+ class Base
5
+ attr_reader :name, :type, :rule, :resources, :net
6
+
7
+ def initialize(name:, type:, rule:, resources:, net:)
8
+ @name = name
9
+ @type = type
10
+ @rule = rule
11
+ @resources = resources
12
+ @net = net
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,74 @@
1
+ require_relative 'base'
2
+ require_relative '../command_builders/comment_body_builder'
3
+ require_relative '../command_builders/comment_command_builder'
4
+ require_relative '../command_builders/label_command_builder'
5
+ require_relative '../command_builders/remove_label_command_builder'
6
+ require_relative '../command_builders/cc_command_builder'
7
+ require_relative '../command_builders/status_command_builder'
8
+
9
+ module Gitlab
10
+ module Triage
11
+ module Action
12
+ class Comment < Base
13
+ class Dry < Comment
14
+ def act
15
+ puts "\nThe following comments would be posted for the rule **#{name}**:\n\n"
16
+
17
+ super
18
+ end
19
+
20
+ private
21
+
22
+ def perform(resource, comment)
23
+ puts "# #{resource[:web_url]}\n```\n#{comment}\n```\n"
24
+ end
25
+ end
26
+
27
+ def act
28
+ resources.each do |resource|
29
+ comment = build_comment(resource)
30
+
31
+ perform(resource, comment)
32
+ end
33
+ end
34
+
35
+ private
36
+
37
+ def build_comment(resource)
38
+ CommandBuilders::CommentCommandBuilder.new(
39
+ [
40
+ CommandBuilders::CommentBodyBuilder.new(rule[:comment], resource: resource, net: net).build_command,
41
+ CommandBuilders::LabelCommandBuilder.new(rule[:labels]).build_command,
42
+ CommandBuilders::RemoveLabelCommandBuilder.new(rule[:remove_labels]).build_command,
43
+ CommandBuilders::CcCommandBuilder.new(rule[:mention]).build_command,
44
+ CommandBuilders::StatusCommandBuilder.new(rule[:status]).build_command
45
+ ]
46
+ ).build_command
47
+ end
48
+
49
+ def perform(resource, comment)
50
+ net[:network].post_api(
51
+ net[:token],
52
+ build_post_url(resource),
53
+ comment)
54
+ end
55
+
56
+ def build_post_url(resource)
57
+ # POST /projects/:id/issues/:issue_iid/notes
58
+ post_url = UrlBuilders::UrlBuilder.new(
59
+ host_url: net[:host_url],
60
+ api_version: net[:api_version],
61
+ source_id: net[:source_id],
62
+ resource_type: type,
63
+ resource_id: resource['iid'],
64
+ sub_resource_type: 'notes'
65
+ ).build
66
+
67
+ puts Gitlab::Triage::UI.debug "post_url: #{post_url}" if net[:debug]
68
+
69
+ post_url
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -1,32 +1,36 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'base_command_builder'
4
+ require_relative '../resource/context'
2
5
 
3
6
  module Gitlab
4
7
  module Triage
5
8
  module CommandBuilders
6
9
  class CommentBodyBuilder < BaseCommandBuilder
7
10
  SUPPORTED_PLACEHOLDERS = {
8
- created_at: "{{created_at}}".freeze,
9
- updated_at: "{{updated_at}}".freeze,
10
- closed_at: "{{closed_at}}".freeze,
11
- merged_at: "{{merged_at}}".freeze,
12
- state: "{{state}}".freeze,
13
- author: "@{{author.username}}".freeze,
14
- assignee: "@{{assignee.username}}".freeze,
15
- assignees: "@{{assignees.username}}".freeze,
16
- closed_by: "@{{closed_by.username}}".freeze,
17
- merged_by: "@{{merged_by.username}}".freeze,
18
- milestone: %(%"{{milestone.title}}").freeze,
19
- labels: %(~"{{labels}}").freeze,
20
- upvotes: "{{upvotes}}".freeze,
21
- downvotes: "{{downvotes}}".freeze
11
+ created_at: "{{created_at}}",
12
+ updated_at: "{{updated_at}}",
13
+ closed_at: "{{closed_at}}",
14
+ merged_at: "{{merged_at}}",
15
+ state: "{{state}}",
16
+ author: "@{{author.username}}",
17
+ assignee: "@{{assignee.username}}",
18
+ assignees: "@{{assignees.username}}",
19
+ closed_by: "@{{closed_by.username}}",
20
+ merged_by: "@{{merged_by.username}}",
21
+ milestone: %(%"{{milestone.title}}"),
22
+ labels: %(~"{{labels}}"),
23
+ upvotes: "{{upvotes}}",
24
+ downvotes: "{{downvotes}}"
22
25
  }.freeze
23
26
  PLACEHOLDER_REGEX = /{{([\w\.]+)}}/
24
27
 
25
- attr_reader :resource
28
+ attr_reader :resource, :net
26
29
 
27
- def initialize(items, resource: nil)
30
+ def initialize(items, resource: nil, net: {})
28
31
  super(items)
29
32
  @resource = resource
33
+ @net = net
30
34
  end
31
35
 
32
36
  private
@@ -38,6 +42,16 @@ module Gitlab
38
42
  def format_item(item)
39
43
  return item unless resource
40
44
 
45
+ replace_placeholders(eval_interpolation(item))
46
+ end
47
+
48
+ def eval_interpolation(item)
49
+ quoted_comment = "%Q{#{item}}"
50
+
51
+ Resource::Context.new(resource, net).eval(quoted_comment)
52
+ end
53
+
54
+ def replace_placeholders(item)
41
55
  SUPPORTED_PLACEHOLDERS.inject(item) do |comment, (placeholder, formatted_text)|
42
56
  next comment unless comment.include?("{{#{placeholder}}}")
43
57
 
@@ -9,12 +9,7 @@ require_relative 'filters/author_member_conditions_filter'
9
9
  require_relative 'filters/assignee_member_conditions_filter'
10
10
  require_relative 'filters/ruby_conditions_filter'
11
11
  require_relative 'limiters/date_field_limiter'
12
- require_relative 'command_builders/comment_body_builder'
13
- require_relative 'command_builders/comment_command_builder'
14
- require_relative 'command_builders/label_command_builder'
15
- require_relative 'command_builders/remove_label_command_builder'
16
- require_relative 'command_builders/cc_command_builder'
17
- require_relative 'command_builders/status_command_builder'
12
+ require_relative 'action'
18
13
  require_relative 'api_query_builders/single_query_param_builder'
19
14
  require_relative 'api_query_builders/multi_query_param_builder'
20
15
  require_relative 'url_builders/url_builder'
@@ -77,6 +72,17 @@ module Gitlab
77
72
  @network ||= Network.new(network_adapter, options)
78
73
  end
79
74
 
75
+ def net
76
+ @net ||= {
77
+ host_url: host_url,
78
+ api_version: api_version,
79
+ token: options.token,
80
+ source_id: options.project_id,
81
+ debug: options.debug,
82
+ network: network
83
+ }
84
+ end
85
+
80
86
  def network_adapter
81
87
  @network_adapter ||= @network_adapter_class.new(options)
82
88
  end
@@ -105,13 +111,17 @@ module Gitlab
105
111
  print "* Limiting resources..."
106
112
  resources = limit_resources(resources, rule_limits(rule))
107
113
  puts "\n* Total after limiting: #{resources.count} resources"
108
- process_resources(resource_type, resources, rule)
114
+ Action.process(
115
+ name: rule[:name],
116
+ type: resource_type,
117
+ rules: rule_actions(rule),
118
+ resources: resources,
119
+ net: net,
120
+ dry: options.dry_run)
109
121
  end
110
122
  end
111
123
 
112
124
  def filter_resources(resources, conditions)
113
- net = { host_url: host_url, api_version: api_version, token: options.token, network: network }
114
-
115
125
  resources.select do |resource|
116
126
  results = []
117
127
 
@@ -135,34 +145,6 @@ module Gitlab
135
145
  end
136
146
  end
137
147
 
138
- def process_resources(resource_type, resources, rule)
139
- if options.dry_run
140
- puts "\nThe following comments would be posted for the rule **#{rule[:name]}**:\n\n"
141
- end
142
-
143
- resources.each do |resource|
144
- comment = build_comment(rule_actions(rule), resource: resource)
145
-
146
- if options.dry_run
147
- puts "# #{resource[:web_url]}\n```\n#{comment}\n```\n"
148
- else
149
- network.post_api(options.token, build_post_url(resource_type, resource), comment)
150
- end
151
- end
152
- end
153
-
154
- def build_comment(actions, resource: nil)
155
- CommandBuilders::CommentCommandBuilder.new(
156
- [
157
- CommandBuilders::CommentBodyBuilder.new(actions[:comment], resource: resource).build_command,
158
- CommandBuilders::LabelCommandBuilder.new(actions[:labels]).build_command,
159
- CommandBuilders::RemoveLabelCommandBuilder.new(actions[:remove_labels]).build_command,
160
- CommandBuilders::CcCommandBuilder.new(actions[:mention]).build_command,
161
- CommandBuilders::StatusCommandBuilder.new(actions[:status]).build_command
162
- ]
163
- ).build_command
164
- end
165
-
166
148
  def build_get_url(resource_type, conditions)
167
149
  # Example issues query with state and labels
168
150
  # https://gitlab.com/api/v4/projects/test-triage%2Fissue-project/issues?state=open&labels=project%20label%20with%20spaces,group_label_no_spaces
@@ -191,22 +173,6 @@ module Gitlab
191
173
 
192
174
  get_url
193
175
  end
194
-
195
- def build_post_url(resource_type, resource)
196
- # POST /projects/:id/issues/:issue_iid/notes
197
- post_url = UrlBuilders::UrlBuilder.new(
198
- host_url: host_url,
199
- api_version: api_version,
200
- source_id: options.project_id,
201
- resource_type: resource_type,
202
- resource_id: resource['iid'],
203
- sub_resource_type: 'notes'
204
- ).build
205
-
206
- puts Gitlab::Triage::UI.debug "post_url: #{post_url}" if options.debug
207
-
208
- post_url
209
- end
210
176
  end
211
177
  end
212
178
  end
@@ -27,10 +27,10 @@ module Gitlab
27
27
 
28
28
  def limit
29
29
  case @criterion
30
- when :most_recent
31
- @resources.first(@threshold)
32
30
  when :oldest
33
- @resources.last(@threshold)
31
+ @resources.first(@threshold)
32
+ when :most_recent
33
+ @resources.last(@threshold).reverse
34
34
  end
35
35
  end
36
36
 
@@ -1,5 +1,5 @@
1
1
  module Gitlab
2
2
  module Triage
3
- VERSION = '0.8.1'.freeze
3
+ VERSION = '0.9.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: 0.8.1
4
+ version: 0.9.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-08-15 00:00:00.000000000 Z
11
+ date: 2018-09-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -131,6 +131,9 @@ files:
131
131
  - bin/gitlab-triage
132
132
  - gitlab-triage.gemspec
133
133
  - lib/gitlab/triage.rb
134
+ - lib/gitlab/triage/action.rb
135
+ - lib/gitlab/triage/action/base.rb
136
+ - lib/gitlab/triage/action/comment.rb
134
137
  - lib/gitlab/triage/api_query_builders/base_query_param_builder.rb
135
138
  - lib/gitlab/triage/api_query_builders/multi_query_param_builder.rb
136
139
  - lib/gitlab/triage/api_query_builders/single_query_param_builder.rb
@@ -172,7 +175,7 @@ files:
172
175
  - lib/gitlab/triage/version.rb
173
176
  - support/.gitlab-ci.example.yml
174
177
  - support/.triage-policies.example.yml
175
- homepage: https://gitlab.com/gitlab-org/triage
178
+ homepage: https://gitlab.com/gitlab-org/gitlab-triage
176
179
  licenses:
177
180
  - MIT
178
181
  metadata: {}