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
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
require_relative 'base_command_builder'
|
|
2
|
+
|
|
3
|
+
module Gitlab
|
|
4
|
+
module Triage
|
|
5
|
+
module CommandBuilders
|
|
6
|
+
class CommentCommandBuilder < BaseCommandBuilder
|
|
7
|
+
private
|
|
8
|
+
|
|
9
|
+
def separator
|
|
10
|
+
"\n\n"
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def format_item(item)
|
|
14
|
+
item
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
require_relative 'base_command_builder'
|
|
2
|
+
|
|
3
|
+
module Gitlab
|
|
4
|
+
module Triage
|
|
5
|
+
module CommandBuilders
|
|
6
|
+
class LabelCommandBuilder < BaseCommandBuilder
|
|
7
|
+
def build_command
|
|
8
|
+
ensure_labels_exist!
|
|
9
|
+
|
|
10
|
+
super
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
private
|
|
14
|
+
|
|
15
|
+
def ensure_labels_exist!
|
|
16
|
+
items.each do |label|
|
|
17
|
+
source_id_key = resource.key?(:group_id) ? :group_id : :project_id
|
|
18
|
+
label_opts = {
|
|
19
|
+
source_id_key => resource[source_id_key],
|
|
20
|
+
name: label
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
unless Resource::Label.new(label_opts, network: network).exist?
|
|
24
|
+
raise Resource::Label::LabelDoesntExistError,
|
|
25
|
+
"Label `#{label}` doesn't exist!"
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def slash_command_string
|
|
31
|
+
"/label"
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def format_item(item)
|
|
35
|
+
"~\"#{item}\""
|
|
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 MoveCommandBuilder < BaseCommandBuilder
|
|
7
|
+
private
|
|
8
|
+
|
|
9
|
+
def slash_command_string
|
|
10
|
+
"/move"
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def format_item(item)
|
|
14
|
+
item
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
require_relative 'base_command_builder'
|
|
2
|
+
|
|
3
|
+
module Gitlab
|
|
4
|
+
module Triage
|
|
5
|
+
module CommandBuilders
|
|
6
|
+
class StatusCommandBuilder < BaseCommandBuilder
|
|
7
|
+
private
|
|
8
|
+
|
|
9
|
+
def separator
|
|
10
|
+
''
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def slash_command_string
|
|
14
|
+
"/"
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def format_item(item)
|
|
18
|
+
item
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'active_support/core_ext/array/wrap'
|
|
4
|
+
require 'cgi'
|
|
5
|
+
|
|
6
|
+
require_relative 'base_command_builder'
|
|
7
|
+
require_relative '../resource/context'
|
|
8
|
+
|
|
9
|
+
module Gitlab
|
|
10
|
+
module Triage
|
|
11
|
+
module CommandBuilders
|
|
12
|
+
class TextContentBuilder < BaseCommandBuilder
|
|
13
|
+
SUPPORTED_PLACEHOLDERS = {
|
|
14
|
+
created_at: "{{created_at}}",
|
|
15
|
+
updated_at: "{{updated_at}}",
|
|
16
|
+
closed_at: "{{closed_at}}",
|
|
17
|
+
merged_at: "{{merged_at}}",
|
|
18
|
+
state: "{{state}}",
|
|
19
|
+
author: "@{{author.username}}",
|
|
20
|
+
assignee: "@{{assignee.username}}",
|
|
21
|
+
assignees: "@{{assignees.username}}",
|
|
22
|
+
source_branch: "{{source_branch}}",
|
|
23
|
+
target_branch: "{{target_branch}}",
|
|
24
|
+
closed_by: "@{{closed_by.username}}",
|
|
25
|
+
merged_by: "@{{merged_by.username}}",
|
|
26
|
+
milestone: %(%"{{milestone.title}}"),
|
|
27
|
+
labels: %(~"{{labels}}"),
|
|
28
|
+
upvotes: "{{upvotes}}",
|
|
29
|
+
downvotes: "{{downvotes}}",
|
|
30
|
+
title: "{{title}}",
|
|
31
|
+
web_url: "{{web_url}}",
|
|
32
|
+
full_reference: "{{references.full}}",
|
|
33
|
+
type: "{{type}}",
|
|
34
|
+
items: "{{items}}",
|
|
35
|
+
name: "{{name}}"
|
|
36
|
+
}.freeze
|
|
37
|
+
PLACEHOLDER_REGEX = /{{([\w\.]+)}}/.freeze
|
|
38
|
+
|
|
39
|
+
def initialize(
|
|
40
|
+
items, resource: nil, network: nil, redact_confidentials: true)
|
|
41
|
+
super(items, resource: resource, network: network)
|
|
42
|
+
@redact_confidentials = redact_confidentials
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
private
|
|
46
|
+
|
|
47
|
+
def separator
|
|
48
|
+
"\n\n"
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def format_item(item)
|
|
52
|
+
return item unless resource
|
|
53
|
+
|
|
54
|
+
replace_placeholders(eval_interpolation(item))
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def eval_interpolation(item)
|
|
58
|
+
quoted_comment = "%Q{#{item}}"
|
|
59
|
+
|
|
60
|
+
Resource::Context.build(
|
|
61
|
+
resource,
|
|
62
|
+
network: network,
|
|
63
|
+
redact_confidentials: @redact_confidentials
|
|
64
|
+
).eval(quoted_comment)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def replace_placeholders(item)
|
|
68
|
+
SUPPORTED_PLACEHOLDERS.inject(item) do |comment, (placeholder, template)|
|
|
69
|
+
next comment unless comment.include?("{{#{placeholder}}}")
|
|
70
|
+
|
|
71
|
+
path = template[/.*#{PLACEHOLDER_REGEX}.*/, 1]
|
|
72
|
+
attributes = extract_attributes(path)
|
|
73
|
+
|
|
74
|
+
formatted_text = attributes.map do |attribute|
|
|
75
|
+
template.sub(PLACEHOLDER_REGEX, attribute.to_s)
|
|
76
|
+
end.join(', ')
|
|
77
|
+
|
|
78
|
+
escaped_text =
|
|
79
|
+
case placeholder
|
|
80
|
+
when :items
|
|
81
|
+
# We don't need to escape it because it's recursive,
|
|
82
|
+
# which the contents should all be escaped already.
|
|
83
|
+
# Or put it another way, items isn't an attribute
|
|
84
|
+
# retrieved externally. It's a generated value which
|
|
85
|
+
# should be safe to begin with. At some point we
|
|
86
|
+
# may want to make this more distinguishable,
|
|
87
|
+
# separating values from API and values generated.
|
|
88
|
+
formatted_text
|
|
89
|
+
else
|
|
90
|
+
CGI.escape_html(formatted_text)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
comment.gsub("{{#{placeholder}}}", escaped_text)
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def extract_attributes(path)
|
|
98
|
+
redact_attributes(path, resource_dig_and_map(path.split('.')))
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# If we don't have to map arrays, we can simply do:
|
|
102
|
+
#
|
|
103
|
+
# resource.dig(*indices)
|
|
104
|
+
#
|
|
105
|
+
# Thus this method name. The only array here is `assignees`
|
|
106
|
+
def resource_dig_and_map(indices)
|
|
107
|
+
attributes = indices.inject(resource) do |result, index|
|
|
108
|
+
break unless result
|
|
109
|
+
|
|
110
|
+
case result
|
|
111
|
+
when Array
|
|
112
|
+
result.flat_map { |sub_resource| sub_resource[index] }
|
|
113
|
+
else
|
|
114
|
+
result[index]
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
Array.wrap(attributes)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def redact_attributes(path, attributes)
|
|
122
|
+
return attributes unless redact_confidential_attributes?
|
|
123
|
+
|
|
124
|
+
case path
|
|
125
|
+
when 'web_url', 'items', 'type', 'references.full'
|
|
126
|
+
attributes # No need to redact them
|
|
127
|
+
else
|
|
128
|
+
[Resource::Base::CONFIDENTIAL_TEXT]
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def redact_confidential_attributes?
|
|
133
|
+
@redact_confidentials && resource[:confidential]
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|