plan_my_stuff 0.7.0 → 0.9.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 (90) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +46 -1
  3. data/CONFIGURATION.md +351 -0
  4. data/README.md +100 -103
  5. data/app/controllers/plan_my_stuff/application_controller.rb +22 -3
  6. data/app/controllers/plan_my_stuff/comments_controller.rb +14 -16
  7. data/app/controllers/plan_my_stuff/issues/approvals_controller.rb +23 -13
  8. data/app/controllers/plan_my_stuff/issues/closures_controller.rb +7 -5
  9. data/app/controllers/plan_my_stuff/issues/links_controller.rb +14 -18
  10. data/app/controllers/plan_my_stuff/issues/takes_controller.rb +99 -28
  11. data/app/controllers/plan_my_stuff/issues/viewers_controller.rb +13 -5
  12. data/app/controllers/plan_my_stuff/issues/waitings_controller.rb +7 -5
  13. data/app/controllers/plan_my_stuff/issues_controller.rb +24 -28
  14. data/app/controllers/plan_my_stuff/labels_controller.rb +21 -5
  15. data/app/controllers/plan_my_stuff/project_items/assignments_controller.rb +13 -6
  16. data/app/controllers/plan_my_stuff/project_items/statuses_controller.rb +5 -4
  17. data/app/controllers/plan_my_stuff/project_items_controller.rb +30 -5
  18. data/app/controllers/plan_my_stuff/projects_controller.rb +16 -16
  19. data/app/controllers/plan_my_stuff/testing_project_items/results_controller.rb +21 -11
  20. data/app/controllers/plan_my_stuff/testing_project_items_controller.rb +9 -4
  21. data/app/controllers/plan_my_stuff/testing_projects_controller.rb +30 -14
  22. data/app/controllers/plan_my_stuff/webhooks/aws_controller.rb +50 -17
  23. data/app/controllers/plan_my_stuff/webhooks/github_controller.rb +32 -49
  24. data/app/jobs/plan_my_stuff/application_job.rb +2 -3
  25. data/app/jobs/plan_my_stuff/reminders_sweep_job.rb +15 -22
  26. data/app/views/plan_my_stuff/comments/edit.html.erb +1 -3
  27. data/app/views/plan_my_stuff/comments/partials/_form.html.erb +1 -0
  28. data/app/views/plan_my_stuff/issues/edit.html.erb +2 -4
  29. data/app/views/plan_my_stuff/issues/index.html.erb +2 -2
  30. data/app/views/plan_my_stuff/issues/new.html.erb +2 -4
  31. data/app/views/plan_my_stuff/issues/partials/_approvals.html.erb +23 -2
  32. data/app/views/plan_my_stuff/issues/partials/_form.html.erb +1 -0
  33. data/app/views/plan_my_stuff/issues/partials/_labels.html.erb +2 -1
  34. data/app/views/plan_my_stuff/issues/partials/_links.html.erb +50 -7
  35. data/app/views/plan_my_stuff/issues/partials/_viewers.html.erb +2 -1
  36. data/app/views/plan_my_stuff/issues/show.html.erb +5 -2
  37. data/app/views/plan_my_stuff/partials/_flash.html.erb +3 -0
  38. data/app/views/plan_my_stuff/projects/edit.html.erb +1 -3
  39. data/app/views/plan_my_stuff/projects/index.html.erb +1 -1
  40. data/app/views/plan_my_stuff/projects/new.html.erb +1 -3
  41. data/app/views/plan_my_stuff/projects/partials/_form.html.erb +1 -0
  42. data/app/views/plan_my_stuff/projects/show.html.erb +13 -3
  43. data/app/views/plan_my_stuff/testing_project_items/new.html.erb +1 -3
  44. data/app/views/plan_my_stuff/testing_project_items/results/new.html.erb +1 -3
  45. data/app/views/plan_my_stuff/testing_projects/edit.html.erb +1 -3
  46. data/app/views/plan_my_stuff/testing_projects/new.html.erb +1 -3
  47. data/app/views/plan_my_stuff/testing_projects/partials/_form.html.erb +4 -3
  48. data/app/views/plan_my_stuff/testing_projects/partials/_item.html.erb +1 -0
  49. data/app/views/plan_my_stuff/testing_projects/partials/items/_form.html.erb +1 -0
  50. data/app/views/plan_my_stuff/testing_projects/show.html.erb +2 -2
  51. data/config/routes.rb +2 -2
  52. data/lib/generators/plan_my_stuff/install/templates/initializer.rb +52 -14
  53. data/lib/plan_my_stuff/approval.rb +12 -4
  54. data/lib/plan_my_stuff/aws_sns_simulator.rb +12 -6
  55. data/lib/plan_my_stuff/base_metadata.rb +4 -15
  56. data/lib/plan_my_stuff/base_project.rb +68 -55
  57. data/lib/plan_my_stuff/base_project_item.rb +62 -57
  58. data/lib/plan_my_stuff/base_project_metadata.rb +1 -1
  59. data/lib/plan_my_stuff/client.rb +136 -48
  60. data/lib/plan_my_stuff/comment.rb +59 -57
  61. data/lib/plan_my_stuff/comment_metadata.rb +1 -1
  62. data/lib/plan_my_stuff/configuration.rb +93 -93
  63. data/lib/plan_my_stuff/errors.rb +10 -10
  64. data/lib/plan_my_stuff/graphql/queries.rb +1 -1
  65. data/lib/plan_my_stuff/issue.rb +471 -333
  66. data/lib/plan_my_stuff/issue_metadata.rb +10 -10
  67. data/lib/plan_my_stuff/label.rb +34 -18
  68. data/lib/plan_my_stuff/link.rb +15 -15
  69. data/lib/plan_my_stuff/markdown.rb +12 -6
  70. data/lib/plan_my_stuff/metadata_parser.rb +3 -1
  71. data/lib/plan_my_stuff/notifications.rb +1 -1
  72. data/lib/plan_my_stuff/pipeline/completed_sweep.rb +2 -2
  73. data/lib/plan_my_stuff/pipeline/issue_linker.rb +1 -1
  74. data/lib/plan_my_stuff/pipeline.rb +61 -83
  75. data/lib/plan_my_stuff/project.rb +4 -4
  76. data/lib/plan_my_stuff/project_item_metadata.rb +1 -1
  77. data/lib/plan_my_stuff/project_metadata.rb +1 -1
  78. data/lib/plan_my_stuff/reminders/closer.rb +1 -1
  79. data/lib/plan_my_stuff/reminders/fire.rb +3 -3
  80. data/lib/plan_my_stuff/reminders/sweep.rb +4 -4
  81. data/lib/plan_my_stuff/repo.rb +12 -6
  82. data/lib/plan_my_stuff/test_helpers.rb +11 -11
  83. data/lib/plan_my_stuff/testing_project.rb +12 -11
  84. data/lib/plan_my_stuff/testing_project_item.rb +11 -9
  85. data/lib/plan_my_stuff/testing_project_metadata.rb +2 -2
  86. data/lib/plan_my_stuff/version.rb +1 -1
  87. data/lib/plan_my_stuff/webhook_replayer.rb +14 -2
  88. data/lib/plan_my_stuff.rb +26 -2
  89. data/lib/tasks/plan_my_stuff.rake +33 -20
  90. metadata +4 -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,65 +84,74 @@ 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.
85
- #
86
- # @return [Proc, nil]
87
+ # Fallback actor for notification events when a caller does not pass +user:+. Set to a proc/lambda that returns the
88
+ # current request user.
87
89
  #
88
- attr_accessor :should_send_request
89
-
90
- # Map of action type to job class name for deferred requests.
91
- # Keys: :create_ticket, :post_comment, :update_status.
90
+ # Example: +config.current_user = -> { Current.user }+
92
91
  #
93
- # @return [Hash{Symbol => String}]
92
+ # @return [Proc, nil]
94
93
  #
95
- attr_accessor :job_classes
94
+ attr_accessor :current_user
96
95
 
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.
96
+ # Callback invoked from gem controller +rescue+ blocks just after the error is logged and just before the
97
+ # user-facing redirect/render. Lets consuming apps forward swallowed errors to their monitoring service. Receives
98
+ # the rescued exception.
99
99
  #
100
- # Example: +config.current_user = -> { Current.user }+
100
+ # Example:
101
+ # config.controller_rescue = ->(error) { MonitoringService.notice_error(error) }
101
102
  #
102
103
  # @return [Proc, nil]
103
104
  #
104
- attr_accessor :current_user
105
+ attr_accessor :controller_rescue
105
106
 
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.
107
+ # Shared field definitions stored in issue/comment metadata. Keys are field names, values are hashes with :type and
108
+ # :required. These fields apply to both issues and comments.
109
109
  #
110
110
  # @return [Hash{Symbol => Hash}]
111
111
  #
112
112
  attr_accessor :custom_fields
113
113
 
114
- # Issue-only field definitions, deep-merged on top of shared custom_fields.
115
- # Context-specific config wins on key conflicts.
114
+ # Issue-only field definitions, deep-merged on top of shared custom_fields. Context-specific config wins on key
115
+ # conflicts.
116
116
  #
117
117
  # @return [Hash{Symbol => Hash}]
118
118
  #
119
119
  attr_accessor :issue_custom_fields
120
120
 
121
- # Comment-only field definitions, deep-merged on top of shared custom_fields.
122
- # Context-specific config wins on key conflicts.
121
+ # Comment-only field definitions, deep-merged on top of shared custom_fields. Context-specific config wins on key
122
+ # conflicts.
123
123
  #
124
124
  # @return [Hash{Symbol => Hash}]
125
125
  #
126
126
  attr_accessor :comment_custom_fields
127
127
 
128
- # Project-only field definitions, deep-merged on top of shared custom_fields.
129
- # Context-specific config wins on key conflicts.
128
+ # Project-only field definitions, deep-merged on top of shared custom_fields. Context-specific config wins on key
129
+ # conflicts.
130
130
  #
131
131
  # @return [Hash{Symbol => Hash}]
132
132
  #
133
133
  attr_accessor :project_custom_fields
134
134
 
135
- # Testing-project-only field definitions, deep-merged on top of shared custom_fields.
136
- # Context-specific config wins on key conflicts.
135
+ # Testing-project-only field definitions, deep-merged on top of shared custom_fields. Context-specific config wins
136
+ # on key conflicts.
137
137
  #
138
138
  # @return [Hash{Symbol => Hash}]
139
139
  #
140
140
  attr_accessor :testing_custom_fields
141
141
 
142
+ # Canonical-name to org-side display-name map for GitHub native issue types. Lets the consuming app rename the
143
+ # seven canonical types the gem knows about (+"Bug"+, +"Feature"+, +"IT Issue / Hardware"+, +"Other"+,
144
+ # +"Performance"+, +"Question"+, +"Task"+) to whatever their org actually uses. Both Symbol shortcuts (resolved via
145
+ # the gem's nickname map) and String inputs to +Issue.create!+ / +Issue.update!+ are passed through this map;
146
+ # missing keys fall through unchanged.
147
+ #
148
+ # Example: +config.issue_types = { 'Bug' => 'User Bug', 'Feature' => 'Enhancement' }+ then +issue_type: :feature+
149
+ # or +issue_type: 'Feature'+ both write +'Enhancement'+ to GitHub.
150
+ #
151
+ # @return [Hash{String => String}]
152
+ #
153
+ attr_accessor :issue_types
154
+
142
155
  # @return [String, nil] URL prefix for building user-facing ticket URLs in the consuming app
143
156
  attr_accessor :issues_url_prefix
144
157
 
@@ -163,23 +176,21 @@ module PlanMyStuff
163
176
  # @return [String, nil] commit hash of the deploying build, prefix-matched against issue metadata commit_sha
164
177
  attr_accessor :production_commit_sha
165
178
 
166
- # Canonical status name to display alias map. Allows consuming apps to rename
167
- # pipeline statuses (e.g. "Started" to "In Progress").
179
+ # Canonical status name to display alias map. Allows consuming apps to rename pipeline statuses (e.g. "Started" to
180
+ # "In Progress").
168
181
  #
169
182
  # @return [Hash{String => String}]
170
183
  #
171
184
  attr_accessor :pipeline_statuses
172
185
 
173
- # Display name for the +Testing+ single-select custom field on the
174
- # pipeline project. Defaults to +"Testing"+.
186
+ # Display name for the +Testing+ single-select custom field on the pipeline project. Defaults to +"Testing"+.
175
187
  #
176
188
  # @return [String]
177
189
  #
178
190
  attr_accessor :pipeline_testing_field_name
179
191
 
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.
192
+ # Map of canonical testing field option keys (+:active+, +:inactive+) to display labels. Allows consuming apps to
193
+ # rename the option labels without changing the canonical identifiers.
183
194
  #
184
195
  # @return [Hash{Symbol => String}]
185
196
  #
@@ -191,10 +202,8 @@ module PlanMyStuff
191
202
  # @return [String] branch name that triggers deployment when a PR merges
192
203
  attr_accessor :production_branch
193
204
 
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.
205
+ # Hash mapping consuming-app user id to GitHub login. Used by the "Take" UI flow to assign the GitHub user when a
206
+ # support user claims an issue. Keys are whatever +config.user_id_method+ returns on the current user.
198
207
  #
199
208
  # Example: +config.github_login_for = { 1 => 'some_username', 2 => 'octocat' }+
200
209
  #
@@ -202,48 +211,44 @@ module PlanMyStuff
202
211
  #
203
212
  attr_accessor :github_login_for
204
213
 
205
- # Per-group route mounting toggles. Keys: :webhooks, :issues, :projects.
206
- # Set a key to false to skip mounting that route group.
214
+ # Per-group route mounting toggles. Keys: :webhooks, :issues, :projects. Set a key to false to skip mounting that
215
+ # route group.
207
216
  #
208
217
  # @return [Hash{Symbol => Boolean}]
209
218
  #
210
219
  attr_accessor :mount_groups
211
220
 
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.
221
+ # Per-route controller overrides. Keys are the controllable route symbols defined in +DEFAULT_CONTROLLERS+; values
222
+ # are fully-qualified controller paths (e.g. +'my_app/issues'+). Unset keys fall back to the gem default. Consuming
223
+ # apps typically subclass the gem controller to add before_actions or tweak responses, then swap their subclass in
224
+ # here.
217
225
  #
218
226
  # @return [Hash{Symbol => String}]
219
227
  #
220
228
  attr_accessor :controllers
221
229
 
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.
230
+ # Whether to use Rails.cache for ETag-based HTTP caching of GitHub reads. Defaults to true; set to false to bypass
231
+ # the cache entirely.
224
232
  #
225
233
  # @return [Boolean]
226
234
  #
227
235
  attr_accessor :cache_enabled
228
236
 
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.
237
+ # Opaque app-supplied version string embedded in every PMS cache key. Bumping this string invalidates all cached
238
+ # entries from the consuming app's side (e.g. after a deploy or schema change). Defaults to nil.
232
239
  #
233
240
  # @return [String, nil]
234
241
  #
235
242
  attr_accessor :cache_version
236
243
 
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.
244
+ # Whether the reminders sweep performs any work. Defaults to +true+. Set to +false+ in apps that don't want
245
+ # follow-up reminders or inactivity auto-close.
240
246
  #
241
247
  # @return [Boolean]
242
248
  #
243
249
  attr_accessor :reminders_enabled
244
250
 
245
- # Days-since-waiting at which reminder events fire. Per-issue override
246
- # via +metadata.reminder_days+.
251
+ # Days-since-waiting at which reminder events fire. Per-issue override via +metadata.reminder_days+.
247
252
  #
248
253
  # @return [Array<Integer>]
249
254
  #
@@ -267,45 +272,42 @@ module PlanMyStuff
267
272
  #
268
273
  attr_accessor :waiting_on_approval_label
269
274
 
270
- # Label name applied to issues auto-closed by the inactivity sweep.
271
- # Removed when an issue is auto-reopened via a user reply.
275
+ # Label name applied to issues auto-closed by the inactivity sweep. Removed when an issue is auto-reopened via a
276
+ # user reply.
272
277
  #
273
278
  # @return [String]
274
279
  #
275
280
  attr_accessor :user_inactive_label
276
281
 
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.
282
+ # Whether the archive sweep performs any work. Defaults to +true+. Set to +false+ in apps that don't want
283
+ # auto-archiving of aged-closed issues.
280
284
  #
281
285
  # @return [Boolean]
282
286
  #
283
287
  attr_accessor :archiving_enabled
284
288
 
285
- # Days after +closed_at+ at which a non-inactive-closed issue becomes an
286
- # archive candidate.
289
+ # Days after +closed_at+ at which a non-inactive-closed issue becomes an archive candidate.
287
290
  #
288
291
  # @return [Integer]
289
292
  #
290
293
  attr_accessor :archive_closed_after_days
291
294
 
292
- # Label name added to archived issues. Also used by the sweep as a
293
- # skip marker to avoid re-archiving the same issue.
295
+ # Label name added to archived issues. Also used by the sweep as a skip marker to avoid re-archiving the same
296
+ # issue.
294
297
  #
295
298
  # @return [String]
296
299
  #
297
300
  attr_accessor :archived_label
298
301
 
299
- # Whether the pipeline sweep removes aged-out +Completed+ items.
300
- # Defaults to +true+. Set to +false+ to keep items in +Completed+
301
- # indefinitely.
302
+ # Whether the pipeline sweep removes aged-out +Completed+ items. Defaults to +true+. Set to +false+ to keep items
303
+ # in +Completed+ indefinitely.
302
304
  #
303
305
  # @return [Boolean]
304
306
  #
305
307
  attr_accessor :pipeline_completion_purge_enabled
306
308
 
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+.
309
+ # Hours after a project item's last update at which the sweep removes it from the pipeline if its status is
310
+ # +Completed+. Defaults to +24+.
309
311
  #
310
312
  # @return [Integer]
311
313
  #
@@ -317,8 +319,7 @@ module PlanMyStuff
317
319
  #
318
320
  attr_accessor :process_aws_webhooks
319
321
 
320
- # Class instantiated per request for SNS signature verification.
321
- # Must respond to +authenticate!(raw_body)+.
322
+ # Class instantiated per request for SNS signature verification. Must respond to +authenticate!(raw_body)+.
322
323
  #
323
324
  # @return [Class]
324
325
  #
@@ -330,11 +331,12 @@ module PlanMyStuff
330
331
  #
331
332
  attr_accessor :sns_verifier_error
332
333
 
333
- # Named repo configs. Set via config.repos[:element] = 'BrandsInsurance/Element'.
334
+ # Named repo configs. Set via config.repos[:element] = 'BrandsInsurance/Element', or assign a whole hash with
335
+ # config.repos = { element: 'BrandsInsurance/Element', underwriter: 'BrandsInsurance/Underwriter' }.
334
336
  #
335
337
  # @return [Hash{Symbol => String}]
336
338
  #
337
- attr_reader :repos
339
+ attr_accessor :repos
338
340
 
339
341
  # @return [Configuration]
340
342
  def initialize
@@ -345,12 +347,12 @@ module PlanMyStuff
345
347
  @support_method = :support?
346
348
  @markdown_renderer = :commonmarker
347
349
  @markdown_options = {}
348
- @job_classes = {}
349
350
  @custom_fields = {}
350
351
  @issue_custom_fields = {}
351
352
  @comment_custom_fields = {}
352
353
  @project_custom_fields = {}
353
354
  @testing_custom_fields = {}
355
+ @issue_types = {}
354
356
  @pipeline_enabled = true
355
357
  @pipeline_statuses = {}
356
358
  @pipeline_testing_field_name = PlanMyStuff::Pipeline::Testing::FIELD_NAME
@@ -406,13 +408,13 @@ module PlanMyStuff
406
408
  return if missing.empty?
407
409
 
408
410
  raise(
409
- ConfigurationError,
411
+ PlanMyStuff::ConfigurationError,
410
412
  "Missing required PlanMyStuff configuration: #{missing.join(', ')}",
411
413
  )
412
414
  end
413
415
 
414
- # Returns the merged custom fields schema for the given context.
415
- # Context-specific fields deep-merge on top of shared fields.
416
+ # Returns the merged custom fields schema for the given context. Context-specific fields deep-merge on top of
417
+ # shared fields.
416
418
  #
417
419
  # @param context [Symbol] :issue or :comment
418
420
  #
@@ -431,16 +433,14 @@ module PlanMyStuff
431
433
  custom_fields.deep_merge(context_fields)
432
434
  end
433
435
 
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]
436
+ # Returns the controller path for the given route group, preferring a consuming-app override from +controllers+
437
+ # and falling back to the gem default from +DEFAULT_CONTROLLERS+. The returned value always begins with +'/'+ so
438
+ # the isolated engine does not re-prefix it with +plan_my_stuff/+.
441
439
  #
442
440
  # @raise [KeyError] if +key+ is not a controllable route group
443
441
  #
442
+ # @param key [Symbol]
443
+ #
444
444
  # @return [String]
445
445
  #
446
446
  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
  #