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.
Files changed (108) hide show
  1. checksums.yaml +7 -0
  2. data/.codeclimate.yml +19 -0
  3. data/.gitignore +15 -0
  4. data/.gitlab/CODEOWNERS +2 -0
  5. data/.gitlab/changelog_config.yml +13 -0
  6. data/.gitlab/issue_templates/Default.md +13 -0
  7. data/.gitlab/merge_request_templates/Default.md +11 -0
  8. data/.gitlab/merge_request_templates/Release.md +13 -0
  9. data/.gitlab-ci.yml +146 -0
  10. data/.rubocop.yml +21 -0
  11. data/.rubocop_todo.yml +145 -0
  12. data/.ruby-version +1 -0
  13. data/.tool-versions +1 -0
  14. data/.yardopts +4 -0
  15. data/CONTRIBUTING.md +31 -0
  16. data/Dangerfile +5 -0
  17. data/Gemfile +15 -0
  18. data/Guardfile +70 -0
  19. data/LICENSE.md +25 -0
  20. data/README.md +1480 -0
  21. data/Rakefile +6 -0
  22. data/bin/gitlab-triage +19 -0
  23. data/gitlab-triage.gemspec +41 -0
  24. data/lib/gitlab/triage/action/base.rb +14 -0
  25. data/lib/gitlab/triage/action/comment.rb +104 -0
  26. data/lib/gitlab/triage/action/comment_on_summary.rb +83 -0
  27. data/lib/gitlab/triage/action/delete.rb +56 -0
  28. data/lib/gitlab/triage/action/issue.rb +64 -0
  29. data/lib/gitlab/triage/action/summarize.rb +82 -0
  30. data/lib/gitlab/triage/action.rb +36 -0
  31. data/lib/gitlab/triage/api_query_builders/base_query_param_builder.rb +27 -0
  32. data/lib/gitlab/triage/api_query_builders/date_query_param_builder.rb +42 -0
  33. data/lib/gitlab/triage/api_query_builders/multi_query_param_builder.rb +28 -0
  34. data/lib/gitlab/triage/api_query_builders/single_query_param_builder.rb +13 -0
  35. data/lib/gitlab/triage/command_builders/base_command_builder.rb +40 -0
  36. data/lib/gitlab/triage/command_builders/cc_command_builder.rb +19 -0
  37. data/lib/gitlab/triage/command_builders/comment_command_builder.rb +19 -0
  38. data/lib/gitlab/triage/command_builders/label_command_builder.rb +40 -0
  39. data/lib/gitlab/triage/command_builders/move_command_builder.rb +19 -0
  40. data/lib/gitlab/triage/command_builders/remove_label_command_builder.rb +15 -0
  41. data/lib/gitlab/triage/command_builders/status_command_builder.rb +23 -0
  42. data/lib/gitlab/triage/command_builders/text_content_builder.rb +138 -0
  43. data/lib/gitlab/triage/engine.rb +635 -0
  44. data/lib/gitlab/triage/entity_builders/issue_builder.rb +54 -0
  45. data/lib/gitlab/triage/entity_builders/summary_builder.rb +82 -0
  46. data/lib/gitlab/triage/errors/network.rb +11 -0
  47. data/lib/gitlab/triage/errors.rb +1 -0
  48. data/lib/gitlab/triage/expand_condition/expansion.rb +203 -0
  49. data/lib/gitlab/triage/expand_condition/list.rb +25 -0
  50. data/lib/gitlab/triage/expand_condition/sequence.rb +25 -0
  51. data/lib/gitlab/triage/expand_condition.rb +23 -0
  52. data/lib/gitlab/triage/filters/assignee_member_conditions_filter.rb +13 -0
  53. data/lib/gitlab/triage/filters/author_member_conditions_filter.rb +13 -0
  54. data/lib/gitlab/triage/filters/base_conditions_filter.rb +58 -0
  55. data/lib/gitlab/triage/filters/branch_date_filter.rb +73 -0
  56. data/lib/gitlab/triage/filters/branch_protected_filter.rb +26 -0
  57. data/lib/gitlab/triage/filters/discussions_conditions_filter.rb +58 -0
  58. data/lib/gitlab/triage/filters/issue_date_conditions_filter.rb +78 -0
  59. data/lib/gitlab/triage/filters/member_conditions_filter.rb +84 -0
  60. data/lib/gitlab/triage/filters/merge_request_date_conditions_filter.rb +13 -0
  61. data/lib/gitlab/triage/filters/name_conditions_filter.rb +26 -0
  62. data/lib/gitlab/triage/filters/no_additional_labels_conditions_filter.rb +30 -0
  63. data/lib/gitlab/triage/filters/ruby_conditions_filter.rb +33 -0
  64. data/lib/gitlab/triage/filters/votes_conditions_filter.rb +54 -0
  65. data/lib/gitlab/triage/graphql_network.rb +81 -0
  66. data/lib/gitlab/triage/graphql_queries/query_builder.rb +158 -0
  67. data/lib/gitlab/triage/graphql_queries/query_param_builders/base_param_builder.rb +30 -0
  68. data/lib/gitlab/triage/graphql_queries/query_param_builders/date_param_builder.rb +35 -0
  69. data/lib/gitlab/triage/graphql_queries/query_param_builders/labels_param_builder.rb +18 -0
  70. data/lib/gitlab/triage/limiters/base_limiter.rb +35 -0
  71. data/lib/gitlab/triage/limiters/date_field_limiter.rb +45 -0
  72. data/lib/gitlab/triage/network.rb +39 -0
  73. data/lib/gitlab/triage/network_adapters/base_adapter.rb +17 -0
  74. data/lib/gitlab/triage/network_adapters/graphql_adapter.rb +92 -0
  75. data/lib/gitlab/triage/network_adapters/httparty_adapter.rb +116 -0
  76. data/lib/gitlab/triage/network_adapters/test_adapter.rb +39 -0
  77. data/lib/gitlab/triage/option_parser.rb +105 -0
  78. data/lib/gitlab/triage/options.rb +30 -0
  79. data/lib/gitlab/triage/param_builders/date_param_builder.rb +64 -0
  80. data/lib/gitlab/triage/policies/base_policy.rb +80 -0
  81. data/lib/gitlab/triage/policies/rule_policy.rb +36 -0
  82. data/lib/gitlab/triage/policies/summary_policy.rb +29 -0
  83. data/lib/gitlab/triage/policies_resources/rule_resources.rb +11 -0
  84. data/lib/gitlab/triage/policies_resources/summary_resources.rb +11 -0
  85. data/lib/gitlab/triage/resource/base.rb +102 -0
  86. data/lib/gitlab/triage/resource/branch.rb +13 -0
  87. data/lib/gitlab/triage/resource/context.rb +47 -0
  88. data/lib/gitlab/triage/resource/epic.rb +20 -0
  89. data/lib/gitlab/triage/resource/instance_version.rb +35 -0
  90. data/lib/gitlab/triage/resource/issue.rb +52 -0
  91. data/lib/gitlab/triage/resource/label.rb +56 -0
  92. data/lib/gitlab/triage/resource/label_event.rb +48 -0
  93. data/lib/gitlab/triage/resource/linked_issue.rb +15 -0
  94. data/lib/gitlab/triage/resource/merge_request.rb +23 -0
  95. data/lib/gitlab/triage/resource/milestone.rb +98 -0
  96. data/lib/gitlab/triage/resource/shared/issuable.rb +119 -0
  97. data/lib/gitlab/triage/rest_api_network.rb +125 -0
  98. data/lib/gitlab/triage/retryable.rb +33 -0
  99. data/lib/gitlab/triage/ui.rb +23 -0
  100. data/lib/gitlab/triage/url_builders/url_builder.rb +54 -0
  101. data/lib/gitlab/triage/utils.rb +13 -0
  102. data/lib/gitlab/triage/validators/limiter_validator.rb +21 -0
  103. data/lib/gitlab/triage/validators/params_validator.rb +43 -0
  104. data/lib/gitlab/triage/version.rb +7 -0
  105. data/lib/gitlab/triage.rb +6 -0
  106. data/support/.gitlab-ci.example.yml +22 -0
  107. data/support/.triage-policies.example.yml +51 -0
  108. 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,15 @@
1
+ require_relative 'base_command_builder'
2
+
3
+ module Gitlab
4
+ module Triage
5
+ module CommandBuilders
6
+ class RemoveLabelCommandBuilder < LabelCommandBuilder
7
+ private
8
+
9
+ def slash_command_string
10
+ '/unlabel'
11
+ end
12
+ end
13
+ end
14
+ end
15
+ 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