plan_my_stuff 0.3.0 → 0.5.0
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 +4 -4
- data/CHANGELOG.md +22 -0
- data/README.md +569 -38
- data/app/controllers/plan_my_stuff/comments_controller.rb +5 -1
- data/app/controllers/plan_my_stuff/issues/approvals_controller.rb +102 -0
- data/app/controllers/plan_my_stuff/issues/closures_controller.rb +37 -0
- data/app/controllers/plan_my_stuff/issues/links_controller.rb +127 -0
- data/app/controllers/plan_my_stuff/issues/takes_controller.rb +88 -0
- data/app/controllers/plan_my_stuff/issues/viewers_controller.rb +48 -0
- data/app/controllers/plan_my_stuff/issues/waitings_controller.rb +47 -0
- data/app/controllers/plan_my_stuff/issues_controller.rb +22 -55
- data/app/controllers/plan_my_stuff/labels_controller.rb +4 -4
- data/app/controllers/plan_my_stuff/project_items/assignments_controller.rb +75 -0
- data/app/controllers/plan_my_stuff/project_items/statuses_controller.rb +40 -0
- data/app/controllers/plan_my_stuff/project_items_controller.rb +0 -75
- data/app/controllers/plan_my_stuff/projects_controller.rb +11 -1
- data/app/controllers/plan_my_stuff/testing_project_items/results_controller.rb +54 -0
- data/app/controllers/plan_my_stuff/testing_project_items_controller.rb +39 -0
- data/app/controllers/plan_my_stuff/testing_projects_controller.rb +93 -0
- data/app/controllers/plan_my_stuff/webhooks/aws_controller.rb +148 -0
- data/app/controllers/plan_my_stuff/webhooks/github_controller.rb +284 -0
- data/app/jobs/plan_my_stuff/application_job.rb +9 -0
- data/app/jobs/plan_my_stuff/reminders_sweep_job.rb +81 -0
- data/app/views/plan_my_stuff/comments/partials/_form.html.erb +7 -0
- data/app/views/plan_my_stuff/issues/partials/_approvals.html.erb +87 -0
- data/app/views/plan_my_stuff/issues/partials/_labels.html.erb +2 -2
- data/app/views/plan_my_stuff/issues/partials/_links.html.erb +70 -0
- data/app/views/plan_my_stuff/issues/partials/_viewers.html.erb +2 -2
- data/app/views/plan_my_stuff/issues/show.html.erb +46 -3
- data/app/views/plan_my_stuff/projects/index.html.erb +15 -1
- data/app/views/plan_my_stuff/projects/show.html.erb +10 -5
- data/app/views/plan_my_stuff/testing_project_items/new.html.erb +12 -0
- data/app/views/plan_my_stuff/testing_project_items/results/new.html.erb +22 -0
- data/app/views/plan_my_stuff/testing_projects/edit.html.erb +7 -0
- data/app/views/plan_my_stuff/testing_projects/new.html.erb +7 -0
- data/app/views/plan_my_stuff/testing_projects/partials/_form.html.erb +39 -0
- data/app/views/plan_my_stuff/testing_projects/partials/_item.html.erb +51 -0
- data/app/views/plan_my_stuff/testing_projects/partials/items/_form.html.erb +35 -0
- data/app/views/plan_my_stuff/testing_projects/show.html.erb +65 -0
- data/config/routes.rb +38 -15
- data/lib/generators/plan_my_stuff/install/templates/initializer.rb +172 -5
- data/lib/plan_my_stuff/application_record.rb +121 -0
- data/lib/plan_my_stuff/approval.rb +80 -0
- data/lib/plan_my_stuff/archive/sweep.rb +85 -0
- data/lib/plan_my_stuff/archive.rb +14 -0
- data/lib/plan_my_stuff/aws_sns_simulator.rb +110 -0
- data/lib/plan_my_stuff/base_project.rb +661 -0
- data/lib/plan_my_stuff/base_project_item.rb +562 -0
- data/lib/plan_my_stuff/base_project_metadata.rb +16 -0
- data/lib/plan_my_stuff/cache.rb +197 -0
- data/lib/plan_my_stuff/client.rb +7 -0
- data/lib/plan_my_stuff/comment.rb +171 -50
- data/lib/plan_my_stuff/configuration.rb +210 -10
- data/lib/plan_my_stuff/custom_fields.rb +31 -17
- data/lib/plan_my_stuff/engine.rb +0 -4
- data/lib/plan_my_stuff/errors.rb +49 -0
- data/lib/plan_my_stuff/graphql/queries.rb +392 -0
- data/lib/plan_my_stuff/issue.rb +1476 -175
- data/lib/plan_my_stuff/issue_metadata.rb +122 -0
- data/lib/plan_my_stuff/label.rb +82 -11
- data/lib/plan_my_stuff/link.rb +144 -0
- data/lib/plan_my_stuff/notifications.rb +142 -0
- data/lib/plan_my_stuff/pipeline/issue_linker.rb +62 -0
- data/lib/plan_my_stuff/pipeline/status.rb +44 -0
- data/lib/plan_my_stuff/pipeline.rb +293 -0
- data/lib/plan_my_stuff/project.rb +30 -693
- data/lib/plan_my_stuff/project_item.rb +3 -417
- data/lib/plan_my_stuff/project_item_metadata.rb +55 -0
- data/lib/plan_my_stuff/project_metadata.rb +9 -3
- data/lib/plan_my_stuff/reminders/closer.rb +70 -0
- data/lib/plan_my_stuff/reminders/fire.rb +129 -0
- data/lib/plan_my_stuff/reminders/sweep.rb +54 -0
- data/lib/plan_my_stuff/reminders.rb +16 -0
- data/lib/plan_my_stuff/test_helpers.rb +260 -15
- data/lib/plan_my_stuff/testing_project.rb +291 -0
- data/lib/plan_my_stuff/testing_project_item.rb +216 -0
- data/lib/plan_my_stuff/testing_project_metadata.rb +94 -0
- data/lib/plan_my_stuff/user_resolver.rb +8 -3
- data/lib/plan_my_stuff/version.rb +1 -1
- data/lib/plan_my_stuff/webhook_replayer.rb +280 -0
- data/lib/plan_my_stuff.rb +15 -0
- data/lib/tasks/plan_my_stuff.rake +179 -0
- metadata +77 -3
|
@@ -2,6 +2,33 @@
|
|
|
2
2
|
|
|
3
3
|
module PlanMyStuff
|
|
4
4
|
class Configuration
|
|
5
|
+
# Default controller for each controllable route group. Consuming apps
|
|
6
|
+
# override by assigning values into +controllers+; lookups go through
|
|
7
|
+
# +controller_for+ which falls back to this table.
|
|
8
|
+
#
|
|
9
|
+
# @return [Hash{Symbol => String}]
|
|
10
|
+
#
|
|
11
|
+
DEFAULT_CONTROLLERS = {
|
|
12
|
+
'issues': 'plan_my_stuff/issues',
|
|
13
|
+
'comments': 'plan_my_stuff/comments',
|
|
14
|
+
'labels': 'plan_my_stuff/labels',
|
|
15
|
+
'projects': 'plan_my_stuff/projects',
|
|
16
|
+
'project_items': 'plan_my_stuff/project_items',
|
|
17
|
+
'testing_projects': 'plan_my_stuff/testing_projects',
|
|
18
|
+
'testing_project_items': 'plan_my_stuff/testing_project_items',
|
|
19
|
+
'issues/closures': 'plan_my_stuff/issues/closures',
|
|
20
|
+
'issues/viewers': 'plan_my_stuff/issues/viewers',
|
|
21
|
+
'issues/takes': 'plan_my_stuff/issues/takes',
|
|
22
|
+
'issues/waitings': 'plan_my_stuff/issues/waitings',
|
|
23
|
+
'issues/links': 'plan_my_stuff/issues/links',
|
|
24
|
+
'issues/approvals': 'plan_my_stuff/issues/approvals',
|
|
25
|
+
'project_items/statuses': 'plan_my_stuff/project_items/statuses',
|
|
26
|
+
'project_items/assignments': 'plan_my_stuff/project_items/assignments',
|
|
27
|
+
'testing_project_items/results': 'plan_my_stuff/testing_project_items/results',
|
|
28
|
+
'webhooks/github': 'plan_my_stuff/webhooks/github',
|
|
29
|
+
'webhooks/aws': 'plan_my_stuff/webhooks/aws',
|
|
30
|
+
}.freeze
|
|
31
|
+
|
|
5
32
|
# @return [String] GitHub PAT with repo and project scopes. Required.
|
|
6
33
|
attr_accessor :access_token
|
|
7
34
|
|
|
@@ -14,6 +41,12 @@ module PlanMyStuff
|
|
|
14
41
|
# @return [Integer, nil] default GitHub Projects V2 number for add_to_project calls
|
|
15
42
|
attr_accessor :default_project_number
|
|
16
43
|
|
|
44
|
+
# @return [Integer, nil] GitHub Projects V2 number of the template project to clone
|
|
45
|
+
# when creating new TestingProjects. When set, TestingProject.create! copies the
|
|
46
|
+
# template (preserving its fields and board layout) instead of bootstrapping fields
|
|
47
|
+
# from scratch. Leave nil to use the default bootstrap-fields path.
|
|
48
|
+
attr_accessor :testing_template_project_number
|
|
49
|
+
|
|
17
50
|
# @return [String] consuming app's user model class name, constantized for lookups
|
|
18
51
|
attr_accessor :user_class
|
|
19
52
|
|
|
@@ -61,14 +94,14 @@ module PlanMyStuff
|
|
|
61
94
|
#
|
|
62
95
|
attr_accessor :job_classes
|
|
63
96
|
|
|
64
|
-
#
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
#
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
#
|
|
71
|
-
attr_accessor :
|
|
97
|
+
# Fallback actor for notification events when a caller does not pass +user:+.
|
|
98
|
+
# Set to a proc/lambda that returns the current request user.
|
|
99
|
+
#
|
|
100
|
+
# Example: +config.current_user = -> { Current.user }+
|
|
101
|
+
#
|
|
102
|
+
# @return [Proc, nil]
|
|
103
|
+
#
|
|
104
|
+
attr_accessor :current_user
|
|
72
105
|
|
|
73
106
|
# Shared field definitions stored in issue/comment metadata.
|
|
74
107
|
# Keys are field names, values are hashes with :type and :required.
|
|
@@ -99,6 +132,13 @@ module PlanMyStuff
|
|
|
99
132
|
#
|
|
100
133
|
attr_accessor :project_custom_fields
|
|
101
134
|
|
|
135
|
+
# Testing-project-only field definitions, deep-merged on top of shared custom_fields.
|
|
136
|
+
# Context-specific config wins on key conflicts.
|
|
137
|
+
#
|
|
138
|
+
# @return [Hash{Symbol => Hash}]
|
|
139
|
+
#
|
|
140
|
+
attr_accessor :testing_custom_fields
|
|
141
|
+
|
|
102
142
|
# @return [String, nil] URL prefix for building user-facing ticket URLs in the consuming app
|
|
103
143
|
attr_accessor :issues_url_prefix
|
|
104
144
|
|
|
@@ -114,8 +154,14 @@ module PlanMyStuff
|
|
|
114
154
|
# @return [String, nil] HMAC secret for GitHub webhook signature verification (required when webhooks mounted)
|
|
115
155
|
attr_accessor :webhook_secret
|
|
116
156
|
|
|
117
|
-
# @return [String, nil]
|
|
118
|
-
attr_accessor :
|
|
157
|
+
# @return [String, nil] expected SNS topic ARN for AWS webhook validation
|
|
158
|
+
attr_accessor :sns_topic_arn
|
|
159
|
+
|
|
160
|
+
# @return [String, nil] suffix matched against ECS event resource ARNs (e.g. 'rawr-production-2-web')
|
|
161
|
+
attr_accessor :aws_service_identifier
|
|
162
|
+
|
|
163
|
+
# @return [String, nil] commit hash of the deploying build, prefix-matched against issue metadata commit_sha
|
|
164
|
+
attr_accessor :production_commit_sha
|
|
119
165
|
|
|
120
166
|
# Canonical status name to display alias map. Allows consuming apps to rename
|
|
121
167
|
# pipeline statuses (e.g. "Submitted" to "Triaged").
|
|
@@ -130,6 +176,17 @@ module PlanMyStuff
|
|
|
130
176
|
# @return [String] branch name that triggers deployment when a PR merges
|
|
131
177
|
attr_accessor :production_branch
|
|
132
178
|
|
|
179
|
+
# Hash mapping consuming-app user id to GitHub login. Used by the
|
|
180
|
+
# "Take" UI flow to assign the GitHub user when a support user claims
|
|
181
|
+
# an issue. Keys are whatever +config.user_id_method+ returns on the
|
|
182
|
+
# current user.
|
|
183
|
+
#
|
|
184
|
+
# Example: +config.github_login_for = { 1 => 'some_username', 2 => 'octocat' }+
|
|
185
|
+
#
|
|
186
|
+
# @return [Hash{Object => String}]
|
|
187
|
+
#
|
|
188
|
+
attr_accessor :github_login_for
|
|
189
|
+
|
|
133
190
|
# Per-group route mounting toggles. Keys: :webhooks, :issues, :projects.
|
|
134
191
|
# Set a key to false to skip mounting that route group.
|
|
135
192
|
#
|
|
@@ -137,6 +194,112 @@ module PlanMyStuff
|
|
|
137
194
|
#
|
|
138
195
|
attr_accessor :mount_groups
|
|
139
196
|
|
|
197
|
+
# Per-route controller overrides. Keys are the controllable route symbols
|
|
198
|
+
# defined in +DEFAULT_CONTROLLERS+; values are fully-qualified controller
|
|
199
|
+
# paths (e.g. +'my_app/issues'+). Unset keys fall back to the gem default.
|
|
200
|
+
# Consuming apps typically subclass the gem controller to add before_actions
|
|
201
|
+
# or tweak responses, then swap their subclass in here.
|
|
202
|
+
#
|
|
203
|
+
# @return [Hash{Symbol => String}]
|
|
204
|
+
#
|
|
205
|
+
attr_accessor :controllers
|
|
206
|
+
|
|
207
|
+
# Whether to use Rails.cache for ETag-based HTTP caching of GitHub reads.
|
|
208
|
+
# Defaults to true; set to false to bypass the cache entirely.
|
|
209
|
+
#
|
|
210
|
+
# @return [Boolean]
|
|
211
|
+
#
|
|
212
|
+
attr_accessor :cache_enabled
|
|
213
|
+
|
|
214
|
+
# Opaque app-supplied version string embedded in every PMS cache key.
|
|
215
|
+
# Bumping this string invalidates all cached entries from the consuming
|
|
216
|
+
# app's side (e.g. after a deploy or schema change). Defaults to nil.
|
|
217
|
+
#
|
|
218
|
+
# @return [String, nil]
|
|
219
|
+
#
|
|
220
|
+
attr_accessor :cache_version
|
|
221
|
+
|
|
222
|
+
# Whether the reminders sweep performs any work. Defaults to +true+.
|
|
223
|
+
# Set to +false+ in apps that don't want follow-up reminders or inactivity
|
|
224
|
+
# auto-close.
|
|
225
|
+
#
|
|
226
|
+
# @return [Boolean]
|
|
227
|
+
#
|
|
228
|
+
attr_accessor :reminders_enabled
|
|
229
|
+
|
|
230
|
+
# Days-since-waiting at which reminder events fire. Per-issue override
|
|
231
|
+
# via +metadata.reminder_days+.
|
|
232
|
+
#
|
|
233
|
+
# @return [Array<Integer>]
|
|
234
|
+
#
|
|
235
|
+
attr_accessor :reminder_days
|
|
236
|
+
|
|
237
|
+
# Days of inactivity after which the sweep auto-closes a waiting issue.
|
|
238
|
+
#
|
|
239
|
+
# @return [Integer]
|
|
240
|
+
#
|
|
241
|
+
attr_accessor :inactivity_close_days
|
|
242
|
+
|
|
243
|
+
# Label name used to flag issues waiting on an end-user reply.
|
|
244
|
+
#
|
|
245
|
+
# @return [String]
|
|
246
|
+
#
|
|
247
|
+
attr_accessor :waiting_on_user_label
|
|
248
|
+
|
|
249
|
+
# Label name used to flag issues waiting on pending approvals.
|
|
250
|
+
#
|
|
251
|
+
# @return [String]
|
|
252
|
+
#
|
|
253
|
+
attr_accessor :waiting_on_approval_label
|
|
254
|
+
|
|
255
|
+
# Label name applied to issues auto-closed by the inactivity sweep.
|
|
256
|
+
# Removed when an issue is auto-reopened via a user reply.
|
|
257
|
+
#
|
|
258
|
+
# @return [String]
|
|
259
|
+
#
|
|
260
|
+
attr_accessor :user_inactive_label
|
|
261
|
+
|
|
262
|
+
# Whether the archive sweep performs any work. Defaults to +true+.
|
|
263
|
+
# Set to +false+ in apps that don't want auto-archiving of aged-closed
|
|
264
|
+
# issues.
|
|
265
|
+
#
|
|
266
|
+
# @return [Boolean]
|
|
267
|
+
#
|
|
268
|
+
attr_accessor :archiving_enabled
|
|
269
|
+
|
|
270
|
+
# Days after +closed_at+ at which a non-inactive-closed issue becomes an
|
|
271
|
+
# archive candidate.
|
|
272
|
+
#
|
|
273
|
+
# @return [Integer]
|
|
274
|
+
#
|
|
275
|
+
attr_accessor :archive_closed_after_days
|
|
276
|
+
|
|
277
|
+
# Label name added to archived issues. Also used by the sweep as a
|
|
278
|
+
# skip marker to avoid re-archiving the same issue.
|
|
279
|
+
#
|
|
280
|
+
# @return [String]
|
|
281
|
+
#
|
|
282
|
+
attr_accessor :archived_label
|
|
283
|
+
|
|
284
|
+
# Whether to process incoming AWS webhook events. Defaults to +Rails.env.production?+.
|
|
285
|
+
#
|
|
286
|
+
# @return [Boolean]
|
|
287
|
+
#
|
|
288
|
+
attr_accessor :process_aws_webhooks
|
|
289
|
+
|
|
290
|
+
# Class instantiated per request for SNS signature verification.
|
|
291
|
+
# Must respond to +authenticate!(raw_body)+.
|
|
292
|
+
#
|
|
293
|
+
# @return [Class]
|
|
294
|
+
#
|
|
295
|
+
attr_accessor :sns_verifier_class
|
|
296
|
+
|
|
297
|
+
# Exception class rescued during SNS signature verification.
|
|
298
|
+
#
|
|
299
|
+
# @return [Class]
|
|
300
|
+
#
|
|
301
|
+
attr_accessor :sns_verifier_error
|
|
302
|
+
|
|
140
303
|
# Named repo configs. Set via config.repos[:element] = 'BrandsInsurance/Element'.
|
|
141
304
|
#
|
|
142
305
|
# @return [Hash{Symbol => String}]
|
|
@@ -157,11 +320,30 @@ module PlanMyStuff
|
|
|
157
320
|
@issue_custom_fields = {}
|
|
158
321
|
@comment_custom_fields = {}
|
|
159
322
|
@project_custom_fields = {}
|
|
323
|
+
@testing_custom_fields = {}
|
|
160
324
|
@pipeline_enabled = true
|
|
161
325
|
@pipeline_statuses = {}
|
|
162
326
|
@main_branch = 'main'
|
|
163
327
|
@production_branch = 'production'
|
|
164
328
|
@mount_groups = { webhooks: true, issues: true, projects: true }
|
|
329
|
+
@controllers = {}
|
|
330
|
+
@cache_enabled = true
|
|
331
|
+
@github_login_for = {}
|
|
332
|
+
@reminders_enabled = true
|
|
333
|
+
@reminder_days = [1, 3, 7, 10, 14, 18].freeze
|
|
334
|
+
@inactivity_close_days = 30
|
|
335
|
+
@waiting_on_user_label = 'waiting-on-user'
|
|
336
|
+
@waiting_on_approval_label = 'waiting-on-approval'
|
|
337
|
+
@user_inactive_label = 'user-inactive'
|
|
338
|
+
@archiving_enabled = true
|
|
339
|
+
@archive_closed_after_days = 90
|
|
340
|
+
@archived_label = 'archived'
|
|
341
|
+
@process_aws_webhooks = Rails.env.production?
|
|
342
|
+
@sns_verifier_class = ::Aws::SNS::MessageVerifier if defined?(::Aws::SNS::MessageVerifier)
|
|
343
|
+
@sns_verifier_error =
|
|
344
|
+
if defined?(::Aws::SNS::MessageVerifier::VerificationError)
|
|
345
|
+
::Aws::SNS::MessageVerifier::VerificationError
|
|
346
|
+
end
|
|
165
347
|
end
|
|
166
348
|
|
|
167
349
|
# Sets the authentication block for engine controllers.
|
|
@@ -208,11 +390,29 @@ module PlanMyStuff
|
|
|
208
390
|
when :issue then issue_custom_fields
|
|
209
391
|
when :comment then comment_custom_fields
|
|
210
392
|
when :project then project_custom_fields
|
|
393
|
+
when :testing then testing_custom_fields
|
|
211
394
|
else {}
|
|
212
395
|
end
|
|
213
396
|
|
|
214
397
|
custom_fields.deep_merge(context_fields)
|
|
215
398
|
end
|
|
399
|
+
|
|
400
|
+
# Returns the controller path for the given route group, preferring a
|
|
401
|
+
# consuming-app override from +controllers+ and falling back to the gem
|
|
402
|
+
# default from +DEFAULT_CONTROLLERS+. The returned value always begins
|
|
403
|
+
# with +'/'+ so the isolated engine does not re-prefix it with
|
|
404
|
+
# +plan_my_stuff/+.
|
|
405
|
+
#
|
|
406
|
+
# @param key [Symbol]
|
|
407
|
+
#
|
|
408
|
+
# @raise [KeyError] if +key+ is not a controllable route group
|
|
409
|
+
#
|
|
410
|
+
# @return [String]
|
|
411
|
+
#
|
|
412
|
+
def controller_for(key)
|
|
413
|
+
path = controllers[key] || DEFAULT_CONTROLLERS.fetch(key)
|
|
414
|
+
path.start_with?('/') ? path : "/#{path}"
|
|
415
|
+
end
|
|
216
416
|
end
|
|
217
417
|
|
|
218
418
|
class ConfigurationError < StandardError
|
|
@@ -60,28 +60,42 @@ module PlanMyStuff
|
|
|
60
60
|
to_h.to_json(...)
|
|
61
61
|
end
|
|
62
62
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
63
|
+
# @param method_name [Symbol]
|
|
64
|
+
# @param include_private [Boolean]
|
|
65
|
+
#
|
|
66
|
+
# @return [Boolean]
|
|
67
|
+
#
|
|
68
|
+
def respond_to_missing?(method_name, include_private = false)
|
|
69
|
+
key = method_name.to_s.delete_suffix('=').to_sym
|
|
70
|
+
@schema.key?(key) || @data.key?(key) || super
|
|
71
|
+
end
|
|
69
72
|
|
|
70
|
-
|
|
71
|
-
|
|
73
|
+
# Dynamic reader/writer access to custom field values. Only resolves field
|
|
74
|
+
# names that appear in the schema or already have a value in @data; unknown
|
|
75
|
+
# names fall through to super (raising NoMethodError).
|
|
76
|
+
#
|
|
77
|
+
# @param method_name [Symbol]
|
|
78
|
+
# @param args [Array]
|
|
79
|
+
#
|
|
80
|
+
# @return [Object]
|
|
81
|
+
#
|
|
82
|
+
def method_missing(method_name, *args)
|
|
83
|
+
name = method_name.to_s
|
|
72
84
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
end
|
|
78
|
-
elsif @schema.key?(method_name) || @data.key?(method_name)
|
|
79
|
-
return @data[method_name]
|
|
85
|
+
if name.end_with?('=')
|
|
86
|
+
key = name.delete_suffix('=').to_sym
|
|
87
|
+
if @schema.key?(key) || @data.key?(key)
|
|
88
|
+
return @data[key] = args.first
|
|
80
89
|
end
|
|
81
|
-
|
|
82
|
-
|
|
90
|
+
elsif @schema.key?(method_name) || @data.key?(method_name)
|
|
91
|
+
return @data[method_name]
|
|
83
92
|
end
|
|
84
93
|
|
|
94
|
+
super
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
private
|
|
98
|
+
|
|
85
99
|
# @return [void]
|
|
86
100
|
def validate_custom_fields
|
|
87
101
|
validate_unknown_fields
|
data/lib/plan_my_stuff/engine.rb
CHANGED
data/lib/plan_my_stuff/errors.rb
CHANGED
|
@@ -66,6 +66,17 @@ module PlanMyStuff
|
|
|
66
66
|
end
|
|
67
67
|
end
|
|
68
68
|
|
|
69
|
+
# Raised when a webhook HMAC-SHA256 signature check fails
|
|
70
|
+
class WebhookSignatureError < Error
|
|
71
|
+
def initialize(message = 'Invalid webhook signature')
|
|
72
|
+
super
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Raised when a pipeline operation fails
|
|
77
|
+
class PipelineError < Error
|
|
78
|
+
end
|
|
79
|
+
|
|
69
80
|
# Raised when custom field validation fails (Phase 1)
|
|
70
81
|
class ValidationError < Error
|
|
71
82
|
# @return [String, nil]
|
|
@@ -84,4 +95,42 @@ module PlanMyStuff
|
|
|
84
95
|
super(message)
|
|
85
96
|
end
|
|
86
97
|
end
|
|
98
|
+
|
|
99
|
+
# Raised when a caller is not authorized to perform an action (e.g.
|
|
100
|
+
# a non-support user attempts to manage approvers on an issue).
|
|
101
|
+
class AuthorizationError < Error
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# Raised when an operation is attempted on an issue whose conversation
|
|
105
|
+
# is locked on GitHub (archived or manually locked).
|
|
106
|
+
class LockedIssueError < Error
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# Raised by +PlanMyStuff::Pipeline+ forward transitions when the linked
|
|
110
|
+
# +Issue+ has any pending manager approvals.
|
|
111
|
+
class PendingApprovalsError < ValidationError
|
|
112
|
+
# @return [PlanMyStuff::Issue, nil]
|
|
113
|
+
attr_reader :issue
|
|
114
|
+
|
|
115
|
+
# @return [Integer]
|
|
116
|
+
attr_reader :pending_count
|
|
117
|
+
|
|
118
|
+
# @param message [String, nil]
|
|
119
|
+
# @param issue [PlanMyStuff::Issue, nil]
|
|
120
|
+
# @param pending_count [Integer]
|
|
121
|
+
#
|
|
122
|
+
def initialize(message = nil, issue: nil, pending_count: 0)
|
|
123
|
+
@issue = issue
|
|
124
|
+
@pending_count = pending_count
|
|
125
|
+
super(message || default_message)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
private
|
|
129
|
+
|
|
130
|
+
# @return [String]
|
|
131
|
+
def default_message
|
|
132
|
+
"Issue ##{issue&.number} has #{pending_count} pending approval(s); " \
|
|
133
|
+
'cannot move forward through pipeline.'
|
|
134
|
+
end
|
|
135
|
+
end
|
|
87
136
|
end
|