plan_my_stuff 0.10.2 → 0.10.5
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 +37 -0
- data/CONFIGURATION.md +14 -1
- data/app/controllers/plan_my_stuff/application_controller.rb +1 -1
- data/lib/generators/plan_my_stuff/install/templates/initializer.rb +8 -1
- data/lib/plan_my_stuff/base_project_extractions/graphql_hydration.rb +3 -1
- data/lib/plan_my_stuff/base_project_item.rb +3 -0
- data/lib/plan_my_stuff/configuration.rb +11 -0
- data/lib/plan_my_stuff/graphql/queries.rb +13 -2
- data/lib/plan_my_stuff/issue.rb +1 -10
- data/lib/plan_my_stuff/test_helpers.rb +10 -2
- data/lib/plan_my_stuff/verifier.rb +10 -0
- data/lib/plan_my_stuff/version.rb +1 -1
- data/lib/tasks/plan_my_stuff.rake +26 -0
- metadata +6 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ce0e2f02e6063ab2fe3238671d06182fc5447f428e6dc01d336ba6e00379e86a
|
|
4
|
+
data.tar.gz: f80f58ce32e19ea6e7b8aca34a62110379e6ea65f10c943fd108c409ec50a669
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3aaf1478091d45cbf8caa72a8a0f14b6cc445c5ec7c17382b92d50bb593d36b04ab00ade2973b2e8c67e19b3dfe1b7841022a9f336da2fe7ba3d27ea6c6b7eb5
|
|
7
|
+
data.tar.gz: 680bbb80160eaa20b20c05d4585e167e143c5be6c4735869bf8d138605cd11a52bacc1f3564cc6b8ea57e772b13aa22bdc7cd720c8254f5cf576c3207b15826e
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,42 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.10.5
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- `config.parent_controller` (default `'::ApplicationController'`) lets consuming apps that don't use the
|
|
8
|
+
`ApplicationController` name (e.g. `ActionController::Base`, `RawrApplicationController`) tell the engine
|
|
9
|
+
what to inherit from. The `plan_my_stuff:verify` rake task now reports whether the configured class
|
|
10
|
+
resolves.
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- Example config option showed `url_options = Rails.application.config.action_mailer.default_url_options`. Now it shows
|
|
15
|
+
`url_options = Rails.application.routes.default_url_options`
|
|
16
|
+
|
|
17
|
+
## 0.10.4
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
|
|
21
|
+
- Internal: unit specs now use VCR cassettes against `BrandsInsurance/ubiquitous-adventure` instead of
|
|
22
|
+
`instance_double(Octokit::Client)`. No effect on consuming apps.
|
|
23
|
+
|
|
24
|
+
### Removed
|
|
25
|
+
|
|
26
|
+
- ETag caching on `Issue.list`. The cache key included `state`, `labels`, `page`, and `per_page`,
|
|
27
|
+
so an etag stored under one combo never matched a request with different params - the cache wrote
|
|
28
|
+
on every call and effectively never hit. `Issue.list` now always issues a fresh GitHub request.
|
|
29
|
+
`Comment.list` keeps ETag caching (param surface is just `issue` + `pms_only`).
|
|
30
|
+
`PlanMyStuff::Cache.read_list` / `write_list` remain available for `Comment.list`.
|
|
31
|
+
|
|
32
|
+
## 0.10.3
|
|
33
|
+
|
|
34
|
+
### Added
|
|
35
|
+
|
|
36
|
+
- `BaseProjectItem#assignees` returns the GitHub logins of users assigned to the underlying Issue,
|
|
37
|
+
PullRequest, or DraftIssue. Populated from the `FIND_PROJECT` GraphQL response (the query was extended
|
|
38
|
+
with `assignees(first: 10)` on each content fragment).
|
|
39
|
+
|
|
3
40
|
## 0.10.2
|
|
4
41
|
|
|
5
42
|
### Changed
|
data/CONFIGURATION.md
CHANGED
|
@@ -67,7 +67,7 @@ config.testing_template_project_number = 42
|
|
|
67
67
|
```ruby
|
|
68
68
|
config.app_name = 'MyApp'
|
|
69
69
|
|
|
70
|
-
url_options = Rails.application.
|
|
70
|
+
url_options = Rails.application.routes.default_url_options
|
|
71
71
|
config.issues_url_prefix = "#{url_options[:protocol] || 'http'}://#{url_options[:host]}/issues"
|
|
72
72
|
```
|
|
73
73
|
|
|
@@ -349,3 +349,16 @@ Controllable keys (with gem defaults):
|
|
|
349
349
|
| `:'testing_project_items/results'` | `plan_my_stuff/testing_project_items/results` |
|
|
350
350
|
| `:'webhooks/github'` | `plan_my_stuff/webhooks/github` |
|
|
351
351
|
| `:'webhooks/aws'` | `plan_my_stuff/webhooks/aws` |
|
|
352
|
+
|
|
353
|
+
### Parent controller
|
|
354
|
+
|
|
355
|
+
| Option | Type | Default | Description |
|
|
356
|
+
|---|---|---|---|
|
|
357
|
+
| `parent_controller` | `String` | `'::ApplicationController'` | Parent of `PlanMyStuff::ApplicationController`. |
|
|
358
|
+
|
|
359
|
+
Set this in `config/initializers/plan_my_stuff.rb`; Rails resolves the superclass once at class definition, so the
|
|
360
|
+
value must be set before the engine's controllers load.
|
|
361
|
+
|
|
362
|
+
```ruby
|
|
363
|
+
config.parent_controller = 'RawrApplicationController'
|
|
364
|
+
```
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module PlanMyStuff
|
|
4
|
-
class ApplicationController <
|
|
4
|
+
class ApplicationController < PlanMyStuff.configuration.parent_controller.constantize
|
|
5
5
|
protect_from_forgery with: :exception
|
|
6
6
|
helper Rails.application.routes.url_helpers
|
|
7
7
|
|
|
@@ -101,7 +101,7 @@ PlanMyStuff.configure do |config|
|
|
|
101
101
|
# number is appended to form `Issue#user_link`, which the gem also
|
|
102
102
|
# writes as the visible body of the GitHub issue.
|
|
103
103
|
# Recommended default:
|
|
104
|
-
# url_options = Rails.application.
|
|
104
|
+
# url_options = Rails.application.routes.default_url_options
|
|
105
105
|
# config.issues_url_prefix =
|
|
106
106
|
# "#{url_options[:protocol] || 'http'}://#{url_options[:host]}/issues"
|
|
107
107
|
|
|
@@ -321,4 +321,11 @@ PlanMyStuff.configure do |config|
|
|
|
321
321
|
# :'testing_project_items/results' => 'plan_my_stuff/testing_project_items/results'
|
|
322
322
|
# :'webhooks/github' => 'plan_my_stuff/webhooks/github'
|
|
323
323
|
# :'webhooks/aws' => 'plan_my_stuff/webhooks/aws'
|
|
324
|
+
|
|
325
|
+
# --------------------------------------------------------------------------
|
|
326
|
+
# Parent controller
|
|
327
|
+
# --------------------------------------------------------------------------
|
|
328
|
+
# Parent class for PlanMyStuff::ApplicationController. Override when the
|
|
329
|
+
# consuming app does not use the `ApplicationController` name.
|
|
330
|
+
# config.parent_controller = 'MyOtherApplicationController'
|
|
324
331
|
end
|
|
@@ -129,6 +129,7 @@ module PlanMyStuff
|
|
|
129
129
|
content = item[:content] || {}
|
|
130
130
|
field_values = item.dig(:fieldValues, :nodes) || []
|
|
131
131
|
repo_name = content.dig(:repository, :nameWithOwner)
|
|
132
|
+
assignee_nodes = content.dig(:assignees, :nodes) || []
|
|
132
133
|
|
|
133
134
|
{
|
|
134
135
|
id: item[:id],
|
|
@@ -142,6 +143,7 @@ module PlanMyStuff
|
|
|
142
143
|
repo: repo_name.present? ? PlanMyStuff::Repo.resolve!(repo_name) : nil,
|
|
143
144
|
status: extract_item_status(field_values),
|
|
144
145
|
field_values: parse_field_values(field_values),
|
|
146
|
+
assignees: assignee_nodes.pluck(:login).compact,
|
|
145
147
|
updated_at: item[:updatedAt],
|
|
146
148
|
github_response: item,
|
|
147
149
|
}
|
|
@@ -168,7 +170,7 @@ module PlanMyStuff
|
|
|
168
170
|
field_name = fv.dig(:field, :name)
|
|
169
171
|
next unless field_name
|
|
170
172
|
|
|
171
|
-
value = fv[:name] || fv[:text]
|
|
173
|
+
value = fv[:name] || fv[:text] || fv[:date]&.to_date
|
|
172
174
|
users_node = fv[:users]
|
|
173
175
|
if users_node
|
|
174
176
|
value = (users_node[:nodes] || []).map { |u| u[:login] }
|
|
@@ -46,6 +46,8 @@ module PlanMyStuff
|
|
|
46
46
|
attribute :updated_at, :datetime
|
|
47
47
|
# @return [Hash]
|
|
48
48
|
attribute :field_values, default: -> { {} }
|
|
49
|
+
# @return [Array<String>] GitHub logins assigned to the underlying Issue, PullRequest, or DraftIssue
|
|
50
|
+
attribute :assignees, default: -> { [] }
|
|
49
51
|
# @return [PlanMyStuff::BaseProject, nil]
|
|
50
52
|
attribute :project
|
|
51
53
|
# @return [PlanMyStuff::Issue, nil] linked issue (nil for draft items)
|
|
@@ -75,6 +77,7 @@ module PlanMyStuff
|
|
|
75
77
|
status: item_hash[:status],
|
|
76
78
|
updated_at: item_hash[:updated_at],
|
|
77
79
|
field_values: item_hash[:field_values] || {},
|
|
80
|
+
assignees: item_hash[:assignees] || [],
|
|
78
81
|
project: project,
|
|
79
82
|
)
|
|
80
83
|
|
|
@@ -227,6 +227,16 @@ module PlanMyStuff
|
|
|
227
227
|
#
|
|
228
228
|
attr_accessor :controllers
|
|
229
229
|
|
|
230
|
+
# Parent class string for +PlanMyStuff::ApplicationController+. Defaults to +'::ApplicationController'+. Override
|
|
231
|
+
# when the consuming app does not use the +ApplicationController+ name (e.g. +'ActionController::Base'+,
|
|
232
|
+
# +'RawrApplicationController'+). Must be set before the gem's controllers load - the standard
|
|
233
|
+
# +config/initializers/plan_my_stuff.rb+ location is correct, since Rails resolves the superclass once at class
|
|
234
|
+
# definition time.
|
|
235
|
+
#
|
|
236
|
+
# @return [String]
|
|
237
|
+
#
|
|
238
|
+
attr_accessor :parent_controller
|
|
239
|
+
|
|
230
240
|
# Whether to use Rails.cache for ETag-based HTTP caching of GitHub reads. Defaults to true; set to false to bypass
|
|
231
241
|
# the cache entirely.
|
|
232
242
|
#
|
|
@@ -361,6 +371,7 @@ module PlanMyStuff
|
|
|
361
371
|
@production_branch = 'production'
|
|
362
372
|
@mount_groups = { webhooks: true, issues: true, projects: true }
|
|
363
373
|
@controllers = {}
|
|
374
|
+
@parent_controller = '::ApplicationController'
|
|
364
375
|
@cache_enabled = true
|
|
365
376
|
@github_login_for = {}
|
|
366
377
|
@reminders_enabled = true
|
|
@@ -63,7 +63,7 @@ module PlanMyStuff
|
|
|
63
63
|
}
|
|
64
64
|
GRAPHQL
|
|
65
65
|
|
|
66
|
-
FIND_PROJECT = <<~GRAPHQL
|
|
66
|
+
FIND_PROJECT = <<~GRAPHQL.freeze
|
|
67
67
|
query($org: String!, $number: Int!, $cursor: String) {
|
|
68
68
|
organization(login: $org) {
|
|
69
69
|
projectV2(number: $number) {
|
|
@@ -95,7 +95,7 @@ module PlanMyStuff
|
|
|
95
95
|
}
|
|
96
96
|
}
|
|
97
97
|
}
|
|
98
|
-
items(first:
|
|
98
|
+
items(first: #{PlanMyStuff::BaseProject::ITEMS_PER_PAGE}, after: $cursor) {
|
|
99
99
|
pageInfo {
|
|
100
100
|
hasNextPage
|
|
101
101
|
endCursor
|
|
@@ -112,6 +112,7 @@ module PlanMyStuff
|
|
|
112
112
|
url
|
|
113
113
|
state
|
|
114
114
|
repository { nameWithOwner }
|
|
115
|
+
assignees(first: 10) { nodes { login } }
|
|
115
116
|
}
|
|
116
117
|
... on PullRequest {
|
|
117
118
|
id
|
|
@@ -120,11 +121,13 @@ module PlanMyStuff
|
|
|
120
121
|
url
|
|
121
122
|
state
|
|
122
123
|
repository { nameWithOwner }
|
|
124
|
+
assignees(first: 10) { nodes { login } }
|
|
123
125
|
}
|
|
124
126
|
... on DraftIssue {
|
|
125
127
|
id
|
|
126
128
|
title
|
|
127
129
|
body
|
|
130
|
+
assignees(first: 10) { nodes { login } }
|
|
128
131
|
}
|
|
129
132
|
}
|
|
130
133
|
fieldValues(first: 20) {
|
|
@@ -145,6 +148,14 @@ module PlanMyStuff
|
|
|
145
148
|
}
|
|
146
149
|
}
|
|
147
150
|
}
|
|
151
|
+
... on ProjectV2ItemFieldDateValue {
|
|
152
|
+
date
|
|
153
|
+
field {
|
|
154
|
+
... on ProjectV2Field {
|
|
155
|
+
name
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
148
159
|
... on ProjectV2ItemFieldUserValue {
|
|
149
160
|
users(first: 10) {
|
|
150
161
|
nodes {
|
data/lib/plan_my_stuff/issue.rb
CHANGED
|
@@ -290,17 +290,8 @@ module PlanMyStuff
|
|
|
290
290
|
params = { state: state.to_s, page: page, per_page: per_page }
|
|
291
291
|
params[:labels] = labels.sort.join(',') if labels.present?
|
|
292
292
|
|
|
293
|
-
|
|
294
|
-
request_options = cached ? params.merge(headers: { 'If-None-Match' => cached[:etag] }) : params
|
|
295
|
-
|
|
296
|
-
github_issues = client.rest(:list_issues, resolved_repo, **request_options)
|
|
297
|
-
|
|
298
|
-
if cached && not_modified?(client)
|
|
299
|
-
return cached[:body].map { |gi| build(gi, repo: resolved_repo) }
|
|
300
|
-
end
|
|
301
|
-
|
|
293
|
+
github_issues = client.rest(:list_issues, resolved_repo, **params)
|
|
302
294
|
filtered = github_issues.reject { |gi| gi.respond_to?(:pull_request) && gi.pull_request }
|
|
303
|
-
store_list_etag_to_cache(client, :issue, resolved_repo, params, filtered)
|
|
304
295
|
filtered.map { |gi| build(gi, repo: resolved_repo) }
|
|
305
296
|
end
|
|
306
297
|
|
|
@@ -3,17 +3,25 @@
|
|
|
3
3
|
require 'plan_my_stuff'
|
|
4
4
|
|
|
5
5
|
module PlanMyStuff
|
|
6
|
-
# Test support for
|
|
6
|
+
# Test support for apps that *consume* PlanMyStuff. Provides:
|
|
7
7
|
# - `PlanMyStuff.test_mode!` to stub all API calls
|
|
8
8
|
# - Factory-style builders: `build_issue`, `build_comment`, `build_project`
|
|
9
9
|
# - RSpec matchers: `expect_pms_issue_created`, `expect_pms_comment_created`, `expect_pms_item_moved`
|
|
10
10
|
#
|
|
11
|
-
# Usage:
|
|
11
|
+
# Usage (in a consuming Rails app):
|
|
12
12
|
# require 'plan_my_stuff/test_helpers'
|
|
13
13
|
#
|
|
14
14
|
# RSpec.configure do |config|
|
|
15
15
|
# config.include PlanMyStuff::TestHelpers
|
|
16
16
|
# end
|
|
17
|
+
#
|
|
18
|
+
# Not the harness for PlanMyStuff's own unit specs. Gem-internal specs go
|
|
19
|
+
# through VCR cassettes against a real GitHub sandbox (see `spec/support/vcr.rb`
|
|
20
|
+
# and the `:pms_vcr_configured` shared context). Calling `PlanMyStuff.test_mode!`
|
|
21
|
+
# inside the gem would monkey-patch the very class methods the cassettes were
|
|
22
|
+
# recorded against, defeating the VCR coverage. The builder utilities
|
|
23
|
+
# (`build_issue`, `build_comment`, `build_project`, `stub_approvals`) are safe
|
|
24
|
+
# to use inside the gem as plain factories - they don't replace any methods.
|
|
17
25
|
module TestHelpers
|
|
18
26
|
# Recorded actions during test mode, keyed by type:
|
|
19
27
|
# :issue_created, :comment_created, :item_moved
|
|
@@ -23,6 +23,7 @@ module PlanMyStuff
|
|
|
23
23
|
check_organization
|
|
24
24
|
check_repos
|
|
25
25
|
check_default_project
|
|
26
|
+
check_parent_controller
|
|
26
27
|
self
|
|
27
28
|
end
|
|
28
29
|
|
|
@@ -80,6 +81,15 @@ module PlanMyStuff
|
|
|
80
81
|
@results << Result.new("Repo :#{key}", false, "#{full_name}: #{e.message}")
|
|
81
82
|
end
|
|
82
83
|
|
|
84
|
+
# @return [void]
|
|
85
|
+
def check_parent_controller
|
|
86
|
+
parent = PlanMyStuff.configuration.parent_controller.to_s
|
|
87
|
+
klass = parent.constantize
|
|
88
|
+
@results << Result.new('Parent controller', true, "#{parent} resolved to #{klass}")
|
|
89
|
+
rescue NameError => e
|
|
90
|
+
@results << Result.new('Parent controller', false, "#{parent.inspect}: #{e.message}")
|
|
91
|
+
end
|
|
92
|
+
|
|
83
93
|
# @return [void]
|
|
84
94
|
def check_default_project
|
|
85
95
|
project_number = PlanMyStuff.configuration.default_project_number
|
|
@@ -193,6 +193,32 @@ namespace :plan_my_stuff do
|
|
|
193
193
|
end
|
|
194
194
|
end
|
|
195
195
|
|
|
196
|
+
desc 'Print all GitHub primary rate-limit buckets for the configured token. ' \
|
|
197
|
+
'Note: secondary/abuse limits and content-creation limits are NOT surfaced by GitHub ' \
|
|
198
|
+
'until you hit them, so a healthy report here does not guarantee writes will succeed.'
|
|
199
|
+
task rate_limit: :environment do
|
|
200
|
+
data = PlanMyStuff.client.rest(:get, '/rate_limit').to_h
|
|
201
|
+
resources = data[:resources] || {}
|
|
202
|
+
|
|
203
|
+
width = resources.keys.map { |k| k.to_s.length }.max || 0
|
|
204
|
+
resources.sort.each do |name, bucket|
|
|
205
|
+
next if bucket[:used].zero?
|
|
206
|
+
|
|
207
|
+
reset_at = Time.at(bucket[:reset]).utc
|
|
208
|
+
reset_in = [bucket[:reset] - Time.now.to_i, 0].max
|
|
209
|
+
puts(format(
|
|
210
|
+
'%-*s used=%-5d remaining=%-5d limit=%-5d resets_at=%s (in %ds)',
|
|
211
|
+
width,
|
|
212
|
+
name,
|
|
213
|
+
bucket[:used],
|
|
214
|
+
bucket[:remaining],
|
|
215
|
+
bucket[:limit],
|
|
216
|
+
reset_at.iso8601,
|
|
217
|
+
reset_in,
|
|
218
|
+
))
|
|
219
|
+
end
|
|
220
|
+
end
|
|
221
|
+
|
|
196
222
|
desc 'Verify PlanMyStuff configuration: token, org, repos, and project access'
|
|
197
223
|
task verify: :environment do
|
|
198
224
|
require 'plan_my_stuff/verifier'
|
metadata
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: plan_my_stuff
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.10.
|
|
4
|
+
version: 0.10.5
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Brands Insurance
|
|
8
|
+
autorequire:
|
|
8
9
|
bindir: exe
|
|
9
10
|
cert_chain: []
|
|
10
|
-
date:
|
|
11
|
+
date: 2026-05-13 00:00:00.000000000 Z
|
|
11
12
|
dependencies:
|
|
12
13
|
- !ruby/object:Gem::Dependency
|
|
13
14
|
name: rails
|
|
@@ -43,6 +44,7 @@ dependencies:
|
|
|
43
44
|
- - "~>"
|
|
44
45
|
- !ruby/object:Gem::Version
|
|
45
46
|
version: 10.0.0
|
|
47
|
+
description:
|
|
46
48
|
email:
|
|
47
49
|
- documents@brandsinsurance.com
|
|
48
50
|
executables: []
|
|
@@ -206,7 +208,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
206
208
|
- !ruby/object:Gem::Version
|
|
207
209
|
version: '0'
|
|
208
210
|
requirements: []
|
|
209
|
-
rubygems_version:
|
|
211
|
+
rubygems_version: 3.5.11
|
|
212
|
+
signing_key:
|
|
210
213
|
specification_version: 4
|
|
211
214
|
summary: Shared PMS
|
|
212
215
|
test_files: []
|