plan_my_stuff 0.8.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +15 -0
- data/CONFIGURATION.md +351 -0
- data/app/views/plan_my_stuff/issues/show.html.erb +1 -1
- data/app/views/plan_my_stuff/partials/_flash.html.erb +0 -1
- data/lib/generators/plan_my_stuff/install/templates/initializer.rb +1 -12
- data/lib/plan_my_stuff/base_project.rb +1 -1
- data/lib/plan_my_stuff/base_project_item.rb +1 -0
- data/lib/plan_my_stuff/comment.rb +5 -3
- data/lib/plan_my_stuff/configuration.rb +3 -16
- data/lib/plan_my_stuff/issue.rb +5 -1
- data/lib/plan_my_stuff/label.rb +4 -4
- data/lib/plan_my_stuff/version.rb +1 -1
- data/lib/tasks/plan_my_stuff.rake +2 -2
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6457257ef431e923519943cd227ffc70488b023467253873e20f52c47fd75f52
|
|
4
|
+
data.tar.gz: b5a16da4dc6c6c3ce45b307879f5146720f2b878809b7a071b7cc9e33986d210
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: efee5f594d9bd014b0ce575781790768a8d51277010d9ad9902ac11beea06c17d39232d65a77532768326eccece3ebcbe3bdb18c464341c963eda9b12b1d6075
|
|
7
|
+
data.tar.gz: ef94bc70d08874c2347e243d0f7967ca7bca2e631cda775494a714df6501d22fe5011a09db805dbb53f5fe8397eb32b8bdf19bbf8a235da39d3f5dd4810c011a
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.9.0
|
|
4
|
+
|
|
5
|
+
### Breaking
|
|
6
|
+
|
|
7
|
+
- `config.should_send_request` and `config.job_classes` accessors — declared but never wired up. The request gateway that would honor them is deferred (see `requirements/09_request_gateway.md` and `designs/init/gem_mvp_deferred_notes.md`); they will return when the gateway lands
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- `CONFIGURATION.md` is now available bundled with the gem
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
|
|
15
|
+
- `config.repos` is now assignable as a whole hash (`config.repos = { atlas: 'Org/Atlas', autofill: 'Org/atlas-autofill-moz' }`) in addition to the existing `config.repos[:key] = '...'` form
|
|
16
|
+
- `Issue.create!` / `Issue.update!` `issue_type:` kwarg now accepts the Symbol nicknames (`'bug'`, `'feature'`, `'it_issue'`, `'other'`, `'performance'`, `'question'`, `'task'`) as Strings too, resolving them to the same canonical name
|
|
17
|
+
|
|
3
18
|
## 0.8.0
|
|
4
19
|
|
|
5
20
|
### Breaking
|
data/CONFIGURATION.md
ADDED
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
# Configuration
|
|
2
|
+
|
|
3
|
+
Every PlanMyStuff option lives on `PlanMyStuff::Configuration`. The install generator drops a fully-commented copy at
|
|
4
|
+
`config/initializers/plan_my_stuff.rb` — this file documents the same options grouped by concern. Defaults shown apply
|
|
5
|
+
when the option is left unset.
|
|
6
|
+
|
|
7
|
+
```ruby
|
|
8
|
+
PMS.configure do |config|
|
|
9
|
+
# ...
|
|
10
|
+
end
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
`PMS` is an alias for `PlanMyStuff`; consuming apps can use either.
|
|
14
|
+
|
|
15
|
+
## Authentication (required)
|
|
16
|
+
|
|
17
|
+
| Option | Type | Default | Description |
|
|
18
|
+
|---|---|---|---|
|
|
19
|
+
| `access_token` | `String` | — | GitHub PAT with `repo` and `project` scopes. Required. |
|
|
20
|
+
| `import_access_token` | `String, nil` | `nil` | Classic PAT (requires `repo` scope) for the Issues Import API. Fine-grained tokens are not supported by that endpoint. |
|
|
21
|
+
| `organization` | `String` | — | GitHub organization name. Required. |
|
|
22
|
+
|
|
23
|
+
Both `access_token` and `organization` are validated by `config.validate!`; missing or blank values raise `PlanMyStuff::ConfigurationError`.
|
|
24
|
+
|
|
25
|
+
> [!NOTE]
|
|
26
|
+
> `import_access_token` is only required if you choose to use `PMS::Issue.import!`/`PMS::Issue.check_import!`
|
|
27
|
+
|
|
28
|
+
```ruby
|
|
29
|
+
config.access_token = Rails.application.credentials.dig(:plan_my_stuff, :github_token)
|
|
30
|
+
config.import_access_token = Rails.application.credentials.dig(:plan_my_stuff, :github_import_token)
|
|
31
|
+
config.organization = 'YourOrg'
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Repositories
|
|
35
|
+
|
|
36
|
+
| Option | Type | Default | Description |
|
|
37
|
+
|---|---|---|---|
|
|
38
|
+
| `repos` | `Hash{Symbol => String}` | `{}` | Named repo configs mapping a key to an `Org/Repo` string. |
|
|
39
|
+
| `default_repo` | `Symbol, nil` | `nil` | Repo key used when callers omit the `repo:` param. |
|
|
40
|
+
|
|
41
|
+
```ruby
|
|
42
|
+
config.repos = { element: 'YourOrg/Element', underwriter: 'YourOrg/Underwriter' }
|
|
43
|
+
config.default_repo = :element
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
`repos` can be mutated via `config.repos[:key] = '...'` or set via `config.repos = { key: 'MyOrg/MyRepo' }`
|
|
47
|
+
|
|
48
|
+
## Projects
|
|
49
|
+
|
|
50
|
+
| Option | Type | Default | Description |
|
|
51
|
+
|---|---|---|---|
|
|
52
|
+
| `default_project_number` | `Integer, nil` | `nil` | Default Projects V2 number for `add_to_project: true`. |
|
|
53
|
+
| `testing_template_project_number` | `Integer, nil` | `nil` | Project to clone in `TestingProject.create!` instead of bootstrapping fields. |
|
|
54
|
+
|
|
55
|
+
```ruby
|
|
56
|
+
config.default_project_number = 14
|
|
57
|
+
config.testing_template_project_number = 42
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## App identity
|
|
61
|
+
|
|
62
|
+
| Option | Type | Default | Description |
|
|
63
|
+
|---|---|---|---|
|
|
64
|
+
| `app_name` | `String, nil` | `nil` | Stored in metadata so subscribers can attribute writes. |
|
|
65
|
+
| `issues_url_prefix` | `String, nil` | `nil` | Prefix for `Issue#user_link`; the gem appends the issue number. |
|
|
66
|
+
|
|
67
|
+
```ruby
|
|
68
|
+
config.app_name = 'MyApp'
|
|
69
|
+
|
|
70
|
+
url_options = Rails.application.config.action_mailer.default_url_options
|
|
71
|
+
config.issues_url_prefix = "#{url_options[:protocol] || 'http'}://#{url_options[:host]}/issues"
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## User integration
|
|
75
|
+
|
|
76
|
+
| Option | Type | Default | Description |
|
|
77
|
+
|---|---|---|---|
|
|
78
|
+
| `user_class` | `String` | `'User'` | Consuming app's user model class name, constantized for lookups. |
|
|
79
|
+
| `display_name_method` | `Symbol` | `:to_s` | Method called on a user to get the display name for comment headers. |
|
|
80
|
+
| `user_id_method` | `Symbol` | `:id` | Method called on a user to extract the app-side user ID. |
|
|
81
|
+
| `support_method` | `Symbol, Proc` | `:support?` | Method name on the user, or a proc receiving the user, returning whether they're support staff. |
|
|
82
|
+
| `github_login_for` | `Hash{Object => String}` | `{}` | Maps app user id (from `user_id_method`) to GitHub login. Powers the Take UI. |
|
|
83
|
+
|
|
84
|
+
`support_method` may be a method name on the user object or a proc that receives the user and returns boolean.
|
|
85
|
+
`github_login_for` maps app user id (whatever `user_id_method` returns) to GitHub login and powers the Take UI.
|
|
86
|
+
|
|
87
|
+
```ruby
|
|
88
|
+
config.user_class = 'User'
|
|
89
|
+
config.display_name_method = :full_name
|
|
90
|
+
config.user_id_method = :id
|
|
91
|
+
config.support_method = :support?
|
|
92
|
+
# or: config.support_method = -> (user) { user.role.in?(%w[support admin]) }
|
|
93
|
+
config.github_login_for = {
|
|
94
|
+
1 => 'some_username',
|
|
95
|
+
2 => 'octocat',
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Engine authentication
|
|
100
|
+
|
|
101
|
+
| Option | Type | Default | Description |
|
|
102
|
+
|---|---|---|---|
|
|
103
|
+
| `authenticate_with` | `Proc` | `nil` | Block executed as a `before_action` on every engine controller. |
|
|
104
|
+
|
|
105
|
+
```ruby
|
|
106
|
+
config.authenticate_with do
|
|
107
|
+
redirect_to main_app.login_path unless current_user
|
|
108
|
+
end
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Markdown rendering
|
|
112
|
+
|
|
113
|
+
| Option | Type | Default | Description |
|
|
114
|
+
|---|---|---|---|
|
|
115
|
+
| `markdown_renderer` | `Symbol` | `:commonmarker` | Which markdown gem to use: `:commonmarker`, `:redcarpet`, or `nil` (raw HTML-escaped). |
|
|
116
|
+
| `markdown_options` | `Hash` | `{}` | Default options passed to the renderer. Per-call options merge on top of these. |
|
|
117
|
+
|
|
118
|
+
Set `markdown_renderer` to `:commonmarker`, `:redcarpet`, or `nil` (raw HTML-escaped). The chosen gem must be in your
|
|
119
|
+
Gemfile.
|
|
120
|
+
|
|
121
|
+
```ruby
|
|
122
|
+
config.markdown_renderer = :commonmarker
|
|
123
|
+
config.markdown_options = { render: { hardbreaks: true } }
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Notification actor
|
|
127
|
+
|
|
128
|
+
| Option | Type | Default | Description |
|
|
129
|
+
|---|---|---|---|
|
|
130
|
+
| `current_user` | `Proc, nil` | `nil` | Fallback actor for notification events when `user:` is not passed. |
|
|
131
|
+
|
|
132
|
+
```ruby
|
|
133
|
+
config.current_user = -> { Current.user }
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Controller rescue
|
|
137
|
+
|
|
138
|
+
| Option | Type | Default | Description |
|
|
139
|
+
|---|---|---|---|
|
|
140
|
+
| `controller_rescue` | `Proc, nil` | `nil` | Receives the rescued exception. Forward to your monitoring service. |
|
|
141
|
+
|
|
142
|
+
```ruby
|
|
143
|
+
config.controller_rescue = -> (error) { MonitoringService.notice_error(error) }
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Custom fields
|
|
147
|
+
|
|
148
|
+
App-defined fields stored in metadata. Keys are field names; values are hashes with `:type` and `:required`.
|
|
149
|
+
Supported types: `:string`, `:integer`, `:boolean`, `:array`, `:hash`.
|
|
150
|
+
|
|
151
|
+
| Option | Type | Default | Description |
|
|
152
|
+
|---|---|---|---|
|
|
153
|
+
| `custom_fields` | `Hash{Symbol => Hash}` | `{}` | Shared field definitions across all contexts. |
|
|
154
|
+
| `issue_custom_fields` | `Hash{Symbol => Hash}` | `{}` | Issue-only definitions; merged on top of shared. |
|
|
155
|
+
| `comment_custom_fields` | `Hash{Symbol => Hash}` | `{}` | Comment-only definitions; merged on top of shared. |
|
|
156
|
+
| `project_custom_fields` | `Hash{Symbol => Hash}` | `{}` | Project-only definitions; merged on top of shared. |
|
|
157
|
+
| `testing_custom_fields` | `Hash{Symbol => Hash}` | `{}` | Testing-project-only definitions; merged on top of shared. |
|
|
158
|
+
|
|
159
|
+
Context-specific config wins on key conflicts.
|
|
160
|
+
|
|
161
|
+
```ruby
|
|
162
|
+
config.custom_fields = {
|
|
163
|
+
notification_recipients: { type: :array, required: true },
|
|
164
|
+
}
|
|
165
|
+
config.issue_custom_fields = {
|
|
166
|
+
ticket_type: { type: :string, required: true },
|
|
167
|
+
}
|
|
168
|
+
config.comment_custom_fields = {
|
|
169
|
+
internal_note: { type: :boolean },
|
|
170
|
+
}
|
|
171
|
+
config.project_custom_fields = {
|
|
172
|
+
team: { type: :string },
|
|
173
|
+
}
|
|
174
|
+
config.testing_custom_fields = {
|
|
175
|
+
test_plan_url: { type: :string },
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
## Issue types
|
|
180
|
+
|
|
181
|
+
| Option | Type | Default | Description |
|
|
182
|
+
|---|---|---|---|
|
|
183
|
+
| `issue_types` | `Hash{String => String}` | `{}` | Maps the gem's canonical issue type names to your org's display names. |
|
|
184
|
+
|
|
185
|
+
Maps the gem's canonical type names (`'Bug'`, `'Feature'`, `'IT Issue / Hardware'`, `'Other'`, `'Performance'`,
|
|
186
|
+
`'Question'`, `'Task'`) to whatever your org uses. Missing keys pass through unchanged.
|
|
187
|
+
|
|
188
|
+
```ruby
|
|
189
|
+
config.issue_types = {
|
|
190
|
+
'Bug' => 'User Bug',
|
|
191
|
+
'Feature' => 'Enhancement',
|
|
192
|
+
}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
## Release pipeline
|
|
196
|
+
|
|
197
|
+
| Option | Type | Default | Description |
|
|
198
|
+
|---|---|---|---|
|
|
199
|
+
| `pipeline_enabled` | `Boolean` | `true` | Whether the release pipeline feature is enabled. |
|
|
200
|
+
| `pipeline_project_number` | `Integer, nil` | `nil` | Projects V2 number for the pipeline board. Falls back to `default_project_number`. |
|
|
201
|
+
| `webhook_secret` | `String, nil` | `nil` | HMAC secret for GitHub webhook signature verification. Required when webhook routes are mounted. |
|
|
202
|
+
| `pipeline_statuses` | `Hash{String => String}` | `{}` | Display aliases for canonical pipeline status names. |
|
|
203
|
+
| `pipeline_testing_field_name` | `String` | `'Testing'` | Display name for the pipeline project's `Testing` single-select field. |
|
|
204
|
+
| `pipeline_testing_values` | `Hash{Symbol => String}` | `{ active: 'Testing', inactive: 'Not testing' }` | Display labels for the canonical `:active`/`:inactive` testing options. |
|
|
205
|
+
| `pipeline_completion_purge_enabled` | `Boolean` | `true` | Whether the sweep removes aged-out `Completed` items from the pipeline. |
|
|
206
|
+
| `pipeline_completion_ttl_hours` | `Integer` | `24` | Hours after a `Completed` item's last update at which the sweep removes it. |
|
|
207
|
+
| `main_branch` | `String` | `'main'` | Branch PRs merge into for the "Ready for Release" transition. |
|
|
208
|
+
| `production_branch` | `String` | `'production'` | Branch PRs mereg into for the "Release in Progress" transition. |
|
|
209
|
+
|
|
210
|
+
`pipeline_statuses` aliases the canonical status names (`'Submitted'`, `'Started'`, `'In Review'`, `'Testing'`,
|
|
211
|
+
`'Ready for Release'`, `'Release in Progress'`, `'Completed'`) for display only. The constants remain the internal
|
|
212
|
+
identifiers.
|
|
213
|
+
|
|
214
|
+
`pipeline_completion_*` controls the sweep that removes aged-out `Completed` items from the pipeline. `webhook_secret`
|
|
215
|
+
is required when webhook routes are mounted.
|
|
216
|
+
|
|
217
|
+
```ruby
|
|
218
|
+
config.pipeline_enabled = true
|
|
219
|
+
config.pipeline_project_number = 14
|
|
220
|
+
config.webhook_secret = Rails.application.credentials.dig(:plan_my_stuff, :webhook_secret)
|
|
221
|
+
config.pipeline_statuses = {
|
|
222
|
+
'Submitted' => 'Triaged',
|
|
223
|
+
'Completed' => 'Done',
|
|
224
|
+
}
|
|
225
|
+
config.pipeline_testing_field_name = 'Testing'
|
|
226
|
+
config.pipeline_testing_values = { active: 'Testing', inactive: 'Not testing' }
|
|
227
|
+
config.pipeline_completion_purge_enabled = true
|
|
228
|
+
config.pipeline_completion_ttl_hours = 24
|
|
229
|
+
config.main_branch = 'main'
|
|
230
|
+
config.production_branch = 'production'
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
## Follow-up reminders
|
|
234
|
+
|
|
235
|
+
| Option | Type | Default | Description |
|
|
236
|
+
|---|---|---|---|
|
|
237
|
+
| `reminders_enabled` | `Boolean` | `true` | Whether the reminders sweep performs any work. |
|
|
238
|
+
| `reminder_days` | `Array<Integer>` | `[1, 3, 7, 10, 14, 18]` | Days-since-waiting at which reminder events fire. |
|
|
239
|
+
| `inactivity_close_days` | `Integer` | `30` | Days of inactivity after which the sweep auto-closes a waiting issue. |
|
|
240
|
+
| `waiting_on_user_label` | `String` | `'waiting-on-user'` | Label flagging issues waiting on an end-user reply. |
|
|
241
|
+
| `waiting_on_approval_label` | `String` | `'waiting-on-approval'` | Label flagging issues waiting on pending approvals. |
|
|
242
|
+
| `user_inactive_label` | `String` | `'user-inactive'` | Label applied to issues auto-closed by the inactivity sweep; removed when an issue is auto-reopened via a user reply. |
|
|
243
|
+
|
|
244
|
+
Per-issue reminder override: `issue.metadata.reminder_days = [...]`.
|
|
245
|
+
|
|
246
|
+
```ruby
|
|
247
|
+
config.reminders_enabled = true
|
|
248
|
+
config.reminder_days = [1, 3, 7, 10, 14, 18]
|
|
249
|
+
config.inactivity_close_days = 30
|
|
250
|
+
config.waiting_on_user_label = 'waiting-on-user'
|
|
251
|
+
config.waiting_on_approval_label = 'waiting-on-approval'
|
|
252
|
+
config.user_inactive_label = 'user-inactive'
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
## Auto-archiving
|
|
256
|
+
|
|
257
|
+
| Option | Type | Default | Description |
|
|
258
|
+
|---|---|---|---|
|
|
259
|
+
| `archiving_enabled` | `Boolean` | `true` | Whether the archive sweep performs any work. |
|
|
260
|
+
| `archive_closed_after_days` | `Integer` | `90` | Days after `closed_at` at which a non-inactive-closed issue becomes an archive candidate. |
|
|
261
|
+
| `archived_label` | `String` | `'archived'` | Label added to archived issues; also used by the sweep as a skip marker. |
|
|
262
|
+
|
|
263
|
+
The archive sweep piggybacks `RemindersSweepJob`. Inactivity-closed and non-PMS issues are excluded.
|
|
264
|
+
|
|
265
|
+
```ruby
|
|
266
|
+
config.archiving_enabled = true
|
|
267
|
+
config.archive_closed_after_days = 90
|
|
268
|
+
config.archived_label = 'archived'
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
## AWS webhook
|
|
272
|
+
|
|
273
|
+
| Option | Type | Default | Description |
|
|
274
|
+
|---|---|---|---|
|
|
275
|
+
| `sns_topic_arn` | `String, nil` | `nil` | Expected SNS topic ARN for AWS webhook validation. |
|
|
276
|
+
| `aws_service_identifier` | `String, nil` | `nil` | Suffix matched against ECS event resource ARNs (e.g. `'my-app-production-2-web-server'`). |
|
|
277
|
+
| `production_commit_sha` | `String, nil` | `nil` | Prefix-matched against issue metadata `commit_sha` on `SERVICE_DEPLOYMENT_COMPLETED` events. |
|
|
278
|
+
| `process_aws_webhooks` | `Boolean` | `Rails.env.production?` | Whether to process incoming AWS webhook events. |
|
|
279
|
+
| `sns_verifier_class` | `Class` | `Aws::SNS::MessageVerifier` (when defined) | Class instantiated per request for SNS signature verification. Must respond to `authenticate!(raw_body)`. |
|
|
280
|
+
| `sns_verifier_error` | `Class` | `Aws::SNS::MessageVerifier::VerificationError` (when defined) | Exception class rescued during SNS signature verification. |
|
|
281
|
+
|
|
282
|
+
`production_commit_sha` is prefix-matched against issue metadata `commit_sha` on `SERVICE_DEPLOYMENT_COMPLETED` events.
|
|
283
|
+
`sns_verifier_class` must respond to `authenticate!(raw_body)`.
|
|
284
|
+
|
|
285
|
+
```ruby
|
|
286
|
+
config.sns_topic_arn = 'arn:aws:sns:us-east-1:123456:ecs-deploy-topic'
|
|
287
|
+
config.aws_service_identifier = 'myapp-production-web'
|
|
288
|
+
config.production_commit_sha = Rails.configuration.x.image_tag
|
|
289
|
+
config.process_aws_webhooks = Rails.env.production?
|
|
290
|
+
config.sns_verifier_class = Aws::SNS::MessageVerifier
|
|
291
|
+
config.sns_verifier_error = Aws::SNS::MessageVerifier::VerificationError
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
## Caching
|
|
295
|
+
|
|
296
|
+
| Option | Type | Default | Description |
|
|
297
|
+
|---|---|---|---|
|
|
298
|
+
| `cache_enabled` | `Boolean` | `true` | ETag-based HTTP caching of GitHub reads via `Rails.cache`. |
|
|
299
|
+
| `cache_version` | `String, nil` | `nil` | Opaque string baked into every PMS cache key; bump to invalidate. |
|
|
300
|
+
|
|
301
|
+
```ruby
|
|
302
|
+
config.cache_enabled = true
|
|
303
|
+
config.cache_version = Rails.configuration.x.image_tag
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
## Route mounting
|
|
307
|
+
|
|
308
|
+
| Option | Type | Default | Description |
|
|
309
|
+
|---|---|---|---|
|
|
310
|
+
| `mount_groups` | `Hash{Symbol => Boolean}` | `{ webhooks: true, issues: true, projects: true }` | Per-group route mounting toggles. Set a key to `false` to skip mounting that group. |
|
|
311
|
+
|
|
312
|
+
```ruby
|
|
313
|
+
config.mount_groups = { webhooks: true, issues: true, projects: true }
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
## Controller overrides
|
|
317
|
+
|
|
318
|
+
| Option | Type | Default | Description |
|
|
319
|
+
|---|---|---|---|
|
|
320
|
+
| `controllers` | `Hash{Symbol => String}` | `{}` | Per-route controller overrides. Keys are controllable route symbols; values are fully-qualified controller paths. |
|
|
321
|
+
|
|
322
|
+
Per-route controller overrides. Keys are the controllable route symbols defined in
|
|
323
|
+
`PlanMyStuff::Configuration::DEFAULT_CONTROLLERS`; values are fully-qualified controller paths. Unset keys fall back to
|
|
324
|
+
the gem default.
|
|
325
|
+
|
|
326
|
+
```ruby
|
|
327
|
+
config.controllers[:issues] = 'my_app/issues'
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
Controllable keys (with gem defaults):
|
|
331
|
+
|
|
332
|
+
| Key | Default |
|
|
333
|
+
|---|---|
|
|
334
|
+
| `:issues` | `plan_my_stuff/issues` |
|
|
335
|
+
| `:comments` | `plan_my_stuff/comments` |
|
|
336
|
+
| `:labels` | `plan_my_stuff/labels` |
|
|
337
|
+
| `:projects` | `plan_my_stuff/projects` |
|
|
338
|
+
| `:project_items` | `plan_my_stuff/project_items` |
|
|
339
|
+
| `:testing_projects` | `plan_my_stuff/testing_projects` |
|
|
340
|
+
| `:testing_project_items` | `plan_my_stuff/testing_project_items` |
|
|
341
|
+
| `:'issues/closures'` | `plan_my_stuff/issues/closures` |
|
|
342
|
+
| `:'issues/viewers'` | `plan_my_stuff/issues/viewers` |
|
|
343
|
+
| `:'issues/takes'` | `plan_my_stuff/issues/takes` |
|
|
344
|
+
| `:'issues/waitings'` | `plan_my_stuff/issues/waitings` |
|
|
345
|
+
| `:'issues/links'` | `plan_my_stuff/issues/links` |
|
|
346
|
+
| `:'issues/approvals'` | `plan_my_stuff/issues/approvals` |
|
|
347
|
+
| `:'project_items/statuses'` | `plan_my_stuff/project_items/statuses` |
|
|
348
|
+
| `:'project_items/assignments'` | `plan_my_stuff/project_items/assignments` |
|
|
349
|
+
| `:'testing_project_items/results'` | `plan_my_stuff/testing_project_items/results` |
|
|
350
|
+
| `:'webhooks/github'` | `plan_my_stuff/webhooks/github` |
|
|
351
|
+
| `:'webhooks/aws'` | `plan_my_stuff/webhooks/aws` |
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
<%= button_to('Take', plan_my_stuff.issue_take_path(@issue.number, repo: @issue.repo.full_name), method: :post) %>
|
|
22
22
|
<% end %>
|
|
23
23
|
<% if @support_user && @pipeline_enabled && @current_user_login.present? && @issue.assignees.include?(@current_user_login) %>
|
|
24
|
-
<%= button_to('
|
|
24
|
+
<%= button_to('Unassign', plan_my_stuff.issue_take_path(@issue.number, repo: @issue.repo.full_name), method: :delete) %>
|
|
25
25
|
<% end %>
|
|
26
26
|
<% if @support_user %>
|
|
27
27
|
<%= link_to('Start Testing Project', plan_my_stuff.new_testing_project_path(subject_url: @issue.html_url)) %>
|
|
@@ -106,19 +106,8 @@ PlanMyStuff.configure do |config|
|
|
|
106
106
|
# "#{url_options[:protocol] || 'http'}://#{url_options[:host]}/issues"
|
|
107
107
|
|
|
108
108
|
# --------------------------------------------------------------------------
|
|
109
|
-
#
|
|
109
|
+
# Notification actor
|
|
110
110
|
# --------------------------------------------------------------------------
|
|
111
|
-
# Proc returning boolean, or nil (always send). When it returns false the
|
|
112
|
-
# request is deferred to a background job instead of hitting GitHub.
|
|
113
|
-
# config.should_send_request = -> { !MaintenanceMode.active? }
|
|
114
|
-
|
|
115
|
-
# Map of action type to job class name for deferred requests.
|
|
116
|
-
# config.job_classes = {
|
|
117
|
-
# create_ticket: 'PmsCreateTicketJob',
|
|
118
|
-
# post_comment: 'PmsPostCommentJob',
|
|
119
|
-
# update_status: 'PmsUpdateStatusJob'
|
|
120
|
-
# }
|
|
121
|
-
|
|
122
111
|
# Fallback actor for notification events (plan_my_stuff.*) when a caller
|
|
123
112
|
# does not pass an explicit user: kwarg. Proc/lambda called at event time.
|
|
124
113
|
# config.current_user = -> { Current.user }
|
|
@@ -32,6 +32,8 @@ module PlanMyStuff
|
|
|
32
32
|
class << self
|
|
33
33
|
# Creates a comment on a GitHub issue with PMS metadata and a visible header.
|
|
34
34
|
#
|
|
35
|
+
# @raise [PlanMyStuff::LockedIssueError] if the parent issue is locked
|
|
36
|
+
#
|
|
35
37
|
# @param issue [PlanMyStuff::Issue] parent issue
|
|
36
38
|
# @param body [String]
|
|
37
39
|
# @param user [Object, Integer] user object or user_id
|
|
@@ -41,8 +43,6 @@ module PlanMyStuff
|
|
|
41
43
|
# @param waiting_on_reply [Boolean] when true and the author is a support user, marks the issue as waiting on
|
|
42
44
|
# an end-user reply. Ignored for non-support authors.
|
|
43
45
|
#
|
|
44
|
-
# @raise [PlanMyStuff::LockedIssueError] if the parent issue is locked
|
|
45
|
-
#
|
|
46
46
|
# @return [PlanMyStuff::Comment]
|
|
47
47
|
#
|
|
48
48
|
def create!(
|
|
@@ -279,7 +279,9 @@ module PlanMyStuff
|
|
|
279
279
|
)
|
|
280
280
|
hydrate_from_comment(created)
|
|
281
281
|
else
|
|
282
|
-
|
|
282
|
+
update_attrs = { user: user, body: body }
|
|
283
|
+
update_attrs[:visibility] = visibility if visibility_changed?
|
|
284
|
+
update!(**update_attrs)
|
|
283
285
|
end
|
|
284
286
|
|
|
285
287
|
self
|
|
@@ -84,19 +84,6 @@ module PlanMyStuff
|
|
|
84
84
|
#
|
|
85
85
|
attr_accessor :markdown_options
|
|
86
86
|
|
|
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.
|
|
89
|
-
#
|
|
90
|
-
# @return [Proc, nil]
|
|
91
|
-
#
|
|
92
|
-
attr_accessor :should_send_request
|
|
93
|
-
|
|
94
|
-
# Map of action type to job class name for deferred requests. Keys: :create_ticket, :post_comment, :update_status.
|
|
95
|
-
#
|
|
96
|
-
# @return [Hash{Symbol => String}]
|
|
97
|
-
#
|
|
98
|
-
attr_accessor :job_classes
|
|
99
|
-
|
|
100
87
|
# Fallback actor for notification events when a caller does not pass +user:+. Set to a proc/lambda that returns the
|
|
101
88
|
# current request user.
|
|
102
89
|
#
|
|
@@ -344,11 +331,12 @@ module PlanMyStuff
|
|
|
344
331
|
#
|
|
345
332
|
attr_accessor :sns_verifier_error
|
|
346
333
|
|
|
347
|
-
# 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' }.
|
|
348
336
|
#
|
|
349
337
|
# @return [Hash{Symbol => String}]
|
|
350
338
|
#
|
|
351
|
-
|
|
339
|
+
attr_accessor :repos
|
|
352
340
|
|
|
353
341
|
# @return [Configuration]
|
|
354
342
|
def initialize
|
|
@@ -359,7 +347,6 @@ module PlanMyStuff
|
|
|
359
347
|
@support_method = :support?
|
|
360
348
|
@markdown_renderer = :commonmarker
|
|
361
349
|
@markdown_options = {}
|
|
362
|
-
@job_classes = {}
|
|
363
350
|
@custom_fields = {}
|
|
364
351
|
@issue_custom_fields = {}
|
|
365
352
|
@comment_custom_fields = {}
|
data/lib/plan_my_stuff/issue.rb
CHANGED
|
@@ -363,7 +363,11 @@ module PlanMyStuff
|
|
|
363
363
|
canonical =
|
|
364
364
|
case value
|
|
365
365
|
when String
|
|
366
|
-
|
|
366
|
+
begin
|
|
367
|
+
resolve_issue_type!(value.to_sym)
|
|
368
|
+
rescue ArgumentError
|
|
369
|
+
value
|
|
370
|
+
end
|
|
367
371
|
when Symbol
|
|
368
372
|
ISSUE_TYPE_NICKNAMES[value] || raise(
|
|
369
373
|
ArgumentError,
|
data/lib/plan_my_stuff/label.rb
CHANGED
|
@@ -48,7 +48,7 @@ module PlanMyStuff
|
|
|
48
48
|
client = PlanMyStuff.client
|
|
49
49
|
client.rest(:label, repo, name)
|
|
50
50
|
rescue PlanMyStuff::APIError => e
|
|
51
|
-
raise unless e.status == 404
|
|
51
|
+
raise(e) unless e.status == 404
|
|
52
52
|
|
|
53
53
|
create_label!(client, repo, name, color, description)
|
|
54
54
|
end
|
|
@@ -62,11 +62,11 @@ module PlanMyStuff
|
|
|
62
62
|
#
|
|
63
63
|
# @return [Boolean]
|
|
64
64
|
#
|
|
65
|
-
def exists?(repo:, name:)
|
|
65
|
+
def exists?(repo:, name:, do_raise: true)
|
|
66
66
|
PlanMyStuff.client.rest(:label, repo, name)
|
|
67
67
|
true
|
|
68
68
|
rescue PlanMyStuff::APIError => e
|
|
69
|
-
raise
|
|
69
|
+
raise(e) if do_raise && e.status != 404
|
|
70
70
|
|
|
71
71
|
false
|
|
72
72
|
end
|
|
@@ -115,7 +115,7 @@ module PlanMyStuff
|
|
|
115
115
|
|
|
116
116
|
client.rest(:add_label, repo, name, color, **options)
|
|
117
117
|
rescue PlanMyStuff::APIError => e
|
|
118
|
-
raise unless e.status == 422
|
|
118
|
+
raise(e) unless e.status == 422
|
|
119
119
|
end
|
|
120
120
|
|
|
121
121
|
# Hydrates a Label from a GitHub API response.
|
|
@@ -46,7 +46,7 @@ namespace :plan_my_stuff do
|
|
|
46
46
|
url = ENV.fetch('URL') { raise(ArgumentError, 'URL env var is required') }
|
|
47
47
|
repo = ENV.fetch('REPO') do
|
|
48
48
|
PlanMyStuff.client.resolve_repo!
|
|
49
|
-
rescue
|
|
49
|
+
rescue PlanMyStuff::ConfigurationError, ArgumentError
|
|
50
50
|
raise(ArgumentError, 'REPO env var is required or configured (e.g. BrandsInsurance/PlanMyStuff)')
|
|
51
51
|
end
|
|
52
52
|
default_events = %w[pull_request issues]
|
|
@@ -94,7 +94,7 @@ namespace :plan_my_stuff do
|
|
|
94
94
|
end
|
|
95
95
|
|
|
96
96
|
desc 'Continuously poll org + repo hooks and auto-replay new deliveries ' \
|
|
97
|
-
'(ENDPOINT_URL=... [ORG_WEBHOOK_URL=...] [REPO_WEBHOOK_URL=... REPO=owner/name] [INTERVAL=
|
|
97
|
+
'(ENDPOINT_URL=... [ORG_WEBHOOK_URL=...] [REPO_WEBHOOK_URL=... REPO=owner/name] [INTERVAL=30]). ' \
|
|
98
98
|
'At least one of ORG_WEBHOOK_URL or REPO_WEBHOOK_URL is required (raises ArgumentError if both absent).'
|
|
99
99
|
task listen: :environment do
|
|
100
100
|
require 'plan_my_stuff/webhook_replayer'
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: plan_my_stuff
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.9.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Brands Insurance
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-05-01 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rails
|
|
@@ -52,6 +52,7 @@ extensions: []
|
|
|
52
52
|
extra_rdoc_files: []
|
|
53
53
|
files:
|
|
54
54
|
- CHANGELOG.md
|
|
55
|
+
- CONFIGURATION.md
|
|
55
56
|
- LICENSE
|
|
56
57
|
- README.md
|
|
57
58
|
- app/controllers/plan_my_stuff/application_controller.rb
|