payping-gitlab-triage 0.1.1
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 +7 -0
- data/.codeclimate.yml +19 -0
- data/.gitignore +15 -0
- data/.gitlab/CODEOWNERS +2 -0
- data/.gitlab/changelog_config.yml +13 -0
- data/.gitlab/issue_templates/Default.md +13 -0
- data/.gitlab/merge_request_templates/Default.md +11 -0
- data/.gitlab/merge_request_templates/Release.md +13 -0
- data/.gitlab-ci.yml +146 -0
- data/.rubocop.yml +21 -0
- data/.rubocop_todo.yml +145 -0
- data/.ruby-version +1 -0
- data/.tool-versions +1 -0
- data/.yardopts +4 -0
- data/CONTRIBUTING.md +31 -0
- data/Dangerfile +5 -0
- data/Gemfile +15 -0
- data/Guardfile +70 -0
- data/LICENSE.md +25 -0
- data/README.md +1480 -0
- data/Rakefile +6 -0
- data/bin/gitlab-triage +19 -0
- data/gitlab-triage.gemspec +41 -0
- data/lib/gitlab/triage/action/base.rb +14 -0
- data/lib/gitlab/triage/action/comment.rb +104 -0
- data/lib/gitlab/triage/action/comment_on_summary.rb +83 -0
- data/lib/gitlab/triage/action/delete.rb +56 -0
- data/lib/gitlab/triage/action/issue.rb +64 -0
- data/lib/gitlab/triage/action/summarize.rb +82 -0
- data/lib/gitlab/triage/action.rb +36 -0
- data/lib/gitlab/triage/api_query_builders/base_query_param_builder.rb +27 -0
- data/lib/gitlab/triage/api_query_builders/date_query_param_builder.rb +42 -0
- data/lib/gitlab/triage/api_query_builders/multi_query_param_builder.rb +28 -0
- data/lib/gitlab/triage/api_query_builders/single_query_param_builder.rb +13 -0
- data/lib/gitlab/triage/command_builders/base_command_builder.rb +40 -0
- data/lib/gitlab/triage/command_builders/cc_command_builder.rb +19 -0
- data/lib/gitlab/triage/command_builders/comment_command_builder.rb +19 -0
- data/lib/gitlab/triage/command_builders/label_command_builder.rb +40 -0
- data/lib/gitlab/triage/command_builders/move_command_builder.rb +19 -0
- data/lib/gitlab/triage/command_builders/remove_label_command_builder.rb +15 -0
- data/lib/gitlab/triage/command_builders/status_command_builder.rb +23 -0
- data/lib/gitlab/triage/command_builders/text_content_builder.rb +138 -0
- data/lib/gitlab/triage/engine.rb +635 -0
- data/lib/gitlab/triage/entity_builders/issue_builder.rb +54 -0
- data/lib/gitlab/triage/entity_builders/summary_builder.rb +82 -0
- data/lib/gitlab/triage/errors/network.rb +11 -0
- data/lib/gitlab/triage/errors.rb +1 -0
- data/lib/gitlab/triage/expand_condition/expansion.rb +203 -0
- data/lib/gitlab/triage/expand_condition/list.rb +25 -0
- data/lib/gitlab/triage/expand_condition/sequence.rb +25 -0
- data/lib/gitlab/triage/expand_condition.rb +23 -0
- data/lib/gitlab/triage/filters/assignee_member_conditions_filter.rb +13 -0
- data/lib/gitlab/triage/filters/author_member_conditions_filter.rb +13 -0
- data/lib/gitlab/triage/filters/base_conditions_filter.rb +58 -0
- data/lib/gitlab/triage/filters/branch_date_filter.rb +73 -0
- data/lib/gitlab/triage/filters/branch_protected_filter.rb +26 -0
- data/lib/gitlab/triage/filters/discussions_conditions_filter.rb +58 -0
- data/lib/gitlab/triage/filters/issue_date_conditions_filter.rb +78 -0
- data/lib/gitlab/triage/filters/member_conditions_filter.rb +84 -0
- data/lib/gitlab/triage/filters/merge_request_date_conditions_filter.rb +13 -0
- data/lib/gitlab/triage/filters/name_conditions_filter.rb +26 -0
- data/lib/gitlab/triage/filters/no_additional_labels_conditions_filter.rb +30 -0
- data/lib/gitlab/triage/filters/ruby_conditions_filter.rb +33 -0
- data/lib/gitlab/triage/filters/votes_conditions_filter.rb +54 -0
- data/lib/gitlab/triage/graphql_network.rb +81 -0
- data/lib/gitlab/triage/graphql_queries/query_builder.rb +158 -0
- data/lib/gitlab/triage/graphql_queries/query_param_builders/base_param_builder.rb +30 -0
- data/lib/gitlab/triage/graphql_queries/query_param_builders/date_param_builder.rb +35 -0
- data/lib/gitlab/triage/graphql_queries/query_param_builders/labels_param_builder.rb +18 -0
- data/lib/gitlab/triage/limiters/base_limiter.rb +35 -0
- data/lib/gitlab/triage/limiters/date_field_limiter.rb +45 -0
- data/lib/gitlab/triage/network.rb +39 -0
- data/lib/gitlab/triage/network_adapters/base_adapter.rb +17 -0
- data/lib/gitlab/triage/network_adapters/graphql_adapter.rb +92 -0
- data/lib/gitlab/triage/network_adapters/httparty_adapter.rb +116 -0
- data/lib/gitlab/triage/network_adapters/test_adapter.rb +39 -0
- data/lib/gitlab/triage/option_parser.rb +105 -0
- data/lib/gitlab/triage/options.rb +30 -0
- data/lib/gitlab/triage/param_builders/date_param_builder.rb +64 -0
- data/lib/gitlab/triage/policies/base_policy.rb +80 -0
- data/lib/gitlab/triage/policies/rule_policy.rb +36 -0
- data/lib/gitlab/triage/policies/summary_policy.rb +29 -0
- data/lib/gitlab/triage/policies_resources/rule_resources.rb +11 -0
- data/lib/gitlab/triage/policies_resources/summary_resources.rb +11 -0
- data/lib/gitlab/triage/resource/base.rb +102 -0
- data/lib/gitlab/triage/resource/branch.rb +13 -0
- data/lib/gitlab/triage/resource/context.rb +47 -0
- data/lib/gitlab/triage/resource/epic.rb +20 -0
- data/lib/gitlab/triage/resource/instance_version.rb +35 -0
- data/lib/gitlab/triage/resource/issue.rb +52 -0
- data/lib/gitlab/triage/resource/label.rb +56 -0
- data/lib/gitlab/triage/resource/label_event.rb +48 -0
- data/lib/gitlab/triage/resource/linked_issue.rb +15 -0
- data/lib/gitlab/triage/resource/merge_request.rb +23 -0
- data/lib/gitlab/triage/resource/milestone.rb +98 -0
- data/lib/gitlab/triage/resource/shared/issuable.rb +119 -0
- data/lib/gitlab/triage/rest_api_network.rb +125 -0
- data/lib/gitlab/triage/retryable.rb +33 -0
- data/lib/gitlab/triage/ui.rb +23 -0
- data/lib/gitlab/triage/url_builders/url_builder.rb +54 -0
- data/lib/gitlab/triage/utils.rb +13 -0
- data/lib/gitlab/triage/validators/limiter_validator.rb +21 -0
- data/lib/gitlab/triage/validators/params_validator.rb +43 -0
- data/lib/gitlab/triage/version.rb +7 -0
- data/lib/gitlab/triage.rb +6 -0
- data/support/.gitlab-ci.example.yml +22 -0
- data/support/.triage-policies.example.yml +51 -0
- metadata +280 -0
data/Rakefile
ADDED
data/bin/gitlab-triage
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require 'yaml'
|
|
4
|
+
require_relative '../lib/gitlab/triage/option_parser'
|
|
5
|
+
require_relative '../lib/gitlab/triage/engine'
|
|
6
|
+
require_relative '../lib/gitlab/triage/ui'
|
|
7
|
+
|
|
8
|
+
options = Gitlab::Triage::OptionParser.parse(ARGV)
|
|
9
|
+
options.policies_files << '.triage-policies.yml' if options.policies_files.empty?
|
|
10
|
+
|
|
11
|
+
options.policies_files.each do |policies_file|
|
|
12
|
+
policies = HashWithIndifferentAccess.new(YAML.load_file(policies_file))
|
|
13
|
+
|
|
14
|
+
policy_engine = Gitlab::Triage::Engine
|
|
15
|
+
.new(policies: policies, options: options)
|
|
16
|
+
|
|
17
|
+
puts Gitlab::Triage::UI.header("Executing policies from #{policies_file}.", char: '*')
|
|
18
|
+
policy_engine.perform
|
|
19
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
lib = File.expand_path('lib', __dir__)
|
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
3
|
+
require 'gitlab/triage/version'
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |spec|
|
|
6
|
+
spec.name = 'payping-gitlab-triage'
|
|
7
|
+
spec.version = Gitlab::Triage::VERSION
|
|
8
|
+
spec.authors = ['GitLab']
|
|
9
|
+
spec.email = ['gitlab_rubygems@gitlab.com']
|
|
10
|
+
|
|
11
|
+
spec.summary = 'GitLab triage automation project.'
|
|
12
|
+
spec.homepage = 'https://gitlab.com/gitlab-org/ruby/gems/gitlab-triage'
|
|
13
|
+
spec.license = 'MIT'
|
|
14
|
+
spec.required_ruby_version = Gem::Requirement.new(">= 2.5.0")
|
|
15
|
+
|
|
16
|
+
spec.metadata["allowed_push_host"] = "https://rubygems.org"
|
|
17
|
+
|
|
18
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
|
19
|
+
spec.metadata["source_code_uri"] = "https://gitlab.com/gitlab-org/ruby/gems/gitlab-triage"
|
|
20
|
+
spec.metadata["changelog_uri"] = "https://gitlab.com/gitlab-org/ruby/gems/gitlab-triage/-/releases"
|
|
21
|
+
|
|
22
|
+
# Specify which files should be added to the gem when it is released.
|
|
23
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
|
24
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
|
25
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match?(%r{^(docs?|spec|tmp)/}) }
|
|
26
|
+
end
|
|
27
|
+
spec.bindir = 'bin'
|
|
28
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
|
29
|
+
spec.require_paths = ['lib']
|
|
30
|
+
|
|
31
|
+
spec.add_dependency 'activesupport', '>= 5.1'
|
|
32
|
+
spec.add_dependency 'globalid', '~> 0.4'
|
|
33
|
+
spec.add_dependency 'graphql-client', '~> 0.16'
|
|
34
|
+
spec.add_dependency 'httparty', '~> 0.17'
|
|
35
|
+
|
|
36
|
+
spec.add_development_dependency 'bundler'
|
|
37
|
+
spec.add_development_dependency 'gitlab-styles', '~> 2.8'
|
|
38
|
+
spec.add_development_dependency 'rake', '~> 10.2'
|
|
39
|
+
spec.add_development_dependency 'rspec', '~> 3.8'
|
|
40
|
+
spec.add_development_dependency 'webmock', '~> 3.4'
|
|
41
|
+
end
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base'
|
|
4
|
+
require_relative '../command_builders/text_content_builder'
|
|
5
|
+
require_relative '../command_builders/comment_command_builder'
|
|
6
|
+
require_relative '../command_builders/label_command_builder'
|
|
7
|
+
require_relative '../command_builders/remove_label_command_builder'
|
|
8
|
+
require_relative '../command_builders/cc_command_builder'
|
|
9
|
+
require_relative '../command_builders/status_command_builder'
|
|
10
|
+
require_relative '../command_builders/move_command_builder'
|
|
11
|
+
|
|
12
|
+
module Gitlab
|
|
13
|
+
module Triage
|
|
14
|
+
module Action
|
|
15
|
+
class Comment < Base
|
|
16
|
+
class Dry < Comment
|
|
17
|
+
def act
|
|
18
|
+
puts "The following comments would be posted for the rule **#{policy.name}**:\n\n"
|
|
19
|
+
|
|
20
|
+
super
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def perform(resource, comment)
|
|
26
|
+
puts "# #{resource[:web_url]}\n```\n#{comment}\n```\n"
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def act
|
|
31
|
+
if policy.type == 'branches'
|
|
32
|
+
puts Gitlab::Triage::UI.warn "Comment actions are not available for branches. They will NOT be performed\n\n"
|
|
33
|
+
return
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
policy.resources.each do |resource|
|
|
37
|
+
comment = build_comment(resource).strip
|
|
38
|
+
|
|
39
|
+
perform(resource, comment) unless comment.empty?
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
private
|
|
44
|
+
|
|
45
|
+
def build_comment(resource)
|
|
46
|
+
CommandBuilders::CommentCommandBuilder.new(
|
|
47
|
+
[
|
|
48
|
+
CommandBuilders::TextContentBuilder.new(policy.actions[:comment], resource: resource, network: network).build_command,
|
|
49
|
+
CommandBuilders::LabelCommandBuilder.new(policy.actions[:labels], resource: resource, network: network).build_command,
|
|
50
|
+
CommandBuilders::RemoveLabelCommandBuilder.new(policy.actions[:remove_labels], resource: resource, network: network).build_command,
|
|
51
|
+
CommandBuilders::CcCommandBuilder.new(policy.actions[:mention]).build_command,
|
|
52
|
+
CommandBuilders::MoveCommandBuilder.new(policy.actions[:move]).build_command,
|
|
53
|
+
CommandBuilders::StatusCommandBuilder.new(policy.actions[:status]).build_command
|
|
54
|
+
]
|
|
55
|
+
).build_command
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def perform(resource, comment)
|
|
59
|
+
network.post_api(
|
|
60
|
+
build_post_url(resource),
|
|
61
|
+
body: comment)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def build_post_url(resource)
|
|
65
|
+
url_builder_opts = {
|
|
66
|
+
network_options: network.options,
|
|
67
|
+
source: policy.source,
|
|
68
|
+
source_id: resource[policy.source_id_sym],
|
|
69
|
+
resource_type: policy.type,
|
|
70
|
+
resource_id: resource_id(resource),
|
|
71
|
+
sub_resource_type: sub_resource_type
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
# POST /(groups|projects)/:id/(epics|issues|merge_requests)/:iid/notes
|
|
75
|
+
post_url = UrlBuilders::UrlBuilder.new(url_builder_opts).build
|
|
76
|
+
|
|
77
|
+
puts Gitlab::Triage::UI.debug "post_url: #{post_url}" if network.options.debug
|
|
78
|
+
|
|
79
|
+
post_url
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def sub_resource_type
|
|
83
|
+
case type = policy.actions[:comment_type]
|
|
84
|
+
when 'comment', nil # nil is default
|
|
85
|
+
'notes'
|
|
86
|
+
when 'thread'
|
|
87
|
+
'discussions'
|
|
88
|
+
else
|
|
89
|
+
raise ArgumentError, "Unknown comment type: #{type}"
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def resource_id(resource)
|
|
94
|
+
case policy.type
|
|
95
|
+
when 'epics'
|
|
96
|
+
resource['id']
|
|
97
|
+
else
|
|
98
|
+
resource['iid']
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base'
|
|
4
|
+
require_relative '../command_builders/text_content_builder'
|
|
5
|
+
require_relative '../command_builders/comment_command_builder'
|
|
6
|
+
require_relative '../command_builders/label_command_builder'
|
|
7
|
+
require_relative '../command_builders/remove_label_command_builder'
|
|
8
|
+
require_relative '../command_builders/cc_command_builder'
|
|
9
|
+
require_relative '../command_builders/status_command_builder'
|
|
10
|
+
require_relative '../command_builders/move_command_builder'
|
|
11
|
+
|
|
12
|
+
module Gitlab
|
|
13
|
+
module Triage
|
|
14
|
+
module Action
|
|
15
|
+
class CommentOnSummary < Base
|
|
16
|
+
class Dry < CommentOnSummary
|
|
17
|
+
def act
|
|
18
|
+
puts "The following comments would be posted for the rule **#{policy.name}**:\n\n"
|
|
19
|
+
|
|
20
|
+
super
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def perform(comment)
|
|
26
|
+
puts "# #{summary[:web_url]}\n```\n#{comment}\n```\n"
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
attr_reader :summary
|
|
31
|
+
|
|
32
|
+
def initialize(policy:, network:)
|
|
33
|
+
super(policy: policy, network: network)
|
|
34
|
+
@summary = policy.summary
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def act
|
|
38
|
+
policy.resources.each do |resource|
|
|
39
|
+
comment = build_comment(resource).strip
|
|
40
|
+
|
|
41
|
+
perform(comment) unless comment.empty?
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
private
|
|
46
|
+
|
|
47
|
+
def build_comment(resource)
|
|
48
|
+
CommandBuilders::TextContentBuilder.new(policy.actions[:comment_on_summary], resource: resource, network: network).build_command
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def perform(comment)
|
|
52
|
+
network.post_api(build_post_url, body: comment)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def build_post_url
|
|
56
|
+
# POST /projects/:id/issues/:issue_iid/notes
|
|
57
|
+
post_url = UrlBuilders::UrlBuilder.new(
|
|
58
|
+
network_options: network.options,
|
|
59
|
+
source_id: summary['project_id'],
|
|
60
|
+
resource_type: policy.type,
|
|
61
|
+
resource_id: summary['iid'],
|
|
62
|
+
sub_resource_type: sub_resource_type
|
|
63
|
+
).build
|
|
64
|
+
|
|
65
|
+
puts Gitlab::Triage::UI.debug "post_url: #{post_url}" if network.options.debug
|
|
66
|
+
|
|
67
|
+
post_url
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def sub_resource_type
|
|
71
|
+
case type = policy.actions[:comment_type]
|
|
72
|
+
when 'comment', nil # nil is default
|
|
73
|
+
'notes'
|
|
74
|
+
when 'thread'
|
|
75
|
+
'discussions'
|
|
76
|
+
else
|
|
77
|
+
raise ArgumentError, "Unknown comment type: #{type}"
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base'
|
|
4
|
+
|
|
5
|
+
module Gitlab
|
|
6
|
+
module Triage
|
|
7
|
+
module Action
|
|
8
|
+
class Delete < Base
|
|
9
|
+
class Dry < Delete
|
|
10
|
+
def act
|
|
11
|
+
puts "The following resources will be deleted by the rule **#{policy.name}**:\n\n"
|
|
12
|
+
super
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
private
|
|
16
|
+
|
|
17
|
+
def perform(resource)
|
|
18
|
+
puts "DELETE resource with type: #{resource[:type]} and id: #{resource_id(resource)}"
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def act
|
|
23
|
+
return unless policy.type&.to_sym == :branches
|
|
24
|
+
|
|
25
|
+
policy.resources.each do |resource|
|
|
26
|
+
perform(resource)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
def perform(resource)
|
|
33
|
+
network.delete_api(build_delete_url(resource))
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def build_delete_url(resource)
|
|
37
|
+
delete_url = UrlBuilders::UrlBuilder.new(
|
|
38
|
+
source: policy.source,
|
|
39
|
+
source_id: network.options.source_id,
|
|
40
|
+
resource_type: policy.type,
|
|
41
|
+
resource_id: resource_id(resource),
|
|
42
|
+
network_options: network.options
|
|
43
|
+
).build
|
|
44
|
+
|
|
45
|
+
puts Gitlab::Triage::UI.debug "delete_url: #{delete_url}" if network.options.debug
|
|
46
|
+
|
|
47
|
+
delete_url
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def resource_id(resource)
|
|
51
|
+
resource[:name]
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base'
|
|
4
|
+
|
|
5
|
+
module Gitlab
|
|
6
|
+
module Triage
|
|
7
|
+
module Action
|
|
8
|
+
class Issue < Base
|
|
9
|
+
class Dry < Issue
|
|
10
|
+
def act
|
|
11
|
+
puts "The following issues would be created for the rule **#{policy.name}**:\n\n"
|
|
12
|
+
|
|
13
|
+
super
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
def perform(resource, issue)
|
|
19
|
+
puts ">>>"
|
|
20
|
+
puts "* Project: #{issue.destination || resource[policy.source_id_sym]}"
|
|
21
|
+
puts "* Title: #{issue.title}"
|
|
22
|
+
puts "* Description: #{issue.description}"
|
|
23
|
+
puts ">>>"
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def act
|
|
28
|
+
policy.resources.each do |resource|
|
|
29
|
+
issue = policy.build_issue(resource)
|
|
30
|
+
|
|
31
|
+
perform(resource, issue) if issue.valid?
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
def perform(resource, issue)
|
|
38
|
+
network.post_api(build_post_url(resource, issue), post_issue_body(issue))
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def build_post_url(resource, issue)
|
|
42
|
+
# POST /projects/:id/issues
|
|
43
|
+
# https://docs.gitlab.com/ee/api/issues.html#new-issue
|
|
44
|
+
post_url = UrlBuilders::UrlBuilder.new(
|
|
45
|
+
network_options: network.options,
|
|
46
|
+
source_id: issue.destination || resource[policy.source_id_sym],
|
|
47
|
+
resource_type: 'issues'
|
|
48
|
+
).build
|
|
49
|
+
|
|
50
|
+
puts Gitlab::Triage::UI.debug "post_issue_url: #{post_url}" if network.options.debug
|
|
51
|
+
|
|
52
|
+
post_url
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def post_issue_body(issue)
|
|
56
|
+
{
|
|
57
|
+
title: issue.title,
|
|
58
|
+
description: issue.description
|
|
59
|
+
}
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base'
|
|
4
|
+
|
|
5
|
+
module Gitlab
|
|
6
|
+
module Triage
|
|
7
|
+
module Action
|
|
8
|
+
class Summarize < Base
|
|
9
|
+
class Dry < Summarize
|
|
10
|
+
private
|
|
11
|
+
|
|
12
|
+
def perform
|
|
13
|
+
policy.summary = {
|
|
14
|
+
web_url: '[the-created-issue-url]',
|
|
15
|
+
project_id: 'some-id',
|
|
16
|
+
iid: 'some-iid'
|
|
17
|
+
}.with_indifferent_access
|
|
18
|
+
|
|
19
|
+
if group_summary_without_destination?
|
|
20
|
+
puts Gitlab::Triage::UI.warn("No issue will be created: No summary destination specified when source is 'groups'.")
|
|
21
|
+
return
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
puts "The following issue would be created in project `#{destination}` for the rule **#{policy.name}**:\n\n"
|
|
25
|
+
puts ">>>"
|
|
26
|
+
puts "* Title: #{issue.title}"
|
|
27
|
+
puts "* Description: #{issue.description}"
|
|
28
|
+
puts ">>>"
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def act
|
|
33
|
+
perform if issue.valid?
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
def perform
|
|
39
|
+
if group_summary_without_destination?
|
|
40
|
+
puts Gitlab::Triage::UI.warn("Issue was not created: No summary destination specified when source is 'groups'.")
|
|
41
|
+
return
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
policy.summary = network.post_api(post_issue_url, post_issue_body)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def issue
|
|
48
|
+
@issue ||= policy.build_summary
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def destination
|
|
52
|
+
issue.destination || network.options.source_id
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def group_summary_without_destination?
|
|
56
|
+
network.options.source == :groups && !issue.destination
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def post_issue_url
|
|
60
|
+
# POST /projects/:id/issues
|
|
61
|
+
# https://docs.gitlab.com/ee/api/issues.html#new-issue
|
|
62
|
+
post_url = UrlBuilders::UrlBuilder.new(
|
|
63
|
+
network_options: network.options,
|
|
64
|
+
source_id: destination,
|
|
65
|
+
resource_type: 'issues'
|
|
66
|
+
).build
|
|
67
|
+
|
|
68
|
+
puts Gitlab::Triage::UI.debug "post_issue_url: #{post_url}" if network.options.debug
|
|
69
|
+
|
|
70
|
+
post_url
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def post_issue_body
|
|
74
|
+
{
|
|
75
|
+
title: issue.title,
|
|
76
|
+
description: issue.description
|
|
77
|
+
}
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
require_relative 'action/summarize'
|
|
2
|
+
require_relative 'action/comment'
|
|
3
|
+
require_relative 'action/comment_on_summary'
|
|
4
|
+
require_relative 'action/issue'
|
|
5
|
+
require_relative 'action/delete'
|
|
6
|
+
|
|
7
|
+
module Gitlab
|
|
8
|
+
module Triage
|
|
9
|
+
module Action
|
|
10
|
+
def self.process(policy:, **args)
|
|
11
|
+
policy.validate!
|
|
12
|
+
|
|
13
|
+
[
|
|
14
|
+
[Summarize, policy.summarize?],
|
|
15
|
+
[Comment, policy.comment?],
|
|
16
|
+
[CommentOnSummary, policy.comment_on_summary?],
|
|
17
|
+
[Issue, policy.issue?],
|
|
18
|
+
[Delete, policy.delete?]
|
|
19
|
+
].each do |action, active|
|
|
20
|
+
act(action: action, policy: policy, **args) if active
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def self.act(action:, dry:, **args)
|
|
25
|
+
klass =
|
|
26
|
+
if dry
|
|
27
|
+
action.const_get(:Dry)
|
|
28
|
+
else
|
|
29
|
+
action
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
klass.new(**args).act
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module Gitlab
|
|
2
|
+
module Triage
|
|
3
|
+
module APIQueryBuilders
|
|
4
|
+
class BaseQueryParamBuilder
|
|
5
|
+
attr_reader :param_name, :param_contents, :allowed_values
|
|
6
|
+
|
|
7
|
+
def initialize(param_name, param_contents, allowed_values: nil)
|
|
8
|
+
@param_name = param_name
|
|
9
|
+
@param_contents = param_contents
|
|
10
|
+
@allowed_values = allowed_values
|
|
11
|
+
|
|
12
|
+
validate_allowed_values! if allowed_values
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def build_param
|
|
16
|
+
"&#{param_name}=#{param_content.strip}"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
def validate_allowed_values!
|
|
22
|
+
ParamsValidator.new([{ name: param_name, type: String, values: allowed_values }], { param_name => param_contents }).validate!
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
require_relative '../param_builders/date_param_builder'
|
|
2
|
+
require_relative 'base_query_param_builder'
|
|
3
|
+
|
|
4
|
+
module Gitlab
|
|
5
|
+
module Triage
|
|
6
|
+
module APIQueryBuilders
|
|
7
|
+
class DateQueryParamBuilder < BaseQueryParamBuilder
|
|
8
|
+
ATTRIBUTES = %w[updated_at created_at].freeze
|
|
9
|
+
|
|
10
|
+
def self.applicable?(condition)
|
|
11
|
+
ATTRIBUTES.include?(condition[:attribute].to_s) &&
|
|
12
|
+
condition[:filter_in_ruby] != true
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def initialize(condition_hash)
|
|
16
|
+
date_param_builder = ParamBuilders::DateParamBuilder.new(ATTRIBUTES, condition_hash)
|
|
17
|
+
|
|
18
|
+
super(build_param_name(condition_hash), date_param_builder.param_content)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def param_content
|
|
22
|
+
param_contents
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
def build_param_name(condition_hash)
|
|
28
|
+
prefix = condition_hash[:attribute].to_s.sub(/_at\z/, '')
|
|
29
|
+
suffix =
|
|
30
|
+
case condition_hash[:condition].to_sym
|
|
31
|
+
when :older_than
|
|
32
|
+
'before'
|
|
33
|
+
when :newer_than
|
|
34
|
+
'after'
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
"#{prefix}_#{suffix}"
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
require_relative 'base_query_param_builder'
|
|
2
|
+
|
|
3
|
+
module Gitlab
|
|
4
|
+
module Triage
|
|
5
|
+
module APIQueryBuilders
|
|
6
|
+
class MultiQueryParamBuilder < BaseQueryParamBuilder
|
|
7
|
+
attr_reader :separator
|
|
8
|
+
|
|
9
|
+
def initialize(param_name, param_contents, separator, allowed_values: nil)
|
|
10
|
+
@separator = separator
|
|
11
|
+
super(param_name, Array(param_contents), allowed_values: allowed_values)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def param_content
|
|
15
|
+
param_contents.map(&:strip).join(separator)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def validate_allowed_values!
|
|
21
|
+
param_contents.each do |param|
|
|
22
|
+
ParamsValidator.new([{ name: param_name, type: String, values: allowed_values }], { param_name => param }).validate!
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
module Gitlab
|
|
2
|
+
module Triage
|
|
3
|
+
module CommandBuilders
|
|
4
|
+
class BaseCommandBuilder
|
|
5
|
+
def initialize(items, resource: nil, network: nil)
|
|
6
|
+
@items = Array.wrap(items)
|
|
7
|
+
@items.delete('')
|
|
8
|
+
@resource = resource&.with_indifferent_access
|
|
9
|
+
@network = network
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def build_command
|
|
13
|
+
if items.any?
|
|
14
|
+
[slash_command_string, content_string].compact.join(separator)
|
|
15
|
+
else
|
|
16
|
+
""
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
attr_reader :items, :resource, :network
|
|
23
|
+
|
|
24
|
+
def separator
|
|
25
|
+
' '
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def slash_command_string
|
|
29
|
+
nil
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def content_string
|
|
33
|
+
items.map do |item|
|
|
34
|
+
format_item(item)
|
|
35
|
+
end.join(separator)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
require_relative 'base_command_builder'
|
|
2
|
+
|
|
3
|
+
module Gitlab
|
|
4
|
+
module Triage
|
|
5
|
+
module CommandBuilders
|
|
6
|
+
class CcCommandBuilder < BaseCommandBuilder
|
|
7
|
+
private
|
|
8
|
+
|
|
9
|
+
def slash_command_string
|
|
10
|
+
"/cc"
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def format_item(item)
|
|
14
|
+
"@#{item}"
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|