plan_my_stuff 0.6.0 → 0.8.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.
Files changed (89) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +41 -1
  3. data/README.md +100 -103
  4. data/app/controllers/plan_my_stuff/application_controller.rb +22 -3
  5. data/app/controllers/plan_my_stuff/comments_controller.rb +14 -16
  6. data/app/controllers/plan_my_stuff/issues/approvals_controller.rb +23 -13
  7. data/app/controllers/plan_my_stuff/issues/closures_controller.rb +7 -5
  8. data/app/controllers/plan_my_stuff/issues/links_controller.rb +14 -18
  9. data/app/controllers/plan_my_stuff/issues/takes_controller.rb +99 -28
  10. data/app/controllers/plan_my_stuff/issues/viewers_controller.rb +13 -5
  11. data/app/controllers/plan_my_stuff/issues/waitings_controller.rb +7 -5
  12. data/app/controllers/plan_my_stuff/issues_controller.rb +24 -28
  13. data/app/controllers/plan_my_stuff/labels_controller.rb +21 -5
  14. data/app/controllers/plan_my_stuff/project_items/assignments_controller.rb +13 -6
  15. data/app/controllers/plan_my_stuff/project_items/statuses_controller.rb +5 -4
  16. data/app/controllers/plan_my_stuff/project_items_controller.rb +30 -5
  17. data/app/controllers/plan_my_stuff/projects_controller.rb +16 -16
  18. data/app/controllers/plan_my_stuff/testing_project_items/results_controller.rb +21 -11
  19. data/app/controllers/plan_my_stuff/testing_project_items_controller.rb +9 -4
  20. data/app/controllers/plan_my_stuff/testing_projects_controller.rb +30 -14
  21. data/app/controllers/plan_my_stuff/webhooks/aws_controller.rb +50 -17
  22. data/app/controllers/plan_my_stuff/webhooks/github_controller.rb +32 -49
  23. data/app/jobs/plan_my_stuff/application_job.rb +2 -3
  24. data/app/jobs/plan_my_stuff/reminders_sweep_job.rb +15 -22
  25. data/app/views/plan_my_stuff/comments/edit.html.erb +1 -3
  26. data/app/views/plan_my_stuff/comments/partials/_form.html.erb +1 -0
  27. data/app/views/plan_my_stuff/issues/edit.html.erb +2 -4
  28. data/app/views/plan_my_stuff/issues/index.html.erb +2 -2
  29. data/app/views/plan_my_stuff/issues/new.html.erb +2 -4
  30. data/app/views/plan_my_stuff/issues/partials/_approvals.html.erb +23 -2
  31. data/app/views/plan_my_stuff/issues/partials/_form.html.erb +1 -0
  32. data/app/views/plan_my_stuff/issues/partials/_labels.html.erb +2 -1
  33. data/app/views/plan_my_stuff/issues/partials/_links.html.erb +50 -7
  34. data/app/views/plan_my_stuff/issues/partials/_viewers.html.erb +2 -1
  35. data/app/views/plan_my_stuff/issues/show.html.erb +5 -2
  36. data/app/views/plan_my_stuff/partials/_flash.html.erb +4 -0
  37. data/app/views/plan_my_stuff/projects/edit.html.erb +1 -3
  38. data/app/views/plan_my_stuff/projects/index.html.erb +1 -1
  39. data/app/views/plan_my_stuff/projects/new.html.erb +1 -3
  40. data/app/views/plan_my_stuff/projects/partials/_form.html.erb +1 -0
  41. data/app/views/plan_my_stuff/projects/show.html.erb +13 -3
  42. data/app/views/plan_my_stuff/testing_project_items/new.html.erb +1 -3
  43. data/app/views/plan_my_stuff/testing_project_items/results/new.html.erb +1 -3
  44. data/app/views/plan_my_stuff/testing_projects/edit.html.erb +1 -3
  45. data/app/views/plan_my_stuff/testing_projects/new.html.erb +1 -3
  46. data/app/views/plan_my_stuff/testing_projects/partials/_form.html.erb +4 -3
  47. data/app/views/plan_my_stuff/testing_projects/partials/_item.html.erb +1 -0
  48. data/app/views/plan_my_stuff/testing_projects/partials/items/_form.html.erb +1 -0
  49. data/app/views/plan_my_stuff/testing_projects/show.html.erb +2 -2
  50. data/config/routes.rb +2 -2
  51. data/lib/generators/plan_my_stuff/install/templates/initializer.rb +56 -3
  52. data/lib/plan_my_stuff/approval.rb +12 -4
  53. data/lib/plan_my_stuff/aws_sns_simulator.rb +12 -6
  54. data/lib/plan_my_stuff/base_metadata.rb +4 -15
  55. data/lib/plan_my_stuff/base_project.rb +68 -55
  56. data/lib/plan_my_stuff/base_project_item.rb +61 -57
  57. data/lib/plan_my_stuff/base_project_metadata.rb +1 -1
  58. data/lib/plan_my_stuff/client.rb +136 -48
  59. data/lib/plan_my_stuff/comment.rb +57 -57
  60. data/lib/plan_my_stuff/comment_metadata.rb +1 -1
  61. data/lib/plan_my_stuff/configuration.rb +95 -82
  62. data/lib/plan_my_stuff/errors.rb +10 -10
  63. data/lib/plan_my_stuff/graphql/queries.rb +1 -1
  64. data/lib/plan_my_stuff/issue.rb +501 -322
  65. data/lib/plan_my_stuff/issue_metadata.rb +10 -10
  66. data/lib/plan_my_stuff/label.rb +32 -16
  67. data/lib/plan_my_stuff/link.rb +15 -15
  68. data/lib/plan_my_stuff/markdown.rb +12 -6
  69. data/lib/plan_my_stuff/metadata_parser.rb +3 -1
  70. data/lib/plan_my_stuff/notifications.rb +1 -1
  71. data/lib/plan_my_stuff/pipeline/completed_sweep.rb +2 -2
  72. data/lib/plan_my_stuff/pipeline/issue_linker.rb +1 -1
  73. data/lib/plan_my_stuff/pipeline.rb +61 -83
  74. data/lib/plan_my_stuff/project.rb +4 -4
  75. data/lib/plan_my_stuff/project_item_metadata.rb +1 -1
  76. data/lib/plan_my_stuff/project_metadata.rb +1 -1
  77. data/lib/plan_my_stuff/reminders/closer.rb +1 -1
  78. data/lib/plan_my_stuff/reminders/fire.rb +3 -3
  79. data/lib/plan_my_stuff/reminders/sweep.rb +4 -4
  80. data/lib/plan_my_stuff/repo.rb +12 -6
  81. data/lib/plan_my_stuff/test_helpers.rb +11 -11
  82. data/lib/plan_my_stuff/testing_project.rb +12 -11
  83. data/lib/plan_my_stuff/testing_project_item.rb +11 -9
  84. data/lib/plan_my_stuff/testing_project_metadata.rb +2 -2
  85. data/lib/plan_my_stuff/version.rb +1 -1
  86. data/lib/plan_my_stuff/webhook_replayer.rb +14 -2
  87. data/lib/plan_my_stuff.rb +26 -2
  88. data/lib/tasks/plan_my_stuff.rake +33 -20
  89. metadata +3 -2
@@ -2,9 +2,8 @@
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.
5
+ # Default controller for each controllable route group. Consuming apps override by assigning values into
6
+ # +controllers+; lookups go through +controller_for+ which falls back to this table.
8
7
  #
9
8
  # @return [Hash{Symbol => String}]
10
9
  #
@@ -32,6 +31,13 @@ module PlanMyStuff
32
31
  # @return [String] GitHub PAT with repo and project scopes. Required.
33
32
  attr_accessor :access_token
34
33
 
34
+ # Classic GitHub PAT used for the Issues Import API (golden-comet-preview). Requires the +repo+ scope (admin-level
35
+ # repository access). Fine-grained tokens are not supported by that endpoint.
36
+ #
37
+ # @return [String, nil]
38
+ #
39
+ attr_accessor :import_access_token
40
+
35
41
  # @return [String] GitHub organization name. Required.
36
42
  attr_accessor :organization
37
43
 
@@ -41,10 +47,9 @@ module PlanMyStuff
41
47
  # @return [Integer, nil] default GitHub Projects V2 number for add_to_project calls
42
48
  attr_accessor :default_project_number
43
49
 
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.
50
+ # @return [Integer, nil] GitHub Projects V2 number of the template project to clone when creating new
51
+ # TestingProjects. When set, TestingProject.create! copies the template (preserving its fields and board layout)
52
+ # instead of bootstrapping fields from scratch. Leave nil to use the default bootstrap-fields path.
48
53
  attr_accessor :testing_template_project_number
49
54
 
50
55
  # @return [String] consuming app's user model class name, constantized for lookups
@@ -56,8 +61,8 @@ module PlanMyStuff
56
61
  # @return [Symbol] method called on user object to extract the app-side user ID
57
62
  attr_accessor :user_id_method
58
63
 
59
- # Determines if a user is support staff. Symbol (method name on user) or Proc that
60
- # receives the user object and returns boolean.
64
+ # Determines if a user is support staff. Symbol (method name on user) or Proc that receives the user object and
65
+ # returns boolean.
61
66
  #
62
67
  # @return [Symbol, Proc]
63
68
  #
@@ -66,8 +71,7 @@ module PlanMyStuff
66
71
  # @return [Symbol] which markdown gem to use: :commonmarker or :redcarpet
67
72
  attr_accessor :markdown_renderer
68
73
 
69
- # Default options passed to the markdown renderer. Per-call options in
70
- # Markdown.render merge on top of these.
74
+ # Default options passed to the markdown renderer. Per-call options in Markdown.render merge on top of these.
71
75
  #
72
76
  # For :commonmarker - passed as `options:` to `Commonmarker.to_html`
73
77
  # e.g. `{ render: { hardbreaks: true } }`
@@ -80,22 +84,21 @@ module PlanMyStuff
80
84
  #
81
85
  attr_accessor :markdown_options
82
86
 
83
- # Proc returning boolean, or nil (always send). When it returns false the request is
84
- # deferred to a background job instead of hitting GitHub.
87
+ # Proc returning boolean, or nil (always send). When it returns false the request is deferred to a background job
88
+ # instead of hitting GitHub.
85
89
  #
86
90
  # @return [Proc, nil]
87
91
  #
88
92
  attr_accessor :should_send_request
89
93
 
90
- # Map of action type to job class name for deferred requests.
91
- # Keys: :create_ticket, :post_comment, :update_status.
94
+ # Map of action type to job class name for deferred requests. Keys: :create_ticket, :post_comment, :update_status.
92
95
  #
93
96
  # @return [Hash{Symbol => String}]
94
97
  #
95
98
  attr_accessor :job_classes
96
99
 
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.
100
+ # Fallback actor for notification events when a caller does not pass +user:+. Set to a proc/lambda that returns the
101
+ # current request user.
99
102
  #
100
103
  # Example: +config.current_user = -> { Current.user }+
101
104
  #
@@ -103,42 +106,65 @@ module PlanMyStuff
103
106
  #
104
107
  attr_accessor :current_user
105
108
 
106
- # Shared field definitions stored in issue/comment metadata.
107
- # Keys are field names, values are hashes with :type and :required.
108
- # These fields apply to both issues and comments.
109
+ # Callback invoked from gem controller +rescue+ blocks just after the error is logged and just before the
110
+ # user-facing redirect/render. Lets consuming apps forward swallowed errors to their monitoring service. Receives
111
+ # the rescued exception.
112
+ #
113
+ # Example:
114
+ # config.controller_rescue = ->(error) { MonitoringService.notice_error(error) }
115
+ #
116
+ # @return [Proc, nil]
117
+ #
118
+ attr_accessor :controller_rescue
119
+
120
+ # Shared field definitions stored in issue/comment metadata. Keys are field names, values are hashes with :type and
121
+ # :required. These fields apply to both issues and comments.
109
122
  #
110
123
  # @return [Hash{Symbol => Hash}]
111
124
  #
112
125
  attr_accessor :custom_fields
113
126
 
114
- # Issue-only field definitions, deep-merged on top of shared custom_fields.
115
- # Context-specific config wins on key conflicts.
127
+ # Issue-only field definitions, deep-merged on top of shared custom_fields. Context-specific config wins on key
128
+ # conflicts.
116
129
  #
117
130
  # @return [Hash{Symbol => Hash}]
118
131
  #
119
132
  attr_accessor :issue_custom_fields
120
133
 
121
- # Comment-only field definitions, deep-merged on top of shared custom_fields.
122
- # Context-specific config wins on key conflicts.
134
+ # Comment-only field definitions, deep-merged on top of shared custom_fields. Context-specific config wins on key
135
+ # conflicts.
123
136
  #
124
137
  # @return [Hash{Symbol => Hash}]
125
138
  #
126
139
  attr_accessor :comment_custom_fields
127
140
 
128
- # Project-only field definitions, deep-merged on top of shared custom_fields.
129
- # Context-specific config wins on key conflicts.
141
+ # Project-only field definitions, deep-merged on top of shared custom_fields. Context-specific config wins on key
142
+ # conflicts.
130
143
  #
131
144
  # @return [Hash{Symbol => Hash}]
132
145
  #
133
146
  attr_accessor :project_custom_fields
134
147
 
135
- # Testing-project-only field definitions, deep-merged on top of shared custom_fields.
136
- # Context-specific config wins on key conflicts.
148
+ # Testing-project-only field definitions, deep-merged on top of shared custom_fields. Context-specific config wins
149
+ # on key conflicts.
137
150
  #
138
151
  # @return [Hash{Symbol => Hash}]
139
152
  #
140
153
  attr_accessor :testing_custom_fields
141
154
 
155
+ # Canonical-name to org-side display-name map for GitHub native issue types. Lets the consuming app rename the
156
+ # seven canonical types the gem knows about (+"Bug"+, +"Feature"+, +"IT Issue / Hardware"+, +"Other"+,
157
+ # +"Performance"+, +"Question"+, +"Task"+) to whatever their org actually uses. Both Symbol shortcuts (resolved via
158
+ # the gem's nickname map) and String inputs to +Issue.create!+ / +Issue.update!+ are passed through this map;
159
+ # missing keys fall through unchanged.
160
+ #
161
+ # Example: +config.issue_types = { 'Bug' => 'User Bug', 'Feature' => 'Enhancement' }+ then +issue_type: :feature+
162
+ # or +issue_type: 'Feature'+ both write +'Enhancement'+ to GitHub.
163
+ #
164
+ # @return [Hash{String => String}]
165
+ #
166
+ attr_accessor :issue_types
167
+
142
168
  # @return [String, nil] URL prefix for building user-facing ticket URLs in the consuming app
143
169
  attr_accessor :issues_url_prefix
144
170
 
@@ -163,23 +189,21 @@ module PlanMyStuff
163
189
  # @return [String, nil] commit hash of the deploying build, prefix-matched against issue metadata commit_sha
164
190
  attr_accessor :production_commit_sha
165
191
 
166
- # Canonical status name to display alias map. Allows consuming apps to rename
167
- # pipeline statuses (e.g. "Started" to "In Progress").
192
+ # Canonical status name to display alias map. Allows consuming apps to rename pipeline statuses (e.g. "Started" to
193
+ # "In Progress").
168
194
  #
169
195
  # @return [Hash{String => String}]
170
196
  #
171
197
  attr_accessor :pipeline_statuses
172
198
 
173
- # Display name for the +Testing+ single-select custom field on the
174
- # pipeline project. Defaults to +"Testing"+.
199
+ # Display name for the +Testing+ single-select custom field on the pipeline project. Defaults to +"Testing"+.
175
200
  #
176
201
  # @return [String]
177
202
  #
178
203
  attr_accessor :pipeline_testing_field_name
179
204
 
180
- # Map of canonical testing field option keys (+:active+, +:inactive+)
181
- # to display labels. Allows consuming apps to rename the option labels
182
- # without changing the canonical identifiers.
205
+ # Map of canonical testing field option keys (+:active+, +:inactive+) to display labels. Allows consuming apps to
206
+ # rename the option labels without changing the canonical identifiers.
183
207
  #
184
208
  # @return [Hash{Symbol => String}]
185
209
  #
@@ -191,10 +215,8 @@ module PlanMyStuff
191
215
  # @return [String] branch name that triggers deployment when a PR merges
192
216
  attr_accessor :production_branch
193
217
 
194
- # Hash mapping consuming-app user id to GitHub login. Used by the
195
- # "Take" UI flow to assign the GitHub user when a support user claims
196
- # an issue. Keys are whatever +config.user_id_method+ returns on the
197
- # current user.
218
+ # Hash mapping consuming-app user id to GitHub login. Used by the "Take" UI flow to assign the GitHub user when a
219
+ # support user claims an issue. Keys are whatever +config.user_id_method+ returns on the current user.
198
220
  #
199
221
  # Example: +config.github_login_for = { 1 => 'some_username', 2 => 'octocat' }+
200
222
  #
@@ -202,48 +224,44 @@ module PlanMyStuff
202
224
  #
203
225
  attr_accessor :github_login_for
204
226
 
205
- # Per-group route mounting toggles. Keys: :webhooks, :issues, :projects.
206
- # Set a key to false to skip mounting that route group.
227
+ # Per-group route mounting toggles. Keys: :webhooks, :issues, :projects. Set a key to false to skip mounting that
228
+ # route group.
207
229
  #
208
230
  # @return [Hash{Symbol => Boolean}]
209
231
  #
210
232
  attr_accessor :mount_groups
211
233
 
212
- # Per-route controller overrides. Keys are the controllable route symbols
213
- # defined in +DEFAULT_CONTROLLERS+; values are fully-qualified controller
214
- # paths (e.g. +'my_app/issues'+). Unset keys fall back to the gem default.
215
- # Consuming apps typically subclass the gem controller to add before_actions
216
- # or tweak responses, then swap their subclass in here.
234
+ # Per-route controller overrides. Keys are the controllable route symbols defined in +DEFAULT_CONTROLLERS+; values
235
+ # are fully-qualified controller paths (e.g. +'my_app/issues'+). Unset keys fall back to the gem default. Consuming
236
+ # apps typically subclass the gem controller to add before_actions or tweak responses, then swap their subclass in
237
+ # here.
217
238
  #
218
239
  # @return [Hash{Symbol => String}]
219
240
  #
220
241
  attr_accessor :controllers
221
242
 
222
- # Whether to use Rails.cache for ETag-based HTTP caching of GitHub reads.
223
- # Defaults to true; set to false to bypass the cache entirely.
243
+ # Whether to use Rails.cache for ETag-based HTTP caching of GitHub reads. Defaults to true; set to false to bypass
244
+ # the cache entirely.
224
245
  #
225
246
  # @return [Boolean]
226
247
  #
227
248
  attr_accessor :cache_enabled
228
249
 
229
- # Opaque app-supplied version string embedded in every PMS cache key.
230
- # Bumping this string invalidates all cached entries from the consuming
231
- # app's side (e.g. after a deploy or schema change). Defaults to nil.
250
+ # Opaque app-supplied version string embedded in every PMS cache key. Bumping this string invalidates all cached
251
+ # entries from the consuming app's side (e.g. after a deploy or schema change). Defaults to nil.
232
252
  #
233
253
  # @return [String, nil]
234
254
  #
235
255
  attr_accessor :cache_version
236
256
 
237
- # Whether the reminders sweep performs any work. Defaults to +true+.
238
- # Set to +false+ in apps that don't want follow-up reminders or inactivity
239
- # auto-close.
257
+ # Whether the reminders sweep performs any work. Defaults to +true+. Set to +false+ in apps that don't want
258
+ # follow-up reminders or inactivity auto-close.
240
259
  #
241
260
  # @return [Boolean]
242
261
  #
243
262
  attr_accessor :reminders_enabled
244
263
 
245
- # Days-since-waiting at which reminder events fire. Per-issue override
246
- # via +metadata.reminder_days+.
264
+ # Days-since-waiting at which reminder events fire. Per-issue override via +metadata.reminder_days+.
247
265
  #
248
266
  # @return [Array<Integer>]
249
267
  #
@@ -267,45 +285,42 @@ module PlanMyStuff
267
285
  #
268
286
  attr_accessor :waiting_on_approval_label
269
287
 
270
- # Label name applied to issues auto-closed by the inactivity sweep.
271
- # Removed when an issue is auto-reopened via a user reply.
288
+ # Label name applied to issues auto-closed by the inactivity sweep. Removed when an issue is auto-reopened via a
289
+ # user reply.
272
290
  #
273
291
  # @return [String]
274
292
  #
275
293
  attr_accessor :user_inactive_label
276
294
 
277
- # Whether the archive sweep performs any work. Defaults to +true+.
278
- # Set to +false+ in apps that don't want auto-archiving of aged-closed
279
- # issues.
295
+ # Whether the archive sweep performs any work. Defaults to +true+. Set to +false+ in apps that don't want
296
+ # auto-archiving of aged-closed issues.
280
297
  #
281
298
  # @return [Boolean]
282
299
  #
283
300
  attr_accessor :archiving_enabled
284
301
 
285
- # Days after +closed_at+ at which a non-inactive-closed issue becomes an
286
- # archive candidate.
302
+ # Days after +closed_at+ at which a non-inactive-closed issue becomes an archive candidate.
287
303
  #
288
304
  # @return [Integer]
289
305
  #
290
306
  attr_accessor :archive_closed_after_days
291
307
 
292
- # Label name added to archived issues. Also used by the sweep as a
293
- # skip marker to avoid re-archiving the same issue.
308
+ # Label name added to archived issues. Also used by the sweep as a skip marker to avoid re-archiving the same
309
+ # issue.
294
310
  #
295
311
  # @return [String]
296
312
  #
297
313
  attr_accessor :archived_label
298
314
 
299
- # Whether the pipeline sweep removes aged-out +Completed+ items.
300
- # Defaults to +true+. Set to +false+ to keep items in +Completed+
301
- # indefinitely.
315
+ # Whether the pipeline sweep removes aged-out +Completed+ items. Defaults to +true+. Set to +false+ to keep items
316
+ # in +Completed+ indefinitely.
302
317
  #
303
318
  # @return [Boolean]
304
319
  #
305
320
  attr_accessor :pipeline_completion_purge_enabled
306
321
 
307
- # Hours after a project item's last update at which the sweep removes
308
- # it from the pipeline if its status is +Completed+. Defaults to +24+.
322
+ # Hours after a project item's last update at which the sweep removes it from the pipeline if its status is
323
+ # +Completed+. Defaults to +24+.
309
324
  #
310
325
  # @return [Integer]
311
326
  #
@@ -317,8 +332,7 @@ module PlanMyStuff
317
332
  #
318
333
  attr_accessor :process_aws_webhooks
319
334
 
320
- # Class instantiated per request for SNS signature verification.
321
- # Must respond to +authenticate!(raw_body)+.
335
+ # Class instantiated per request for SNS signature verification. Must respond to +authenticate!(raw_body)+.
322
336
  #
323
337
  # @return [Class]
324
338
  #
@@ -351,6 +365,7 @@ module PlanMyStuff
351
365
  @comment_custom_fields = {}
352
366
  @project_custom_fields = {}
353
367
  @testing_custom_fields = {}
368
+ @issue_types = {}
354
369
  @pipeline_enabled = true
355
370
  @pipeline_statuses = {}
356
371
  @pipeline_testing_field_name = PlanMyStuff::Pipeline::Testing::FIELD_NAME
@@ -406,13 +421,13 @@ module PlanMyStuff
406
421
  return if missing.empty?
407
422
 
408
423
  raise(
409
- ConfigurationError,
424
+ PlanMyStuff::ConfigurationError,
410
425
  "Missing required PlanMyStuff configuration: #{missing.join(', ')}",
411
426
  )
412
427
  end
413
428
 
414
- # Returns the merged custom fields schema for the given context.
415
- # Context-specific fields deep-merge on top of shared fields.
429
+ # Returns the merged custom fields schema for the given context. Context-specific fields deep-merge on top of
430
+ # shared fields.
416
431
  #
417
432
  # @param context [Symbol] :issue or :comment
418
433
  #
@@ -431,16 +446,14 @@ module PlanMyStuff
431
446
  custom_fields.deep_merge(context_fields)
432
447
  end
433
448
 
434
- # Returns the controller path for the given route group, preferring a
435
- # consuming-app override from +controllers+ and falling back to the gem
436
- # default from +DEFAULT_CONTROLLERS+. The returned value always begins
437
- # with +'/'+ so the isolated engine does not re-prefix it with
438
- # +plan_my_stuff/+.
439
- #
440
- # @param key [Symbol]
449
+ # Returns the controller path for the given route group, preferring a consuming-app override from +controllers+
450
+ # and falling back to the gem default from +DEFAULT_CONTROLLERS+. The returned value always begins with +'/'+ so
451
+ # the isolated engine does not re-prefix it with +plan_my_stuff/+.
441
452
  #
442
453
  # @raise [KeyError] if +key+ is not a controllable route group
443
454
  #
455
+ # @param key [Symbol]
456
+ #
444
457
  # @return [String]
445
458
  #
446
459
  def controller_for(key)
@@ -6,7 +6,7 @@ module PlanMyStuff
6
6
  end
7
7
 
8
8
  # Raised when GitHub REST API returns a non-success HTTP status
9
- class APIError < Error
9
+ class APIError < PlanMyStuff::Error
10
10
  # @return [Integer]
11
11
  attr_reader :status
12
12
 
@@ -20,7 +20,7 @@ module PlanMyStuff
20
20
  end
21
21
 
22
22
  # Raised when GitHub GraphQL API returns errors in the response body
23
- class GraphQLError < Error
23
+ class GraphQLError < PlanMyStuff::Error
24
24
  # @return [Array<Hash>]
25
25
  attr_reader :errors
26
26
 
@@ -34,7 +34,7 @@ module PlanMyStuff
34
34
  end
35
35
 
36
36
  # Raised when GitHub rate limit is exhausted (429 or rate limit headers)
37
- class RateLimitError < Error
37
+ class RateLimitError < PlanMyStuff::Error
38
38
  # @return [Time]
39
39
  attr_reader :retry_after
40
40
 
@@ -48,7 +48,7 @@ module PlanMyStuff
48
48
  end
49
49
 
50
50
  # Raised when an object has been modified remotely since it was loaded
51
- class StaleObjectError < Error
51
+ class StaleObjectError < PlanMyStuff::Error
52
52
  # @return [Time, nil]
53
53
  attr_reader :local_updated_at
54
54
 
@@ -67,18 +67,18 @@ module PlanMyStuff
67
67
  end
68
68
 
69
69
  # Raised when a webhook HMAC-SHA256 signature check fails
70
- class WebhookSignatureError < Error
70
+ class WebhookSignatureError < PlanMyStuff::Error
71
71
  def initialize(message = 'Invalid webhook signature')
72
72
  super
73
73
  end
74
74
  end
75
75
 
76
76
  # Raised when a pipeline operation fails
77
- class PipelineError < Error
77
+ class PipelineError < PlanMyStuff::Error
78
78
  end
79
79
 
80
80
  # Raised when custom field validation fails (Phase 1)
81
- class ValidationError < Error
81
+ class ValidationError < PlanMyStuff::Error
82
82
  # @return [String, nil]
83
83
  attr_reader :field
84
84
 
@@ -98,17 +98,17 @@ module PlanMyStuff
98
98
 
99
99
  # Raised when a caller is not authorized to perform an action (e.g.
100
100
  # a non-support user attempts to manage approvers on an issue).
101
- class AuthorizationError < Error
101
+ class AuthorizationError < PlanMyStuff::Error
102
102
  end
103
103
 
104
104
  # Raised when an operation is attempted on an issue whose conversation
105
105
  # is locked on GitHub (archived or manually locked).
106
- class LockedIssueError < Error
106
+ class LockedIssueError < PlanMyStuff::Error
107
107
  end
108
108
 
109
109
  # Raised by +PlanMyStuff::Pipeline+ forward transitions when the linked
110
110
  # +Issue+ has any pending manager approvals.
111
- class PendingApprovalsError < ValidationError
111
+ class PendingApprovalsError < PlanMyStuff::ValidationError
112
112
  # @return [PlanMyStuff::Issue, nil]
113
113
  attr_reader :issue
114
114
 
@@ -9,7 +9,7 @@ module PlanMyStuff
9
9
  # Callers pass the constant straight to +PlanMyStuff.client.graphql+:
10
10
  #
11
11
  # PlanMyStuff.client.graphql(
12
- # PMS::GraphQL::Queries::DELETE_PROJECT_ITEM,
12
+ # PlanMyStuff::GraphQL::Queries::DELETE_PROJECT_ITEM,
13
13
  # variables: { projectId: ..., itemId: ... },
14
14
  # )
15
15
  #