plan_my_stuff 0.1.0 → 1.0.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 +595 -0
- data/CONFIGURATION.md +487 -0
- data/README.md +612 -88
- data/app/controllers/plan_my_stuff/application_controller.rb +27 -5
- data/app/controllers/plan_my_stuff/comments_controller.rb +50 -19
- data/app/controllers/plan_my_stuff/issues/approvals_controller.rb +127 -0
- data/app/controllers/plan_my_stuff/issues/closures_controller.rb +53 -0
- data/app/controllers/plan_my_stuff/issues/links_controller.rb +129 -0
- data/app/controllers/plan_my_stuff/issues/takes_controller.rb +161 -0
- data/app/controllers/plan_my_stuff/issues/testings_controller.rb +82 -0
- data/app/controllers/plan_my_stuff/issues/viewers_controller.rb +62 -0
- data/app/controllers/plan_my_stuff/issues/waitings_controller.rb +55 -0
- data/app/controllers/plan_my_stuff/issues_controller.rb +53 -70
- data/app/controllers/plan_my_stuff/labels_controller.rb +32 -10
- data/app/controllers/plan_my_stuff/project_items/assignments_controller.rb +88 -0
- data/app/controllers/plan_my_stuff/project_items/statuses_controller.rb +44 -0
- data/app/controllers/plan_my_stuff/project_items_controller.rb +32 -69
- data/app/controllers/plan_my_stuff/projects_controller.rb +81 -3
- data/app/controllers/plan_my_stuff/testing_project_items/results_controller.rb +67 -0
- data/app/controllers/plan_my_stuff/testing_project_items_controller.rb +49 -0
- data/app/controllers/plan_my_stuff/testing_projects_controller.rb +121 -0
- data/app/controllers/plan_my_stuff/webhooks/aws_controller.rb +202 -0
- data/app/controllers/plan_my_stuff/webhooks/github_controller.rb +371 -0
- data/app/jobs/plan_my_stuff/application_job.rb +8 -0
- data/app/jobs/plan_my_stuff/reminders_sweep_job.rb +75 -0
- data/app/views/plan_my_stuff/comments/edit.html.erb +1 -3
- data/app/views/plan_my_stuff/comments/partials/_form.html.erb +8 -0
- data/app/views/plan_my_stuff/issues/edit.html.erb +2 -4
- data/app/views/plan_my_stuff/issues/index.html.erb +5 -5
- data/app/views/plan_my_stuff/issues/new.html.erb +2 -4
- data/app/views/plan_my_stuff/issues/partials/_approvals.html.erb +108 -0
- data/app/views/plan_my_stuff/issues/partials/_form.html.erb +11 -6
- data/app/views/plan_my_stuff/issues/partials/_labels.html.erb +4 -3
- data/app/views/plan_my_stuff/issues/partials/_links.html.erb +113 -0
- data/app/views/plan_my_stuff/issues/partials/_viewers.html.erb +4 -3
- data/app/views/plan_my_stuff/issues/show.html.erb +67 -6
- data/app/views/plan_my_stuff/partials/_flash.html.erb +3 -0
- data/app/views/plan_my_stuff/projects/edit.html.erb +5 -0
- data/app/views/plan_my_stuff/projects/index.html.erb +18 -2
- data/app/views/plan_my_stuff/projects/new.html.erb +5 -0
- data/app/views/plan_my_stuff/projects/partials/_form.html.erb +30 -0
- data/app/views/plan_my_stuff/projects/show.html.erb +30 -11
- data/app/views/plan_my_stuff/testing_project_items/new.html.erb +10 -0
- data/app/views/plan_my_stuff/testing_project_items/results/new.html.erb +20 -0
- data/app/views/plan_my_stuff/testing_projects/edit.html.erb +5 -0
- data/app/views/plan_my_stuff/testing_projects/new.html.erb +5 -0
- data/app/views/plan_my_stuff/testing_projects/partials/_form.html.erb +40 -0
- data/app/views/plan_my_stuff/testing_projects/partials/_item.html.erb +52 -0
- data/app/views/plan_my_stuff/testing_projects/partials/items/_form.html.erb +36 -0
- data/app/views/plan_my_stuff/testing_projects/show.html.erb +65 -0
- data/config/routes.rb +43 -15
- data/lib/generators/plan_my_stuff/install/templates/initializer.rb +302 -20
- data/lib/plan_my_stuff/application_record.rb +158 -1
- data/lib/plan_my_stuff/approval.rb +88 -0
- data/lib/plan_my_stuff/archive/sweep.rb +85 -0
- data/lib/plan_my_stuff/archive.rb +12 -0
- data/lib/plan_my_stuff/attachment.rb +83 -0
- data/lib/plan_my_stuff/attachment_uploader.rb +245 -0
- data/lib/plan_my_stuff/aws_sns_simulator.rb +116 -0
- data/lib/plan_my_stuff/base_metadata.rb +25 -28
- data/lib/plan_my_stuff/base_project.rb +502 -0
- data/lib/plan_my_stuff/base_project_extractions/graphql_hydration.rb +186 -0
- data/lib/plan_my_stuff/base_project_item.rb +588 -0
- data/lib/plan_my_stuff/base_project_metadata.rb +16 -0
- data/lib/plan_my_stuff/cache.rb +197 -0
- data/lib/plan_my_stuff/client.rb +139 -64
- data/lib/plan_my_stuff/comment.rb +225 -100
- data/lib/plan_my_stuff/comment_metadata.rb +68 -5
- data/lib/plan_my_stuff/configuration.rb +459 -28
- data/lib/plan_my_stuff/custom_fields.rb +96 -12
- data/lib/plan_my_stuff/engine.rb +14 -2
- data/lib/plan_my_stuff/errors.rb +65 -5
- data/lib/plan_my_stuff/graphql/queries.rb +454 -0
- data/lib/plan_my_stuff/issue.rb +1097 -166
- data/lib/plan_my_stuff/issue_extractions/approvals.rb +370 -0
- data/lib/plan_my_stuff/issue_extractions/links.rb +525 -0
- data/lib/plan_my_stuff/issue_extractions/viewers.rb +75 -0
- data/lib/plan_my_stuff/issue_extractions/waiting.rb +171 -0
- data/lib/plan_my_stuff/issue_field.rb +126 -0
- data/lib/plan_my_stuff/issue_field_translation.rb +67 -0
- data/lib/plan_my_stuff/issue_field_value_set.rb +68 -0
- data/lib/plan_my_stuff/issue_metadata.rb +132 -21
- data/lib/plan_my_stuff/label.rb +100 -13
- data/lib/plan_my_stuff/link.rb +144 -0
- data/lib/plan_my_stuff/markdown.rb +13 -7
- data/lib/plan_my_stuff/metadata_parser.rb +51 -12
- data/lib/plan_my_stuff/notifications.rb +148 -0
- data/lib/plan_my_stuff/pipeline/completed_sweep.rb +46 -0
- data/lib/plan_my_stuff/pipeline/issue_linker.rb +62 -0
- data/lib/plan_my_stuff/pipeline/status.rb +40 -0
- data/lib/plan_my_stuff/pipeline/testing.rb +23 -0
- data/lib/plan_my_stuff/pipeline.rb +310 -0
- data/lib/plan_my_stuff/project.rb +63 -465
- data/lib/plan_my_stuff/project_item.rb +3 -409
- data/lib/plan_my_stuff/project_item_metadata.rb +55 -0
- data/lib/plan_my_stuff/project_metadata.rb +47 -0
- data/lib/plan_my_stuff/reminders/closer.rb +70 -0
- data/lib/plan_my_stuff/reminders/fire.rb +129 -0
- data/lib/plan_my_stuff/reminders/sweep.rb +54 -0
- data/lib/plan_my_stuff/reminders.rb +12 -0
- data/lib/plan_my_stuff/repo.rb +145 -0
- data/lib/plan_my_stuff/test_helpers.rb +265 -25
- data/lib/plan_my_stuff/testing_project.rb +292 -0
- data/lib/plan_my_stuff/testing_project_item.rb +218 -0
- data/lib/plan_my_stuff/testing_project_metadata.rb +94 -0
- data/lib/plan_my_stuff/user_resolver.rb +24 -3
- data/lib/plan_my_stuff/verifier.rb +10 -0
- data/lib/plan_my_stuff/version.rb +2 -2
- data/lib/plan_my_stuff/webhook_replayer.rb +292 -0
- data/lib/plan_my_stuff.rb +55 -20
- data/lib/tasks/plan_my_stuff.rake +331 -0
- metadata +99 -4
|
@@ -1,6 +1,337 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
namespace :plan_my_stuff do
|
|
4
|
+
desc 'Run the plan_my_stuff install generator (alias for `rails g plan_my_stuff:install`)'
|
|
5
|
+
task install: :environment do
|
|
6
|
+
require 'rails/generators'
|
|
7
|
+
|
|
8
|
+
require 'generators/plan_my_stuff/install/install_generator'
|
|
9
|
+
PlanMyStuff::Generators::InstallGenerator.start([])
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
desc 'Copy plan_my_stuff view templates (alias for `rails g plan_my_stuff:views`)'
|
|
13
|
+
task views: :environment do
|
|
14
|
+
require 'rails/generators'
|
|
15
|
+
|
|
16
|
+
require 'generators/plan_my_stuff/views/views_generator'
|
|
17
|
+
PlanMyStuff::Generators::ViewsGenerator.start([])
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
namespace :webhooks do
|
|
21
|
+
desc 'Create an organization webhook (URL=... [EVENTS=ev1,ev2]). ' \
|
|
22
|
+
'Raises PlanMyStuff::ConfigurationError if config.webhook_secret is blank.'
|
|
23
|
+
task create_org: :environment do
|
|
24
|
+
url = ENV.fetch('URL') { raise(ArgumentError, 'URL env var is required') }
|
|
25
|
+
default_events = %w[projects_v2 projects_v2_item projects_v2_status_update]
|
|
26
|
+
events = ENV['EVENTS'].present? ? ENV['EVENTS'].split(',').map(&:strip).compact_blank : default_events
|
|
27
|
+
config = PlanMyStuff.configuration
|
|
28
|
+
if config.webhook_secret.blank?
|
|
29
|
+
raise(PlanMyStuff::ConfigurationError, 'PlanMyStuff.configuration.webhook_secret is blank')
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
hook = PlanMyStuff.client.rest(
|
|
33
|
+
:create_org_hook,
|
|
34
|
+
config.organization,
|
|
35
|
+
{ url: url, content_type: 'json', secret: config.webhook_secret, insecure_ssl: '0' },
|
|
36
|
+
{ events: events, active: true },
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
puts("Created org hook #{hook.id} on #{config.organization} -> #{url}")
|
|
40
|
+
puts("Events: #{events.join(', ')}")
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
desc 'Create a repo webhook (REPO=owner/name URL=... [EVENTS=ev1,ev2]). ' \
|
|
44
|
+
'Raises PlanMyStuff::ConfigurationError if config.webhook_secret is blank.'
|
|
45
|
+
task create_repo: :environment do
|
|
46
|
+
url = ENV.fetch('URL') { raise(ArgumentError, 'URL env var is required') }
|
|
47
|
+
repo = ENV.fetch('REPO') do
|
|
48
|
+
PlanMyStuff.client.resolve_repo!
|
|
49
|
+
rescue PlanMyStuff::ConfigurationError, ArgumentError
|
|
50
|
+
raise(ArgumentError, 'REPO env var is required or configured (e.g. BrandsInsurance/PlanMyStuff)')
|
|
51
|
+
end
|
|
52
|
+
default_events = %w[pull_request issues]
|
|
53
|
+
events = ENV['EVENTS'].present? ? ENV['EVENTS'].split(',').map(&:strip).compact_blank : default_events
|
|
54
|
+
config = PlanMyStuff.configuration
|
|
55
|
+
if config.webhook_secret.blank?
|
|
56
|
+
raise(PlanMyStuff::ConfigurationError, 'PlanMyStuff.configuration.webhook_secret is blank')
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
hook = PlanMyStuff.client.rest(
|
|
60
|
+
:create_hook,
|
|
61
|
+
repo,
|
|
62
|
+
'web',
|
|
63
|
+
{ url: url, content_type: 'json', secret: config.webhook_secret, insecure_ssl: '0' },
|
|
64
|
+
{ events: events, active: true },
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
puts("Created repo hook #{hook.id} on #{repo} -> #{url}")
|
|
68
|
+
puts("Events: #{events.join(', ')}")
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
desc 'Replay recent deliveries to a local endpoint (ENDPOINT_URL=... WEBHOOK_URL=... ' \
|
|
72
|
+
'[SCOPE=org|repo] [REPO=owner/name] [PROCESSED_FILE=...] [NON_INTERACTIVE=1])'
|
|
73
|
+
task replay: :environment do
|
|
74
|
+
require 'plan_my_stuff/webhook_replayer'
|
|
75
|
+
|
|
76
|
+
endpoint_url = ENV.fetch('ENDPOINT_URL') { raise(ArgumentError, 'ENDPOINT_URL env var is required') }
|
|
77
|
+
webhook_url = ENV.fetch('WEBHOOK_URL') { raise(ArgumentError, 'WEBHOOK_URL env var is required') }
|
|
78
|
+
scope = ENV.fetch('SCOPE', 'org').to_sym
|
|
79
|
+
repo = ENV.fetch('REPO', nil)
|
|
80
|
+
processed_file =
|
|
81
|
+
ENV.fetch('PROCESSED_FILE') do
|
|
82
|
+
Rails.root.join('tmp', 'plan_my_stuff', "webhook_replay_#{scope}_processed.txt").to_s
|
|
83
|
+
end
|
|
84
|
+
interactive = ENV['NON_INTERACTIVE'].to_s.strip.empty?
|
|
85
|
+
|
|
86
|
+
PlanMyStuff::WebhookReplayer.fetch_and_replay(
|
|
87
|
+
endpoint_url: endpoint_url,
|
|
88
|
+
webhook_url: webhook_url,
|
|
89
|
+
scope: scope,
|
|
90
|
+
repo: repo,
|
|
91
|
+
processed_file: processed_file,
|
|
92
|
+
interactive: interactive,
|
|
93
|
+
)
|
|
94
|
+
end
|
|
95
|
+
|
|
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=30]). ' \
|
|
98
|
+
'At least one of ORG_WEBHOOK_URL or REPO_WEBHOOK_URL is required (raises ArgumentError if both absent).'
|
|
99
|
+
task listen: :environment do
|
|
100
|
+
require 'plan_my_stuff/webhook_replayer'
|
|
101
|
+
|
|
102
|
+
endpoint_url = ENV.fetch('ENDPOINT_URL') { raise(ArgumentError, 'ENDPOINT_URL env var is required') }
|
|
103
|
+
org_webhook_url = ENV.fetch('ORG_WEBHOOK_URL', nil)
|
|
104
|
+
repo_webhook_url = ENV.fetch('REPO_WEBHOOK_URL', nil)
|
|
105
|
+
repo = ENV.fetch('REPO', nil)
|
|
106
|
+
interval = ENV.fetch('INTERVAL', '30').to_i
|
|
107
|
+
|
|
108
|
+
targets = []
|
|
109
|
+
targets << { scope: :org, webhook_url: org_webhook_url } if org_webhook_url.present?
|
|
110
|
+
if repo_webhook_url.present?
|
|
111
|
+
raise(ArgumentError, 'REPO env var required when REPO_WEBHOOK_URL is set') if repo.blank?
|
|
112
|
+
|
|
113
|
+
targets << { scope: :repo, webhook_url: repo_webhook_url, repo: repo }
|
|
114
|
+
end
|
|
115
|
+
raise(ArgumentError, 'Set at least one of ORG_WEBHOOK_URL or REPO_WEBHOOK_URL') if targets.empty?
|
|
116
|
+
|
|
117
|
+
processed_file_for = -> (target) {
|
|
118
|
+
Rails.root.join('tmp', 'plan_my_stuff', "webhook_listen_#{target[:scope]}_processed.txt").to_s
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
PlanMyStuff::WebhookReplayer.listen(
|
|
122
|
+
targets: targets,
|
|
123
|
+
endpoint_url: endpoint_url,
|
|
124
|
+
processed_file_for: processed_file_for,
|
|
125
|
+
interval: interval,
|
|
126
|
+
)
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
desc 'Simulate an AWS SNS deployment webhook to a local endpoint ' \
|
|
130
|
+
'(ENDPOINT_URL=... [EVENT=SERVICE_DEPLOYMENT_COMPLETED])'
|
|
131
|
+
task simulate_aws: :environment do
|
|
132
|
+
require 'plan_my_stuff/aws_sns_simulator'
|
|
133
|
+
|
|
134
|
+
endpoint_url = ENV.fetch('ENDPOINT_URL') { raise(ArgumentError, 'ENDPOINT_URL env var is required') }
|
|
135
|
+
event_name = ENV.fetch('EVENT', PlanMyStuff::AwsSnsSimulator::DEFAULT_EVENT)
|
|
136
|
+
|
|
137
|
+
PlanMyStuff::AwsSnsSimulator.post!(
|
|
138
|
+
endpoint_url: endpoint_url,
|
|
139
|
+
event_name: event_name,
|
|
140
|
+
)
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
namespace :reminders do
|
|
145
|
+
desc 'Enqueue a RemindersSweepJob per configured repo ' \
|
|
146
|
+
'([REPO=<key>] to target a single repo). ' \
|
|
147
|
+
'Raises PlanMyStuff::ConfigurationError when no repos are configured (config.repos empty and REPO unset).'
|
|
148
|
+
task sweep: :environment do
|
|
149
|
+
config = PlanMyStuff.configuration
|
|
150
|
+
repo_keys =
|
|
151
|
+
if ENV['REPO'].present?
|
|
152
|
+
[ENV['REPO'].to_sym]
|
|
153
|
+
else
|
|
154
|
+
config.repos.keys
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
if repo_keys.empty?
|
|
158
|
+
raise(PlanMyStuff::ConfigurationError, 'No repos configured (set config.repos or pass REPO=<key>)')
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
repo_keys.each do |key|
|
|
162
|
+
PlanMyStuff::RemindersSweepJob.requeue(key)
|
|
163
|
+
puts("Scheduled RemindersSweepJob for #{key.inspect} " \
|
|
164
|
+
"(#{config.repos[key] || '<unknown>'}) at #{PlanMyStuff::RemindersSweepJob.next_run.iso8601}")
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
namespace :testing do
|
|
170
|
+
desc 'Create a TestingProject template in the configured organization. ' \
|
|
171
|
+
'Bootstraps all testing custom fields. Set the returned project number as ' \
|
|
172
|
+
'config.testing_template_project_number, then configure its board view ' \
|
|
173
|
+
'and "Column by: Test Status" manually in the GitHub UI. ' \
|
|
174
|
+
'Options: TITLE="My Template" (default: "PMS Testing Template")'
|
|
175
|
+
task create_template: :environment do
|
|
176
|
+
title = ENV.fetch('TITLE', '[TEMPLATE] Testing Feature')
|
|
177
|
+
|
|
178
|
+
puts("Creating testing project template '#{title}' in " \
|
|
179
|
+
"#{PlanMyStuff.configuration.organization}...")
|
|
180
|
+
|
|
181
|
+
project = PlanMyStuff::TestingProject.create!(title: title)
|
|
182
|
+
|
|
183
|
+
puts
|
|
184
|
+
puts("\e[32mTemplate created successfully.\e[0m")
|
|
185
|
+
puts(" Title: #{project.title}")
|
|
186
|
+
puts(" Number: #{project.number}")
|
|
187
|
+
puts(" URL: #{project.url}")
|
|
188
|
+
puts
|
|
189
|
+
puts('Next steps:')
|
|
190
|
+
puts(' 1. Open the project in GitHub and set the board view to "Column by: Test Status"')
|
|
191
|
+
puts(' 2. Add to your PlanMyStuff initializer:')
|
|
192
|
+
puts(" config.testing_template_project_number = #{project.number}")
|
|
193
|
+
end
|
|
194
|
+
end
|
|
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
|
+
|
|
222
|
+
namespace :debug do
|
|
223
|
+
desc 'Probe GitHub issue body size limit by creating issues of increasing size, then closing them. ' \
|
|
224
|
+
'Options: REPO=owner/name (default: config.default_repo) START=60000 MAX=70000 STEP=1000 ' \
|
|
225
|
+
'LABEL=body-size-probe KEEP=0 (set KEEP=1 to leave issues open for inspection)'
|
|
226
|
+
task body_size_limit: :environment do
|
|
227
|
+
client = PlanMyStuff.client
|
|
228
|
+
repo = client.resolve_repo!(ENV.fetch('REPO', nil))
|
|
229
|
+
start = Integer(ENV.fetch('START', '60000'))
|
|
230
|
+
max = Integer(ENV.fetch('MAX', '70000'))
|
|
231
|
+
step = Integer(ENV.fetch('STEP', '1000'))
|
|
232
|
+
keep = ENV.fetch('KEEP', '0') == '1'
|
|
233
|
+
label = 'pms-body-size-probe'
|
|
234
|
+
|
|
235
|
+
puts("Probing #{repo} body limit: sizes #{start}..#{max} step #{step} " \
|
|
236
|
+
"label=#{label.inspect} (KEEP=#{keep ? '1' : '0'})")
|
|
237
|
+
puts
|
|
238
|
+
|
|
239
|
+
PlanMyStuff::Label.ensure!(repo: repo, name: label) if label.present?
|
|
240
|
+
|
|
241
|
+
created_numbers = []
|
|
242
|
+
|
|
243
|
+
start.step(max, step) do |size|
|
|
244
|
+
header = "<details><summary>#{size} chars</summary>\n\n"
|
|
245
|
+
footer = "\n\n</details>"
|
|
246
|
+
inner = 'a' * [size - header.length - footer.length, 0].max
|
|
247
|
+
body = "#{header}#{inner}#{footer}"
|
|
248
|
+
title = "[PMS body-size probe] #{size} chars"
|
|
249
|
+
print(format('size=%-8d ', size))
|
|
250
|
+
|
|
251
|
+
begin
|
|
252
|
+
options = label.present? ? { labels: [label] } : {}
|
|
253
|
+
result = client.rest(:create_issue, repo, title, body, **options)
|
|
254
|
+
number = result.respond_to?(:number) ? result.number : result[:number]
|
|
255
|
+
created_numbers << number
|
|
256
|
+
puts("OK ##{number}")
|
|
257
|
+
rescue Octokit::Error => e
|
|
258
|
+
puts("FAIL #{e.class}: #{e.message.to_s[0, 200]}")
|
|
259
|
+
break
|
|
260
|
+
end
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
puts
|
|
264
|
+
if keep || created_numbers.empty?
|
|
265
|
+
puts("Created #{created_numbers.size} issue(s); leaving open (KEEP=1).") if keep
|
|
266
|
+
else
|
|
267
|
+
puts("Closing #{created_numbers.size} probe issue(s)...")
|
|
268
|
+
created_numbers.each do |n|
|
|
269
|
+
PlanMyStuff::Issue.update!(number: n, repo: repo, state: 'closed')
|
|
270
|
+
rescue Octokit::Error => e
|
|
271
|
+
puts(" ##{n}: close failed (#{e.class})")
|
|
272
|
+
end
|
|
273
|
+
end
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
desc 'Probe GitHub issue comment body size limit by posting comments of increasing size on a single ' \
|
|
277
|
+
'bootstrap issue, then closing it. ' \
|
|
278
|
+
'Options: START=60000 MAX=70000 STEP=1000 KEEP=0 (set KEEP=1 to leave the bootstrap issue open)'
|
|
279
|
+
task comment_size_limit: :environment do
|
|
280
|
+
client = PlanMyStuff.client
|
|
281
|
+
repo = client.resolve_repo!
|
|
282
|
+
start = Integer(ENV.fetch('START', '60000'))
|
|
283
|
+
max = Integer(ENV.fetch('MAX', '70000'))
|
|
284
|
+
step = Integer(ENV.fetch('STEP', '1000'))
|
|
285
|
+
keep = ENV.fetch('KEEP', '0') == '1'
|
|
286
|
+
label = 'pms-comment-size-probe'
|
|
287
|
+
|
|
288
|
+
puts("Probing #{repo} comment body limit: sizes #{start}..#{max} step #{step} " \
|
|
289
|
+
"label=#{label.inspect} (KEEP=#{keep ? '1' : '0'})")
|
|
290
|
+
puts
|
|
291
|
+
|
|
292
|
+
PlanMyStuff::Label.ensure!(repo: repo, name: label)
|
|
293
|
+
|
|
294
|
+
issue = client.rest(
|
|
295
|
+
:create_issue,
|
|
296
|
+
repo,
|
|
297
|
+
'[PMS comment-size probe] bootstrap',
|
|
298
|
+
'Bootstrap issue for comment-size probing.',
|
|
299
|
+
labels: [label],
|
|
300
|
+
)
|
|
301
|
+
issue_number = issue.respond_to?(:number) ? issue.number : issue[:number]
|
|
302
|
+
puts("Bootstrap issue: ##{issue_number}")
|
|
303
|
+
puts
|
|
304
|
+
|
|
305
|
+
start.step(max, step) do |size|
|
|
306
|
+
header = "<details><summary>#{size} chars</summary>\n\n"
|
|
307
|
+
footer = "\n\n</details>"
|
|
308
|
+
inner = 'a' * [size - header.length - footer.length, 0].max
|
|
309
|
+
body = "#{header}#{inner}#{footer}"
|
|
310
|
+
print(format('size=%-8d ', size))
|
|
311
|
+
|
|
312
|
+
begin
|
|
313
|
+
client.rest(:add_comment, repo, issue_number, body)
|
|
314
|
+
puts('OK')
|
|
315
|
+
rescue Octokit::Error => e
|
|
316
|
+
puts("FAIL #{e.class}: #{e.message.to_s[0, 200]}")
|
|
317
|
+
break
|
|
318
|
+
end
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
puts
|
|
322
|
+
if keep
|
|
323
|
+
puts("Leaving bootstrap issue ##{issue_number} open (KEEP=1).")
|
|
324
|
+
else
|
|
325
|
+
puts("Closing bootstrap issue ##{issue_number}...")
|
|
326
|
+
begin
|
|
327
|
+
PlanMyStuff::Issue.update!(number: issue_number, repo: repo, state: 'closed')
|
|
328
|
+
rescue Octokit::Error => e
|
|
329
|
+
puts(" close failed (#{e.class})")
|
|
330
|
+
end
|
|
331
|
+
end
|
|
332
|
+
end
|
|
333
|
+
end
|
|
334
|
+
|
|
4
335
|
desc 'Verify PlanMyStuff configuration: token, org, repos, and project access'
|
|
5
336
|
task verify: :environment do
|
|
6
337
|
require 'plan_my_stuff/verifier'
|
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:
|
|
4
|
+
version: 1.0.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-29 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rails
|
|
@@ -51,32 +51,75 @@ executables: []
|
|
|
51
51
|
extensions: []
|
|
52
52
|
extra_rdoc_files: []
|
|
53
53
|
files:
|
|
54
|
+
- CHANGELOG.md
|
|
55
|
+
- CONFIGURATION.md
|
|
54
56
|
- LICENSE
|
|
55
57
|
- README.md
|
|
56
58
|
- app/controllers/plan_my_stuff/application_controller.rb
|
|
57
59
|
- app/controllers/plan_my_stuff/comments_controller.rb
|
|
60
|
+
- app/controllers/plan_my_stuff/issues/approvals_controller.rb
|
|
61
|
+
- app/controllers/plan_my_stuff/issues/closures_controller.rb
|
|
62
|
+
- app/controllers/plan_my_stuff/issues/links_controller.rb
|
|
63
|
+
- app/controllers/plan_my_stuff/issues/takes_controller.rb
|
|
64
|
+
- app/controllers/plan_my_stuff/issues/testings_controller.rb
|
|
65
|
+
- app/controllers/plan_my_stuff/issues/viewers_controller.rb
|
|
66
|
+
- app/controllers/plan_my_stuff/issues/waitings_controller.rb
|
|
58
67
|
- app/controllers/plan_my_stuff/issues_controller.rb
|
|
59
68
|
- app/controllers/plan_my_stuff/labels_controller.rb
|
|
69
|
+
- app/controllers/plan_my_stuff/project_items/assignments_controller.rb
|
|
70
|
+
- app/controllers/plan_my_stuff/project_items/statuses_controller.rb
|
|
60
71
|
- app/controllers/plan_my_stuff/project_items_controller.rb
|
|
61
72
|
- app/controllers/plan_my_stuff/projects_controller.rb
|
|
73
|
+
- app/controllers/plan_my_stuff/testing_project_items/results_controller.rb
|
|
74
|
+
- app/controllers/plan_my_stuff/testing_project_items_controller.rb
|
|
75
|
+
- app/controllers/plan_my_stuff/testing_projects_controller.rb
|
|
76
|
+
- app/controllers/plan_my_stuff/webhooks/aws_controller.rb
|
|
77
|
+
- app/controllers/plan_my_stuff/webhooks/github_controller.rb
|
|
78
|
+
- app/jobs/plan_my_stuff/application_job.rb
|
|
79
|
+
- app/jobs/plan_my_stuff/reminders_sweep_job.rb
|
|
62
80
|
- app/views/plan_my_stuff/comments/edit.html.erb
|
|
63
81
|
- app/views/plan_my_stuff/comments/partials/_form.html.erb
|
|
64
82
|
- app/views/plan_my_stuff/issues/edit.html.erb
|
|
65
83
|
- app/views/plan_my_stuff/issues/index.html.erb
|
|
66
84
|
- app/views/plan_my_stuff/issues/new.html.erb
|
|
85
|
+
- app/views/plan_my_stuff/issues/partials/_approvals.html.erb
|
|
67
86
|
- app/views/plan_my_stuff/issues/partials/_form.html.erb
|
|
68
87
|
- app/views/plan_my_stuff/issues/partials/_labels.html.erb
|
|
88
|
+
- app/views/plan_my_stuff/issues/partials/_links.html.erb
|
|
69
89
|
- app/views/plan_my_stuff/issues/partials/_viewers.html.erb
|
|
70
90
|
- app/views/plan_my_stuff/issues/show.html.erb
|
|
91
|
+
- app/views/plan_my_stuff/partials/_flash.html.erb
|
|
92
|
+
- app/views/plan_my_stuff/projects/edit.html.erb
|
|
71
93
|
- app/views/plan_my_stuff/projects/index.html.erb
|
|
94
|
+
- app/views/plan_my_stuff/projects/new.html.erb
|
|
95
|
+
- app/views/plan_my_stuff/projects/partials/_form.html.erb
|
|
72
96
|
- app/views/plan_my_stuff/projects/show.html.erb
|
|
97
|
+
- app/views/plan_my_stuff/testing_project_items/new.html.erb
|
|
98
|
+
- app/views/plan_my_stuff/testing_project_items/results/new.html.erb
|
|
99
|
+
- app/views/plan_my_stuff/testing_projects/edit.html.erb
|
|
100
|
+
- app/views/plan_my_stuff/testing_projects/new.html.erb
|
|
101
|
+
- app/views/plan_my_stuff/testing_projects/partials/_form.html.erb
|
|
102
|
+
- app/views/plan_my_stuff/testing_projects/partials/_item.html.erb
|
|
103
|
+
- app/views/plan_my_stuff/testing_projects/partials/items/_form.html.erb
|
|
104
|
+
- app/views/plan_my_stuff/testing_projects/show.html.erb
|
|
73
105
|
- config/routes.rb
|
|
74
106
|
- lib/generators/plan_my_stuff/install/install_generator.rb
|
|
75
107
|
- lib/generators/plan_my_stuff/install/templates/initializer.rb
|
|
76
108
|
- lib/generators/plan_my_stuff/views/views_generator.rb
|
|
77
109
|
- lib/plan_my_stuff.rb
|
|
78
110
|
- lib/plan_my_stuff/application_record.rb
|
|
111
|
+
- lib/plan_my_stuff/approval.rb
|
|
112
|
+
- lib/plan_my_stuff/archive.rb
|
|
113
|
+
- lib/plan_my_stuff/archive/sweep.rb
|
|
114
|
+
- lib/plan_my_stuff/attachment.rb
|
|
115
|
+
- lib/plan_my_stuff/attachment_uploader.rb
|
|
116
|
+
- lib/plan_my_stuff/aws_sns_simulator.rb
|
|
79
117
|
- lib/plan_my_stuff/base_metadata.rb
|
|
118
|
+
- lib/plan_my_stuff/base_project.rb
|
|
119
|
+
- lib/plan_my_stuff/base_project_extractions/graphql_hydration.rb
|
|
120
|
+
- lib/plan_my_stuff/base_project_item.rb
|
|
121
|
+
- lib/plan_my_stuff/base_project_metadata.rb
|
|
122
|
+
- lib/plan_my_stuff/cache.rb
|
|
80
123
|
- lib/plan_my_stuff/client.rb
|
|
81
124
|
- lib/plan_my_stuff/comment.rb
|
|
82
125
|
- lib/plan_my_stuff/comment_metadata.rb
|
|
@@ -84,17 +127,43 @@ files:
|
|
|
84
127
|
- lib/plan_my_stuff/custom_fields.rb
|
|
85
128
|
- lib/plan_my_stuff/engine.rb
|
|
86
129
|
- lib/plan_my_stuff/errors.rb
|
|
130
|
+
- lib/plan_my_stuff/graphql/queries.rb
|
|
87
131
|
- lib/plan_my_stuff/issue.rb
|
|
132
|
+
- lib/plan_my_stuff/issue_extractions/approvals.rb
|
|
133
|
+
- lib/plan_my_stuff/issue_extractions/links.rb
|
|
134
|
+
- lib/plan_my_stuff/issue_extractions/viewers.rb
|
|
135
|
+
- lib/plan_my_stuff/issue_extractions/waiting.rb
|
|
136
|
+
- lib/plan_my_stuff/issue_field.rb
|
|
137
|
+
- lib/plan_my_stuff/issue_field_translation.rb
|
|
138
|
+
- lib/plan_my_stuff/issue_field_value_set.rb
|
|
88
139
|
- lib/plan_my_stuff/issue_metadata.rb
|
|
89
140
|
- lib/plan_my_stuff/label.rb
|
|
141
|
+
- lib/plan_my_stuff/link.rb
|
|
90
142
|
- lib/plan_my_stuff/markdown.rb
|
|
91
143
|
- lib/plan_my_stuff/metadata_parser.rb
|
|
144
|
+
- lib/plan_my_stuff/notifications.rb
|
|
145
|
+
- lib/plan_my_stuff/pipeline.rb
|
|
146
|
+
- lib/plan_my_stuff/pipeline/completed_sweep.rb
|
|
147
|
+
- lib/plan_my_stuff/pipeline/issue_linker.rb
|
|
148
|
+
- lib/plan_my_stuff/pipeline/status.rb
|
|
149
|
+
- lib/plan_my_stuff/pipeline/testing.rb
|
|
92
150
|
- lib/plan_my_stuff/project.rb
|
|
93
151
|
- lib/plan_my_stuff/project_item.rb
|
|
152
|
+
- lib/plan_my_stuff/project_item_metadata.rb
|
|
153
|
+
- lib/plan_my_stuff/project_metadata.rb
|
|
154
|
+
- lib/plan_my_stuff/reminders.rb
|
|
155
|
+
- lib/plan_my_stuff/reminders/closer.rb
|
|
156
|
+
- lib/plan_my_stuff/reminders/fire.rb
|
|
157
|
+
- lib/plan_my_stuff/reminders/sweep.rb
|
|
158
|
+
- lib/plan_my_stuff/repo.rb
|
|
94
159
|
- lib/plan_my_stuff/test_helpers.rb
|
|
160
|
+
- lib/plan_my_stuff/testing_project.rb
|
|
161
|
+
- lib/plan_my_stuff/testing_project_item.rb
|
|
162
|
+
- lib/plan_my_stuff/testing_project_metadata.rb
|
|
95
163
|
- lib/plan_my_stuff/user_resolver.rb
|
|
96
164
|
- lib/plan_my_stuff/verifier.rb
|
|
97
165
|
- lib/plan_my_stuff/version.rb
|
|
166
|
+
- lib/plan_my_stuff/webhook_replayer.rb
|
|
98
167
|
- lib/tasks/plan_my_stuff.rake
|
|
99
168
|
homepage: https://github.com/brandsinsurance/PlanMyStuff/
|
|
100
169
|
licenses:
|
|
@@ -103,8 +172,34 @@ metadata:
|
|
|
103
172
|
rubygems_mfa_required: 'true'
|
|
104
173
|
homepage_uri: https://github.com/brandsinsurance/PlanMyStuff/
|
|
105
174
|
source_code_uri: https://github.com/brandsinsurance/PlanMyStuff
|
|
106
|
-
changelog_uri: https://github.com/brandsinsurance/PlanMyStuff/blob/main/CHANGELOG.
|
|
107
|
-
post_install_message:
|
|
175
|
+
changelog_uri: https://github.com/brandsinsurance/PlanMyStuff/blob/main/CHANGELOG.md
|
|
176
|
+
post_install_message: |
|
|
177
|
+
Thanks for installing plan_my_stuff!
|
|
178
|
+
|
|
179
|
+
Getting started:
|
|
180
|
+
|
|
181
|
+
rake plan_my_stuff:install
|
|
182
|
+
Generates config/initializers/plan_my_stuff.rb and mounts the engine
|
|
183
|
+
|
|
184
|
+
rake plan_my_stuff:views
|
|
185
|
+
Copies view templates to app/views/plan_my_stuff/ (optional)
|
|
186
|
+
|
|
187
|
+
Available rake tasks:
|
|
188
|
+
|
|
189
|
+
plan_my_stuff:verify
|
|
190
|
+
Verify token, org, repos, and project access
|
|
191
|
+
|
|
192
|
+
plan_my_stuff:webhooks:create_org URL=... [EVENTS=...]
|
|
193
|
+
plan_my_stuff:webhooks:create_repo URL=... [REPO=owner/name] [EVENTS=...]
|
|
194
|
+
plan_my_stuff:webhooks:replay ENDPOINT_URL=... WEBHOOK_URL=... [SCOPE=org|repo]
|
|
195
|
+
plan_my_stuff:webhooks:listen ENDPOINT_URL=... [ORG_WEBHOOK_URL=...] [REPO_WEBHOOK_URL=... REPO=...]
|
|
196
|
+
plan_my_stuff:webhooks:simulate_aws ENDPOINT_URL=... [EVENT=...]
|
|
197
|
+
|
|
198
|
+
plan_my_stuff:reminders:sweep [REPO=<key>]
|
|
199
|
+
|
|
200
|
+
plan_my_stuff:testing:create_template [TITLE=...]
|
|
201
|
+
|
|
202
|
+
Run `rake -D plan_my_stuff` for full descriptions.
|
|
108
203
|
rdoc_options: []
|
|
109
204
|
require_paths:
|
|
110
205
|
- lib
|