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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +46 -1
- data/CONFIGURATION.md +351 -0
- data/README.md +100 -103
- data/app/controllers/plan_my_stuff/application_controller.rb +22 -3
- data/app/controllers/plan_my_stuff/comments_controller.rb +14 -16
- data/app/controllers/plan_my_stuff/issues/approvals_controller.rb +23 -13
- data/app/controllers/plan_my_stuff/issues/closures_controller.rb +7 -5
- data/app/controllers/plan_my_stuff/issues/links_controller.rb +14 -18
- data/app/controllers/plan_my_stuff/issues/takes_controller.rb +99 -28
- data/app/controllers/plan_my_stuff/issues/viewers_controller.rb +13 -5
- data/app/controllers/plan_my_stuff/issues/waitings_controller.rb +7 -5
- data/app/controllers/plan_my_stuff/issues_controller.rb +24 -28
- data/app/controllers/plan_my_stuff/labels_controller.rb +21 -5
- data/app/controllers/plan_my_stuff/project_items/assignments_controller.rb +13 -6
- data/app/controllers/plan_my_stuff/project_items/statuses_controller.rb +5 -4
- data/app/controllers/plan_my_stuff/project_items_controller.rb +30 -5
- data/app/controllers/plan_my_stuff/projects_controller.rb +16 -16
- data/app/controllers/plan_my_stuff/testing_project_items/results_controller.rb +21 -11
- data/app/controllers/plan_my_stuff/testing_project_items_controller.rb +9 -4
- data/app/controllers/plan_my_stuff/testing_projects_controller.rb +30 -14
- data/app/controllers/plan_my_stuff/webhooks/aws_controller.rb +50 -17
- data/app/controllers/plan_my_stuff/webhooks/github_controller.rb +32 -49
- data/app/jobs/plan_my_stuff/application_job.rb +2 -3
- data/app/jobs/plan_my_stuff/reminders_sweep_job.rb +15 -22
- data/app/views/plan_my_stuff/comments/edit.html.erb +1 -3
- data/app/views/plan_my_stuff/comments/partials/_form.html.erb +1 -0
- data/app/views/plan_my_stuff/issues/edit.html.erb +2 -4
- data/app/views/plan_my_stuff/issues/index.html.erb +2 -2
- data/app/views/plan_my_stuff/issues/new.html.erb +2 -4
- data/app/views/plan_my_stuff/issues/partials/_approvals.html.erb +23 -2
- data/app/views/plan_my_stuff/issues/partials/_form.html.erb +1 -0
- data/app/views/plan_my_stuff/issues/partials/_labels.html.erb +2 -1
- data/app/views/plan_my_stuff/issues/partials/_links.html.erb +50 -7
- data/app/views/plan_my_stuff/issues/partials/_viewers.html.erb +2 -1
- data/app/views/plan_my_stuff/issues/show.html.erb +5 -2
- data/app/views/plan_my_stuff/partials/_flash.html.erb +3 -0
- data/app/views/plan_my_stuff/projects/edit.html.erb +1 -3
- data/app/views/plan_my_stuff/projects/index.html.erb +1 -1
- data/app/views/plan_my_stuff/projects/new.html.erb +1 -3
- data/app/views/plan_my_stuff/projects/partials/_form.html.erb +1 -0
- data/app/views/plan_my_stuff/projects/show.html.erb +13 -3
- data/app/views/plan_my_stuff/testing_project_items/new.html.erb +1 -3
- data/app/views/plan_my_stuff/testing_project_items/results/new.html.erb +1 -3
- data/app/views/plan_my_stuff/testing_projects/edit.html.erb +1 -3
- data/app/views/plan_my_stuff/testing_projects/new.html.erb +1 -3
- data/app/views/plan_my_stuff/testing_projects/partials/_form.html.erb +4 -3
- data/app/views/plan_my_stuff/testing_projects/partials/_item.html.erb +1 -0
- data/app/views/plan_my_stuff/testing_projects/partials/items/_form.html.erb +1 -0
- data/app/views/plan_my_stuff/testing_projects/show.html.erb +2 -2
- data/config/routes.rb +2 -2
- data/lib/generators/plan_my_stuff/install/templates/initializer.rb +52 -14
- data/lib/plan_my_stuff/approval.rb +12 -4
- data/lib/plan_my_stuff/aws_sns_simulator.rb +12 -6
- data/lib/plan_my_stuff/base_metadata.rb +4 -15
- data/lib/plan_my_stuff/base_project.rb +68 -55
- data/lib/plan_my_stuff/base_project_item.rb +62 -57
- data/lib/plan_my_stuff/base_project_metadata.rb +1 -1
- data/lib/plan_my_stuff/client.rb +136 -48
- data/lib/plan_my_stuff/comment.rb +59 -57
- data/lib/plan_my_stuff/comment_metadata.rb +1 -1
- data/lib/plan_my_stuff/configuration.rb +93 -93
- data/lib/plan_my_stuff/errors.rb +10 -10
- data/lib/plan_my_stuff/graphql/queries.rb +1 -1
- data/lib/plan_my_stuff/issue.rb +471 -333
- data/lib/plan_my_stuff/issue_metadata.rb +10 -10
- data/lib/plan_my_stuff/label.rb +34 -18
- data/lib/plan_my_stuff/link.rb +15 -15
- data/lib/plan_my_stuff/markdown.rb +12 -6
- data/lib/plan_my_stuff/metadata_parser.rb +3 -1
- data/lib/plan_my_stuff/notifications.rb +1 -1
- data/lib/plan_my_stuff/pipeline/completed_sweep.rb +2 -2
- data/lib/plan_my_stuff/pipeline/issue_linker.rb +1 -1
- data/lib/plan_my_stuff/pipeline.rb +61 -83
- data/lib/plan_my_stuff/project.rb +4 -4
- data/lib/plan_my_stuff/project_item_metadata.rb +1 -1
- data/lib/plan_my_stuff/project_metadata.rb +1 -1
- data/lib/plan_my_stuff/reminders/closer.rb +1 -1
- data/lib/plan_my_stuff/reminders/fire.rb +3 -3
- data/lib/plan_my_stuff/reminders/sweep.rb +4 -4
- data/lib/plan_my_stuff/repo.rb +12 -6
- data/lib/plan_my_stuff/test_helpers.rb +11 -11
- data/lib/plan_my_stuff/testing_project.rb +12 -11
- data/lib/plan_my_stuff/testing_project_item.rb +11 -9
- data/lib/plan_my_stuff/testing_project_metadata.rb +2 -2
- data/lib/plan_my_stuff/version.rb +1 -1
- data/lib/plan_my_stuff/webhook_replayer.rb +14 -2
- data/lib/plan_my_stuff.rb +26 -2
- data/lib/tasks/plan_my_stuff.rake +33 -20
- metadata +4 -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,50 @@
|
|
|
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
|
+
|
|
18
|
+
## 0.8.0
|
|
19
|
+
|
|
20
|
+
### Breaking
|
|
21
|
+
|
|
22
|
+
- Issue show "Take" button is now hidden when the issue already has assignees, and `Issues::TakesController#create` rejects the request with a flash error naming the existing assignee. Best-effort race guard for two users clicking Take simultaneously — without it, GitHub silently piles the second user on as a co-assignee.
|
|
23
|
+
- Guard lives in the controller, not `Pipeline.take!` itself, because webhook paths (`handle_issue_assigned`, `handle_projects_v2_item`, `handle_draft_opened`, `handle_converted_to_draft`) legitimately call `take!` on already-assigned issues
|
|
24
|
+
- `Issue#add_viewers` / `Issue#remove_viewers` renamed to `Issue#add_viewers!` / `Issue#remove_viewers!` for consistency with other mutating instance methods (`approve!`, `close!`, etc.)
|
|
25
|
+
- `Approval#status` extended to a 3-state model (`pending`, `approved`, `rejected`); `Approval` gains a `rejected_at` attribute serialized in `to_h` and the metadata blob. Existing approvals deserialize unchanged (`rejected_at` defaults to `nil`)
|
|
26
|
+
- `Issue#fully_approved?` now requires every approver to be `approved` — a single rejection blocks the gate until revoked. Previously equivalent to `pending_approvals.empty?`, which silently treated rejections as "done"
|
|
27
|
+
- `Issue#revoke_approval!` accepts either an `approved` or `rejected` source state (previously only `approved`); raises `ValidationError` when the target is still `pending`. Authorization error message updated to "another user's response"
|
|
28
|
+
|
|
29
|
+
### Added
|
|
30
|
+
|
|
31
|
+
- `CONFIGURATION.md` documents every `PlanMyStuff::Configuration` option grouped by concern; `README.md` Configuration section trimmed to the two required options plus a link
|
|
32
|
+
- Install generator's initializer template now includes the four pipeline options previously missing from it: `pipeline_testing_field_name`, `pipeline_testing_values`, `pipeline_completion_purge_enabled`, `pipeline_completion_ttl_hours`
|
|
33
|
+
- Project show "Remove from project" button (and `DELETE /projects/:project_id/items/:id` route on `ProjectItemsController`) lets the user remove an item from a project board without bouncing out to GitHub. Calls `ProjectItem#destroy!` which fires `plan_my_stuff.project_item.removed`
|
|
34
|
+
- Issue show "Release" button (and `DELETE /issues/:issue_id/take` route on `Issues::TakesController`) lets a dev who took an issue undo their assignment from the same view, without bouncing out to GitHub or the project board. When the current user is the sole assignee the issue's GitHub assignees are cleared and the project item is removed from the pipeline (`project_item.destroy!`); when other assignees remain the current user is unassigned via `project_item.assign!(remaining)` and the item stays on the project
|
|
35
|
+
- `config.import_access_token` classic PAT (requires `repo` scope) used exclusively for the Issues Import API (`golden-comet-preview`); fine-grained tokens are not supported by that endpoint. Optional — defaults to `nil`
|
|
36
|
+
- `Issue.import!(payloads)` POSTs an `Array<Hash>` (one POST per payload) to GitHub's "Import Issues" preview endpoint and returns one status hash per input. Each payload must include `:repo` plus the GitHub-shaped `:issue` / `:comments` keys; payloads are passed through unchanged otherwise
|
|
37
|
+
- `Issue.check_import!(import_id, repo:)` polls a previously-submitted import for its status
|
|
38
|
+
- `Issue#created_at` / `Comment#created_at` attributes hydrated from GitHub's `created_at` field
|
|
39
|
+
- `Issue#issue_type` reader hydrated from GitHub's native `type.name`. `Issue.create!` and `Issue.update!` accept an `issue_type:` kwarg as a String (passed through), Symbol shortcut (`:bug`, `:feature`, `:it_issue`, `:other`, `:performance`, `:question`, `:task`), or `nil`. On `update!`, omitting the kwarg leaves the type untouched; passing `nil` clears it
|
|
40
|
+
- `config.issue_types` Hash{String => String} maps canonical type names to org-specific display names so consuming apps can rename without touching call sites (e.g. `{ 'Feature' => 'Enhancement' }`); missing keys pass through unchanged
|
|
41
|
+
- `config.controller_rescue` Proc invoked from every user-facing controller `rescue` block (after the gem logs the error and stack trace) so consuming apps can forward swallowed errors to their monitoring service
|
|
42
|
+
- `Issue#reject!(user:)` symmetric with `approve!`; accepts either `pending` or `approved` source state and raises `ValidationError` when already rejected. Fires `plan_my_stuff.issue.approval_rejected` and, when the flip drops the issue out of `fully_approved?`, `approvals_invalidated(trigger: :rejected)`
|
|
43
|
+
- `Issue#approve!` now accepts either `pending` or `rejected` source state; raises `ValidationError` only on `approved -> approved`. Clears `rejected_at` on the rejected -> approved transition
|
|
44
|
+
- `Issue#rejected_approvals` reader returns the subset of approvers with `status == 'rejected'`
|
|
45
|
+
- New events: `plan_my_stuff.issue.approval_rejected` and `plan_my_stuff.issue.rejection_revoked` (the latter fires when revoking a rejection back to pending)
|
|
46
|
+
- Approvals partial renders a `Reject` button alongside `Approve` for pending approvers, a `rejected at <ts>` row, a parenthetical rejected count in the header, and a `Revoke` button for either non-pending state
|
|
47
|
+
|
|
3
48
|
## 0.7.0
|
|
4
49
|
|
|
5
50
|
### Added
|
|
@@ -17,7 +62,7 @@
|
|
|
17
62
|
- `Pipeline.submit!` removed; consuming apps that called it directly should switch to `ProjectItem.create!` + `Pipeline.take!`
|
|
18
63
|
- `Pipeline::Status::SUBMITTED` and `Pipeline::Status::TESTING` constants removed; `Status::ALL` no longer includes them
|
|
19
64
|
- `Pipeline.request_testing!` no longer moves the `Status` field — it now writes to a separate `Testing` single-select custom field on the pipeline project. The pipeline project must have a `Testing` field with `Testing` / `Not testing` options
|
|
20
|
-
- Active pipeline status set is now `Started
|
|
65
|
+
- Active pipeline status set is now `Started -> In Review -> Ready for Release -> Release in Progress -> Completed`
|
|
21
66
|
|
|
22
67
|
### Added
|
|
23
68
|
|
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` |
|