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.
Files changed (113) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +595 -0
  3. data/CONFIGURATION.md +487 -0
  4. data/README.md +612 -88
  5. data/app/controllers/plan_my_stuff/application_controller.rb +27 -5
  6. data/app/controllers/plan_my_stuff/comments_controller.rb +50 -19
  7. data/app/controllers/plan_my_stuff/issues/approvals_controller.rb +127 -0
  8. data/app/controllers/plan_my_stuff/issues/closures_controller.rb +53 -0
  9. data/app/controllers/plan_my_stuff/issues/links_controller.rb +129 -0
  10. data/app/controllers/plan_my_stuff/issues/takes_controller.rb +161 -0
  11. data/app/controllers/plan_my_stuff/issues/testings_controller.rb +82 -0
  12. data/app/controllers/plan_my_stuff/issues/viewers_controller.rb +62 -0
  13. data/app/controllers/plan_my_stuff/issues/waitings_controller.rb +55 -0
  14. data/app/controllers/plan_my_stuff/issues_controller.rb +53 -70
  15. data/app/controllers/plan_my_stuff/labels_controller.rb +32 -10
  16. data/app/controllers/plan_my_stuff/project_items/assignments_controller.rb +88 -0
  17. data/app/controllers/plan_my_stuff/project_items/statuses_controller.rb +44 -0
  18. data/app/controllers/plan_my_stuff/project_items_controller.rb +32 -69
  19. data/app/controllers/plan_my_stuff/projects_controller.rb +81 -3
  20. data/app/controllers/plan_my_stuff/testing_project_items/results_controller.rb +67 -0
  21. data/app/controllers/plan_my_stuff/testing_project_items_controller.rb +49 -0
  22. data/app/controllers/plan_my_stuff/testing_projects_controller.rb +121 -0
  23. data/app/controllers/plan_my_stuff/webhooks/aws_controller.rb +202 -0
  24. data/app/controllers/plan_my_stuff/webhooks/github_controller.rb +371 -0
  25. data/app/jobs/plan_my_stuff/application_job.rb +8 -0
  26. data/app/jobs/plan_my_stuff/reminders_sweep_job.rb +75 -0
  27. data/app/views/plan_my_stuff/comments/edit.html.erb +1 -3
  28. data/app/views/plan_my_stuff/comments/partials/_form.html.erb +8 -0
  29. data/app/views/plan_my_stuff/issues/edit.html.erb +2 -4
  30. data/app/views/plan_my_stuff/issues/index.html.erb +5 -5
  31. data/app/views/plan_my_stuff/issues/new.html.erb +2 -4
  32. data/app/views/plan_my_stuff/issues/partials/_approvals.html.erb +108 -0
  33. data/app/views/plan_my_stuff/issues/partials/_form.html.erb +11 -6
  34. data/app/views/plan_my_stuff/issues/partials/_labels.html.erb +4 -3
  35. data/app/views/plan_my_stuff/issues/partials/_links.html.erb +113 -0
  36. data/app/views/plan_my_stuff/issues/partials/_viewers.html.erb +4 -3
  37. data/app/views/plan_my_stuff/issues/show.html.erb +67 -6
  38. data/app/views/plan_my_stuff/partials/_flash.html.erb +3 -0
  39. data/app/views/plan_my_stuff/projects/edit.html.erb +5 -0
  40. data/app/views/plan_my_stuff/projects/index.html.erb +18 -2
  41. data/app/views/plan_my_stuff/projects/new.html.erb +5 -0
  42. data/app/views/plan_my_stuff/projects/partials/_form.html.erb +30 -0
  43. data/app/views/plan_my_stuff/projects/show.html.erb +30 -11
  44. data/app/views/plan_my_stuff/testing_project_items/new.html.erb +10 -0
  45. data/app/views/plan_my_stuff/testing_project_items/results/new.html.erb +20 -0
  46. data/app/views/plan_my_stuff/testing_projects/edit.html.erb +5 -0
  47. data/app/views/plan_my_stuff/testing_projects/new.html.erb +5 -0
  48. data/app/views/plan_my_stuff/testing_projects/partials/_form.html.erb +40 -0
  49. data/app/views/plan_my_stuff/testing_projects/partials/_item.html.erb +52 -0
  50. data/app/views/plan_my_stuff/testing_projects/partials/items/_form.html.erb +36 -0
  51. data/app/views/plan_my_stuff/testing_projects/show.html.erb +65 -0
  52. data/config/routes.rb +43 -15
  53. data/lib/generators/plan_my_stuff/install/templates/initializer.rb +302 -20
  54. data/lib/plan_my_stuff/application_record.rb +158 -1
  55. data/lib/plan_my_stuff/approval.rb +88 -0
  56. data/lib/plan_my_stuff/archive/sweep.rb +85 -0
  57. data/lib/plan_my_stuff/archive.rb +12 -0
  58. data/lib/plan_my_stuff/attachment.rb +83 -0
  59. data/lib/plan_my_stuff/attachment_uploader.rb +245 -0
  60. data/lib/plan_my_stuff/aws_sns_simulator.rb +116 -0
  61. data/lib/plan_my_stuff/base_metadata.rb +25 -28
  62. data/lib/plan_my_stuff/base_project.rb +502 -0
  63. data/lib/plan_my_stuff/base_project_extractions/graphql_hydration.rb +186 -0
  64. data/lib/plan_my_stuff/base_project_item.rb +588 -0
  65. data/lib/plan_my_stuff/base_project_metadata.rb +16 -0
  66. data/lib/plan_my_stuff/cache.rb +197 -0
  67. data/lib/plan_my_stuff/client.rb +139 -64
  68. data/lib/plan_my_stuff/comment.rb +225 -100
  69. data/lib/plan_my_stuff/comment_metadata.rb +68 -5
  70. data/lib/plan_my_stuff/configuration.rb +459 -28
  71. data/lib/plan_my_stuff/custom_fields.rb +96 -12
  72. data/lib/plan_my_stuff/engine.rb +14 -2
  73. data/lib/plan_my_stuff/errors.rb +65 -5
  74. data/lib/plan_my_stuff/graphql/queries.rb +454 -0
  75. data/lib/plan_my_stuff/issue.rb +1097 -166
  76. data/lib/plan_my_stuff/issue_extractions/approvals.rb +370 -0
  77. data/lib/plan_my_stuff/issue_extractions/links.rb +525 -0
  78. data/lib/plan_my_stuff/issue_extractions/viewers.rb +75 -0
  79. data/lib/plan_my_stuff/issue_extractions/waiting.rb +171 -0
  80. data/lib/plan_my_stuff/issue_field.rb +126 -0
  81. data/lib/plan_my_stuff/issue_field_translation.rb +67 -0
  82. data/lib/plan_my_stuff/issue_field_value_set.rb +68 -0
  83. data/lib/plan_my_stuff/issue_metadata.rb +132 -21
  84. data/lib/plan_my_stuff/label.rb +100 -13
  85. data/lib/plan_my_stuff/link.rb +144 -0
  86. data/lib/plan_my_stuff/markdown.rb +13 -7
  87. data/lib/plan_my_stuff/metadata_parser.rb +51 -12
  88. data/lib/plan_my_stuff/notifications.rb +148 -0
  89. data/lib/plan_my_stuff/pipeline/completed_sweep.rb +46 -0
  90. data/lib/plan_my_stuff/pipeline/issue_linker.rb +62 -0
  91. data/lib/plan_my_stuff/pipeline/status.rb +40 -0
  92. data/lib/plan_my_stuff/pipeline/testing.rb +23 -0
  93. data/lib/plan_my_stuff/pipeline.rb +310 -0
  94. data/lib/plan_my_stuff/project.rb +63 -465
  95. data/lib/plan_my_stuff/project_item.rb +3 -409
  96. data/lib/plan_my_stuff/project_item_metadata.rb +55 -0
  97. data/lib/plan_my_stuff/project_metadata.rb +47 -0
  98. data/lib/plan_my_stuff/reminders/closer.rb +70 -0
  99. data/lib/plan_my_stuff/reminders/fire.rb +129 -0
  100. data/lib/plan_my_stuff/reminders/sweep.rb +54 -0
  101. data/lib/plan_my_stuff/reminders.rb +12 -0
  102. data/lib/plan_my_stuff/repo.rb +145 -0
  103. data/lib/plan_my_stuff/test_helpers.rb +265 -25
  104. data/lib/plan_my_stuff/testing_project.rb +292 -0
  105. data/lib/plan_my_stuff/testing_project_item.rb +218 -0
  106. data/lib/plan_my_stuff/testing_project_metadata.rb +94 -0
  107. data/lib/plan_my_stuff/user_resolver.rb +24 -3
  108. data/lib/plan_my_stuff/verifier.rb +10 -0
  109. data/lib/plan_my_stuff/version.rb +2 -2
  110. data/lib/plan_my_stuff/webhook_replayer.rb +292 -0
  111. data/lib/plan_my_stuff.rb +55 -20
  112. data/lib/tasks/plan_my_stuff.rake +331 -0
  113. metadata +99 -4
@@ -0,0 +1,454 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PlanMyStuff
4
+ module GraphQL
5
+ # Consolidated GitHub GraphQL queries and mutations used by the gem.
6
+ # Strings are static (no runtime parameterization) so they live as
7
+ # frozen String constants rather than methods.
8
+ #
9
+ # Callers pass the constant straight to +PlanMyStuff.client.graphql+:
10
+ #
11
+ # PlanMyStuff.client.graphql(
12
+ # PlanMyStuff::GraphQL::Queries::DELETE_PROJECT_ITEM,
13
+ # variables: { projectId: ..., itemId: ... },
14
+ # )
15
+ #
16
+ module Queries
17
+ # --- Organization / project lookup ---------------------------------
18
+
19
+ ORG_ID = <<~GRAPHQL
20
+ query($org: String!) {
21
+ organization(login: $org) {
22
+ id
23
+ }
24
+ }
25
+ GRAPHQL
26
+
27
+ PROJECT_ID = <<~GRAPHQL
28
+ query($org: String!, $number: Int!) {
29
+ organization(login: $org) {
30
+ projectV2(number: $number) {
31
+ id
32
+ }
33
+ }
34
+ }
35
+ GRAPHQL
36
+
37
+ USER_NODE_ID = <<~GRAPHQL
38
+ query($login: String!) {
39
+ user(login: $login) {
40
+ id
41
+ }
42
+ }
43
+ GRAPHQL
44
+
45
+ # --- Project list / find -------------------------------------------
46
+
47
+ LIST_PROJECTS = <<~GRAPHQL
48
+ query($org: String!) {
49
+ organization(login: $org) {
50
+ projectsV2(first: 100) {
51
+ nodes {
52
+ id
53
+ number
54
+ title
55
+ shortDescription
56
+ readme
57
+ url
58
+ closed
59
+ updatedAt
60
+ }
61
+ }
62
+ }
63
+ }
64
+ GRAPHQL
65
+
66
+ FIND_PROJECT = <<~GRAPHQL.freeze
67
+ query($org: String!, $number: Int!, $cursor: String) {
68
+ organization(login: $org) {
69
+ projectV2(number: $number) {
70
+ id
71
+ number
72
+ title
73
+ shortDescription
74
+ readme
75
+ url
76
+ closed
77
+ updatedAt
78
+ fields(first: 50) {
79
+ nodes {
80
+ ... on ProjectV2SingleSelectField {
81
+ id
82
+ name
83
+ options {
84
+ id
85
+ name
86
+ }
87
+ }
88
+ ... on ProjectV2Field {
89
+ id
90
+ name
91
+ }
92
+ ... on ProjectV2IterationField {
93
+ id
94
+ name
95
+ }
96
+ }
97
+ }
98
+ items(first: #{PlanMyStuff::BaseProject::ITEMS_PER_PAGE}, after: $cursor) {
99
+ pageInfo {
100
+ hasNextPage
101
+ endCursor
102
+ }
103
+ nodes {
104
+ id
105
+ type
106
+ updatedAt
107
+ content {
108
+ ... on Issue {
109
+ id
110
+ title
111
+ number
112
+ url
113
+ state
114
+ repository { nameWithOwner }
115
+ assignees(first: 10) { nodes { login } }
116
+ }
117
+ ... on PullRequest {
118
+ id
119
+ title
120
+ number
121
+ url
122
+ state
123
+ repository { nameWithOwner }
124
+ assignees(first: 10) { nodes { login } }
125
+ }
126
+ ... on DraftIssue {
127
+ id
128
+ title
129
+ body
130
+ assignees(first: 10) { nodes { login } }
131
+ }
132
+ }
133
+ fieldValues(first: 20) {
134
+ nodes {
135
+ ... on ProjectV2ItemFieldSingleSelectValue {
136
+ name
137
+ field {
138
+ ... on ProjectV2SingleSelectField {
139
+ name
140
+ }
141
+ }
142
+ }
143
+ ... on ProjectV2ItemFieldTextValue {
144
+ text
145
+ field {
146
+ ... on ProjectV2Field {
147
+ name
148
+ }
149
+ }
150
+ }
151
+ ... on ProjectV2ItemFieldDateValue {
152
+ date
153
+ field {
154
+ ... on ProjectV2Field {
155
+ name
156
+ }
157
+ }
158
+ }
159
+ ... on ProjectV2ItemFieldUserValue {
160
+ users(first: 10) {
161
+ nodes {
162
+ login
163
+ }
164
+ }
165
+ field {
166
+ ... on ProjectV2Field {
167
+ name
168
+ }
169
+ }
170
+ }
171
+ }
172
+ }
173
+ }
174
+ }
175
+ }
176
+ }
177
+ }
178
+ GRAPHQL
179
+
180
+ # --- Project mutations ---------------------------------------------
181
+
182
+ CREATE_PROJECT = <<~GRAPHQL
183
+ mutation($input: CreateProjectV2Input!) {
184
+ createProjectV2(input: $input) {
185
+ projectV2 {
186
+ id
187
+ number
188
+ }
189
+ }
190
+ }
191
+ GRAPHQL
192
+
193
+ COPY_PROJECT_V2 = <<~GRAPHQL
194
+ mutation($input: CopyProjectV2Input!) {
195
+ copyProjectV2(input: $input) {
196
+ projectV2 {
197
+ id
198
+ number
199
+ }
200
+ }
201
+ }
202
+ GRAPHQL
203
+
204
+ UPDATE_PROJECT = <<~GRAPHQL
205
+ mutation($input: UpdateProjectV2Input!) {
206
+ updateProjectV2(input: $input) {
207
+ projectV2 {
208
+ id
209
+ number
210
+ }
211
+ }
212
+ }
213
+ GRAPHQL
214
+
215
+ # --- Project item mutations ----------------------------------------
216
+
217
+ ADD_ITEM = <<~GRAPHQL
218
+ mutation($projectId: ID!, $contentId: ID!) {
219
+ addProjectV2ItemById(input: {
220
+ projectId: $projectId,
221
+ contentId: $contentId
222
+ }) {
223
+ item {
224
+ id
225
+ }
226
+ }
227
+ }
228
+ GRAPHQL
229
+
230
+ ADD_DRAFT_ITEM = <<~GRAPHQL
231
+ mutation($projectId: ID!, $title: String!, $body: String) {
232
+ addProjectV2DraftIssue(input: {
233
+ projectId: $projectId,
234
+ title: $title,
235
+ body: $body
236
+ }) {
237
+ projectItem {
238
+ id
239
+ content { ... on DraftIssue { id body } }
240
+ }
241
+ }
242
+ }
243
+ GRAPHQL
244
+
245
+ UPDATE_SINGLE_SELECT_FIELD = <<~GRAPHQL
246
+ mutation($projectId: ID!, $itemId: ID!, $fieldId: ID!, $optionId: String!) {
247
+ updateProjectV2ItemFieldValue(input: {
248
+ projectId: $projectId,
249
+ itemId: $itemId,
250
+ fieldId: $fieldId,
251
+ value: { singleSelectOptionId: $optionId }
252
+ }) {
253
+ projectV2Item {
254
+ id
255
+ }
256
+ }
257
+ }
258
+ GRAPHQL
259
+
260
+ UPDATE_TEXT_FIELD = <<~GRAPHQL
261
+ mutation($projectId: ID!, $itemId: ID!, $fieldId: ID!, $value: String!) {
262
+ updateProjectV2ItemFieldValue(input: {
263
+ projectId: $projectId,
264
+ itemId: $itemId,
265
+ fieldId: $fieldId,
266
+ value: { text: $value }
267
+ }) {
268
+ projectV2Item {
269
+ id
270
+ }
271
+ }
272
+ }
273
+ GRAPHQL
274
+
275
+ CREATE_PROJECT_V2_FIELD = <<~GRAPHQL
276
+ mutation($input: CreateProjectV2FieldInput!) {
277
+ createProjectV2Field(input: $input) {
278
+ projectV2Field {
279
+ ... on ProjectV2Field {
280
+ id
281
+ name
282
+ }
283
+ ... on ProjectV2SingleSelectField {
284
+ id
285
+ name
286
+ }
287
+ }
288
+ }
289
+ }
290
+ GRAPHQL
291
+
292
+ DELETE_PROJECT_V2_FIELD = <<~GRAPHQL
293
+ mutation($input: DeleteProjectV2FieldInput!) {
294
+ deleteProjectV2Field(input: $input) {
295
+ projectV2Field {
296
+ ... on ProjectV2Field {
297
+ id
298
+ }
299
+ ... on ProjectV2SingleSelectField {
300
+ id
301
+ }
302
+ }
303
+ }
304
+ }
305
+ GRAPHQL
306
+
307
+ UPDATE_DATE_FIELD = <<~GRAPHQL
308
+ mutation($projectId: ID!, $itemId: ID!, $fieldId: ID!, $date: Date!) {
309
+ updateProjectV2ItemFieldValue(input: {
310
+ projectId: $projectId,
311
+ itemId: $itemId,
312
+ fieldId: $fieldId,
313
+ value: { date: $date }
314
+ }) {
315
+ projectV2Item {
316
+ id
317
+ }
318
+ }
319
+ }
320
+ GRAPHQL
321
+
322
+ DELETE_PROJECT_ITEM = <<~GRAPHQL
323
+ mutation($projectId: ID!, $itemId: ID!) {
324
+ deleteProjectV2Item(input: {
325
+ projectId: $projectId,
326
+ itemId: $itemId
327
+ }) {
328
+ deletedItemId
329
+ }
330
+ }
331
+ GRAPHQL
332
+
333
+ ASSIGN_DRAFT = <<~GRAPHQL
334
+ mutation($draftIssueId: ID!, $assigneeIds: [ID!]) {
335
+ updateProjectV2DraftIssue(input: {
336
+ draftIssueId: $draftIssueId,
337
+ assigneeIds: $assigneeIds
338
+ }) {
339
+ draftIssue { id }
340
+ }
341
+ }
342
+ GRAPHQL
343
+
344
+ # --- Issue relationships -------------------------------------------
345
+ #
346
+ # Sub-issues (parent / sub_tickets) and issue dependencies
347
+ # (blocking / blocked_by) are both handled via REST in +Issue+:
348
+ # - +/repos/{owner}/{repo}/issues/{number}/parent+
349
+ # - +/repos/{owner}/{repo}/issues/{number}/sub_issues+
350
+ # - +/repos/{owner}/{repo}/issues/{number}/sub_issue+ (DELETE)
351
+ # - +/repos/{owner}/{repo}/issues/{number}/dependencies/{side}+
352
+ # Only +duplicate_of+ still uses GraphQL.
353
+
354
+ FETCH_DUPLICATE_OF = <<~GRAPHQL
355
+ query($owner: String!, $repo: String!, $number: Int!) {
356
+ repository(owner: $owner, name: $repo) {
357
+ issue(number: $number) {
358
+ stateReason
359
+ duplicateOf {
360
+ number
361
+ repository {
362
+ nameWithOwner
363
+ }
364
+ }
365
+ }
366
+ }
367
+ }
368
+ GRAPHQL
369
+
370
+ CLOSE_AS_DUPLICATE = <<~GRAPHQL
371
+ mutation($issueId: ID!, $duplicateIssueId: ID!) {
372
+ closeIssue(input: {
373
+ issueId: $issueId,
374
+ stateReason: DUPLICATE,
375
+ duplicateIssueId: $duplicateIssueId
376
+ }) {
377
+ issue {
378
+ number
379
+ stateReason
380
+ }
381
+ }
382
+ }
383
+ GRAPHQL
384
+
385
+ # --- Archive support -----------------------------------------------
386
+
387
+ LIST_ISSUE_PROJECT_ITEMS = <<~GRAPHQL
388
+ query($owner: String!, $repo: String!, $number: Int!, $cursor: String) {
389
+ repository(owner: $owner, name: $repo) {
390
+ issue(number: $number) {
391
+ projectItems(first: 50, after: $cursor) {
392
+ pageInfo { hasNextPage endCursor }
393
+ nodes {
394
+ id
395
+ project { id number }
396
+ }
397
+ }
398
+ }
399
+ }
400
+ }
401
+ GRAPHQL
402
+
403
+ # --- Issue Fields (org-level public preview) -----------------------
404
+
405
+ LIST_ORG_ISSUE_FIELDS = <<~GRAPHQL
406
+ query($org: String!) {
407
+ organization(login: $org) {
408
+ issueFields(first: 50) {
409
+ nodes {
410
+ __typename
411
+ ... on IssueFieldText { id name description }
412
+ ... on IssueFieldNumber { id name description }
413
+ ... on IssueFieldDate { id name description }
414
+ ... on IssueFieldSingleSelect {
415
+ id name description
416
+ options { id name description color }
417
+ }
418
+ }
419
+ }
420
+ }
421
+ }
422
+ GRAPHQL
423
+
424
+ READ_ISSUE_FIELD_VALUES = <<~GRAPHQL
425
+ query($owner: String!, $name: String!, $number: Int!) {
426
+ repository(owner: $owner, name: $name) {
427
+ issue(number: $number) {
428
+ issueFieldValues(first: 50) {
429
+ nodes {
430
+ __typename
431
+ ... on IssueFieldTextValue { value field { ... on IssueFieldText { id name } } }
432
+ ... on IssueFieldNumberValue { value field { ... on IssueFieldNumber { id name } } }
433
+ ... on IssueFieldDateValue { value field { ... on IssueFieldDate { id name } } }
434
+ ... on IssueFieldSingleSelectValue {
435
+ name optionId
436
+ field { ... on IssueFieldSingleSelect { id name } }
437
+ }
438
+ }
439
+ }
440
+ }
441
+ }
442
+ }
443
+ GRAPHQL
444
+
445
+ SET_ISSUE_FIELD_VALUES = <<~GRAPHQL
446
+ mutation($issueId: ID!, $issueFields: [IssueFieldCreateOrUpdateInput!]!) {
447
+ setIssueFieldValue(input: { issueId: $issueId, issueFields: $issueFields }) {
448
+ issue { number }
449
+ }
450
+ }
451
+ GRAPHQL
452
+ end
453
+ end
454
+ end