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
|
@@ -1,28 +1,23 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module PlanMyStuff
|
|
4
|
-
# Daily-cadence sweep job for reminder dispatch + inactivity auto-close.
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
# setup. Queue-adapter-agnostic: runs through ActiveJob's
|
|
8
|
-
# +set(wait_until:).perform_later+ so any backend works.
|
|
4
|
+
# Daily-cadence sweep job for reminder dispatch + inactivity auto-close. Consuming apps enqueue it once; the job
|
|
5
|
+
# self-requeues after each perform so the schedule persists without requiring a cron/whenever setup.
|
|
6
|
+
# Queue-adapter-agnostic: runs through ActiveJob's +set(wait_until:).perform_later+ so any backend works.
|
|
9
7
|
class RemindersSweepJob < PlanMyStuff::ApplicationJob
|
|
10
8
|
queue_as :default
|
|
11
9
|
|
|
12
|
-
# Only try once per enqueue. Without this, Delayed-style adapters
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
# +perform_later+; if it fails, the follow-up scheduled in +ensure+
|
|
17
|
-
# takes over tomorrow.
|
|
10
|
+
# Only try once per enqueue. Without this, Delayed-style adapters retry up to 25 times on error and our
|
|
11
|
+
# +around_perform+ +ensure+ re-enqueues a follow-up run on every attempt, causing geometric duplicate
|
|
12
|
+
# pile-up. With +attempts: 1+, exactly one perform per +perform_later+; if it fails, the follow-up scheduled
|
|
13
|
+
# in +ensure+ takes over tomorrow.
|
|
18
14
|
retry_on StandardError, attempts: 1
|
|
19
15
|
|
|
20
16
|
around_perform :requeue_for_next_run
|
|
21
17
|
|
|
22
18
|
class << self
|
|
23
|
-
# Next sweep time. Default: 6:30am Eastern tomorrow (today if the
|
|
24
|
-
#
|
|
25
|
-
# cadence override this on a subclass.
|
|
19
|
+
# Next sweep time. Default: 6:30am Eastern tomorrow (today if the current time is before 6:30am ET). Apps
|
|
20
|
+
# wanting a different cadence override this on a subclass.
|
|
26
21
|
#
|
|
27
22
|
# @return [Time] UTC
|
|
28
23
|
#
|
|
@@ -33,9 +28,8 @@ module PlanMyStuff
|
|
|
33
28
|
target.utc
|
|
34
29
|
end
|
|
35
30
|
|
|
36
|
-
# Schedules a sweep for +next_run+. Used by the after-perform
|
|
37
|
-
#
|
|
38
|
-
# both kick off runs on the same cadence (instead of "now").
|
|
31
|
+
# Schedules a sweep for +next_run+. Used by the after-perform self-requeue and the
|
|
32
|
+
# +plan_my_stuff:reminders:sweep+ rake task so both kick off runs on the same cadence (instead of "now").
|
|
39
33
|
#
|
|
40
34
|
# @param repo [Symbol, String]
|
|
41
35
|
#
|
|
@@ -54,15 +48,14 @@ module PlanMyStuff
|
|
|
54
48
|
@repo_arg = repo
|
|
55
49
|
PlanMyStuff::Reminders::Sweep.new(repo: repo).call
|
|
56
50
|
PlanMyStuff::Archive::Sweep.new(repo: repo).call
|
|
57
|
-
PlanMyStuff::Pipeline::CompletedSweep.perform
|
|
51
|
+
PlanMyStuff::Pipeline::CompletedSweep.perform!
|
|
58
52
|
end
|
|
59
53
|
|
|
60
54
|
private
|
|
61
55
|
|
|
62
|
-
# Runs inside +around_perform+. Re-enqueues the next run in an
|
|
63
|
-
#
|
|
64
|
-
#
|
|
65
|
-
# error or direct +.perform+ call with missing kwargs).
|
|
56
|
+
# Runs inside +around_perform+. Re-enqueues the next run in an +ensure+ so a perform error still schedules
|
|
57
|
+
# the next one. Skips requeue when perform never captured a repo arg (deserialization error or direct
|
|
58
|
+
# +.perform+ call with missing kwargs).
|
|
66
59
|
#
|
|
67
60
|
# @return [void]
|
|
68
61
|
#
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
<h1>Edit Issue #<%= @issue.number %></h1>
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
<p style="color: red;"><%= flash[:error] %></p>
|
|
5
|
-
<% end %>
|
|
3
|
+
<%= render({ partial: 'plan_my_stuff/partials/flash' }) %>
|
|
6
4
|
|
|
7
|
-
<%= render({ partial: 'plan_my_stuff/issues/partials/form', locals: { issue: @issue
|
|
5
|
+
<%= render({ partial: 'plan_my_stuff/issues/partials/form', locals: { issue: @issue } }) %>
|
|
8
6
|
|
|
9
7
|
<% if @support_user %>
|
|
10
8
|
<hr>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<h1>Issues</h1>
|
|
2
2
|
|
|
3
|
-
<% if @issues.
|
|
3
|
+
<% if @issues.present? %>
|
|
4
4
|
<table>
|
|
5
5
|
<thead>
|
|
6
6
|
<tr>
|
|
@@ -34,4 +34,4 @@
|
|
|
34
34
|
<p>No issues found.</p>
|
|
35
35
|
<% end %>
|
|
36
36
|
<br>
|
|
37
|
-
<%= link_to
|
|
37
|
+
<%= link_to('New Issue', plan_my_stuff.new_issue_path(repo: @repo)) %>
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
<h1>New Issue</h1>
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
<p style="color: red;"><%= flash[:error] %></p>
|
|
5
|
-
<% end %>
|
|
3
|
+
<%= render({ partial: 'plan_my_stuff/partials/flash' }) %>
|
|
6
4
|
|
|
7
|
-
<%= render({ partial: 'plan_my_stuff/issues/partials/form', locals: { issue: @issue
|
|
5
|
+
<%= render({ partial: 'plan_my_stuff/issues/partials/form', locals: { issue: @issue } }) %>
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
<%# locals: (issue:, support_user:, current_user_id_local:) %>
|
|
1
2
|
<%
|
|
2
3
|
approvers = issue.approvers
|
|
3
4
|
pending_count = issue.pending_approvals.size
|
|
5
|
+
rejected_count = issue.rejected_approvals.size
|
|
4
6
|
current_user_id = current_user_id_local
|
|
5
7
|
%>
|
|
6
8
|
|
|
@@ -12,7 +14,12 @@
|
|
|
12
14
|
<% if issue.fully_approved? %>
|
|
13
15
|
<p><strong>Fully approved</strong></p>
|
|
14
16
|
<% else %>
|
|
15
|
-
<p
|
|
17
|
+
<p>
|
|
18
|
+
<strong><%= pending_count %> of <%= approvers.size %> approval(s) pending</strong>
|
|
19
|
+
<% if rejected_count.positive? %>
|
|
20
|
+
(<%= rejected_count %> rejected)
|
|
21
|
+
<% end %>
|
|
22
|
+
</p>
|
|
16
23
|
<% end %>
|
|
17
24
|
|
|
18
25
|
<ul>
|
|
@@ -24,6 +31,11 @@
|
|
|
24
31
|
<% if approval.approved_at %>
|
|
25
32
|
at <%= approval.approved_at.iso8601 %>
|
|
26
33
|
<% end %>
|
|
34
|
+
<% elsif approval.rejected? %>
|
|
35
|
+
rejected
|
|
36
|
+
<% if approval.rejected_at %>
|
|
37
|
+
at <%= approval.rejected_at.iso8601 %>
|
|
38
|
+
<% end %>
|
|
27
39
|
<% else %>
|
|
28
40
|
pending
|
|
29
41
|
<% end %>
|
|
@@ -38,9 +50,18 @@
|
|
|
38
50
|
form: { style: 'display:inline' },
|
|
39
51
|
)
|
|
40
52
|
%>
|
|
53
|
+
<%=
|
|
54
|
+
button_to(
|
|
55
|
+
'Reject',
|
|
56
|
+
plan_my_stuff.issue_approval_path(issue.number, approval.user_id, repo: issue.repo.full_name),
|
|
57
|
+
method: :patch,
|
|
58
|
+
params: { approval: { status: 'rejected' } },
|
|
59
|
+
form: { style: 'display:inline' },
|
|
60
|
+
)
|
|
61
|
+
%>
|
|
41
62
|
<% end %>
|
|
42
63
|
|
|
43
|
-
<% if approval.
|
|
64
|
+
<% if !approval.pending? && (approval.user_id == current_user_id || support_user) %>
|
|
44
65
|
<%=
|
|
45
66
|
button_to(
|
|
46
67
|
'Revoke',
|
|
@@ -1,14 +1,57 @@
|
|
|
1
|
+
<%# locals: (issue:, support_user:) %>
|
|
1
2
|
<%
|
|
2
3
|
# read_only sections have no add form; remove_only sections allow X but
|
|
3
4
|
# no add (blocking is created from the blocked side; duplicate_of is
|
|
4
5
|
# created via mark_duplicate! and cleared by reopening on GitHub).
|
|
5
6
|
sections = [
|
|
6
|
-
{
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
{
|
|
8
|
+
type: 'parent',
|
|
9
|
+
label: 'Parent',
|
|
10
|
+
single: true,
|
|
11
|
+
add_form: true,
|
|
12
|
+
removable: true,
|
|
13
|
+
targets: [issue.parent].compact
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
type: 'sub_ticket',
|
|
17
|
+
label: 'Sub-tickets',
|
|
18
|
+
single: false,
|
|
19
|
+
add_form: true,
|
|
20
|
+
removable: true,
|
|
21
|
+
targets: issue.sub_tickets
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
type: 'blocked_by',
|
|
25
|
+
label: 'Blocked by',
|
|
26
|
+
single: false,
|
|
27
|
+
add_form: true,
|
|
28
|
+
removable: true,
|
|
29
|
+
targets: issue.blocked_by
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
type: 'blocking',
|
|
33
|
+
label: 'Blocking',
|
|
34
|
+
single: false,
|
|
35
|
+
add_form: false,
|
|
36
|
+
removable: false,
|
|
37
|
+
targets: issue.blocking
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
type: 'related',
|
|
41
|
+
label: 'Related',
|
|
42
|
+
single: false,
|
|
43
|
+
add_form: true,
|
|
44
|
+
removable: true,
|
|
45
|
+
targets: issue.related
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
type: 'duplicate_of',
|
|
49
|
+
label: 'Duplicate of',
|
|
50
|
+
single: true,
|
|
51
|
+
add_form: false,
|
|
52
|
+
removable: false,
|
|
53
|
+
targets: [issue.duplicate_of].compact
|
|
54
|
+
},
|
|
12
55
|
]
|
|
13
56
|
visible_sections = support_user ? sections : sections.select { |s| s[:type] == 'related' }
|
|
14
57
|
%>
|
|
@@ -18,7 +61,7 @@
|
|
|
18
61
|
<% visible_sections.each do |section| %>
|
|
19
62
|
<div>
|
|
20
63
|
<h4><%= section[:label] %></h4>
|
|
21
|
-
<% if section[:targets].
|
|
64
|
+
<% if section[:targets].present? %>
|
|
22
65
|
<ul>
|
|
23
66
|
<% section[:targets].each do |target| %>
|
|
24
67
|
<li>
|
|
@@ -17,9 +17,12 @@
|
|
|
17
17
|
<%= button_to('Mark waiting', plan_my_stuff.issue_waiting_path(@issue.number, repo: @issue.repo.full_name), method: :post) %>
|
|
18
18
|
<% end %>
|
|
19
19
|
<% end %>
|
|
20
|
-
<% if @support_user && @pipeline_enabled && @pipeline_item.nil? %>
|
|
20
|
+
<% if @support_user && @pipeline_enabled && @pipeline_item.nil? && @issue.assignees.blank? %>
|
|
21
21
|
<%= button_to('Take', plan_my_stuff.issue_take_path(@issue.number, repo: @issue.repo.full_name), method: :post) %>
|
|
22
22
|
<% end %>
|
|
23
|
+
<% if @support_user && @pipeline_enabled && @current_user_login.present? && @issue.assignees.include?(@current_user_login) %>
|
|
24
|
+
<%= button_to('Unassign', plan_my_stuff.issue_take_path(@issue.number, repo: @issue.repo.full_name), method: :delete) %>
|
|
25
|
+
<% end %>
|
|
23
26
|
<% if @support_user %>
|
|
24
27
|
<%= link_to('Start Testing Project', plan_my_stuff.new_testing_project_path(subject_url: @issue.html_url)) %>
|
|
25
28
|
<% end %>
|
|
@@ -67,7 +70,7 @@
|
|
|
67
70
|
|
|
68
71
|
<h2>Comments (<%= @comments.size %>)</h2>
|
|
69
72
|
|
|
70
|
-
<% if @comments.
|
|
73
|
+
<% if @comments.present? %>
|
|
71
74
|
<% @comments.each do |comment| %>
|
|
72
75
|
<div>
|
|
73
76
|
<%= PlanMyStuff::Markdown.render(comment.body || '').html_safe %>
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
<h1>Edit Project #<%= @project.number %></h1>
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
<p style="color: red;"><%= flash[:error] %></p>
|
|
5
|
-
<% end %>
|
|
3
|
+
<%= render({ partial: 'plan_my_stuff/partials/flash' }) %>
|
|
6
4
|
|
|
7
5
|
<%= render({ partial: 'plan_my_stuff/projects/partials/form', locals: { project: @project } }) %>
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
<h1>New Project</h1>
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
<p style="color: red;"><%= flash[:error] %></p>
|
|
5
|
-
<% end %>
|
|
3
|
+
<%= render({ partial: 'plan_my_stuff/partials/flash' }) %>
|
|
6
4
|
|
|
7
5
|
<%= render({ partial: 'plan_my_stuff/projects/partials/form', locals: { project: @project } }) %>
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
<% end %>
|
|
8
8
|
</p>
|
|
9
9
|
|
|
10
|
-
<% if @statuses.
|
|
10
|
+
<% if @statuses.present? %>
|
|
11
11
|
<table>
|
|
12
12
|
<thead>
|
|
13
13
|
<tr>
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
<% end %>
|
|
44
44
|
|
|
45
45
|
<% assignees = item.field_values['Assignees'] || [] %>
|
|
46
|
-
<% if assignees.
|
|
46
|
+
<% if assignees.present? %>
|
|
47
47
|
<div>
|
|
48
48
|
<% assignees.each do |username| %>
|
|
49
49
|
<span>
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
) do |form|
|
|
58
58
|
%>
|
|
59
59
|
<%= form.hidden_field(:username, value: username) %>
|
|
60
|
-
<%= form.submit('
|
|
60
|
+
<%= form.submit('x', title: "Unassign #{username}") %>
|
|
61
61
|
<% end %>
|
|
62
62
|
</span>
|
|
63
63
|
<% end %>
|
|
@@ -74,6 +74,16 @@
|
|
|
74
74
|
<%= form.text_field(:assignee, placeholder: 'GitHub username') %>
|
|
75
75
|
<%= form.submit('Assign') %>
|
|
76
76
|
<% end %>
|
|
77
|
+
|
|
78
|
+
<%=
|
|
79
|
+
form_with(
|
|
80
|
+
url: plan_my_stuff.project_item_path(@project.number, item.id),
|
|
81
|
+
method: :delete,
|
|
82
|
+
local: true,
|
|
83
|
+
) do |form|
|
|
84
|
+
%>
|
|
85
|
+
<%= form.submit('Remove from project') %>
|
|
86
|
+
<% end %>
|
|
77
87
|
</div>
|
|
78
88
|
<% end %>
|
|
79
89
|
<% if items.empty? %>
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
<h1>Fail Item</h1>
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
<p style="color: red;"><%= flash[:error] %></p>
|
|
5
|
-
<% end %>
|
|
3
|
+
<%= render({ partial: 'plan_my_stuff/partials/flash' }) %>
|
|
6
4
|
|
|
7
5
|
<%= form_with(
|
|
8
6
|
url: plan_my_stuff.testing_project_item_result_path(@project_number, @item_id),
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
<h1>Edit Testing Project #<%= @project.number %></h1>
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
<p style="color: red;"><%= flash[:error] %></p>
|
|
5
|
-
<% end %>
|
|
3
|
+
<%= render({ partial: 'plan_my_stuff/partials/flash' }) %>
|
|
6
4
|
|
|
7
5
|
<%= render({ partial: 'plan_my_stuff/testing_projects/partials/form', locals: { project: @project } }) %>
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
<h1>New Testing Project</h1>
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
<p style="color: red;"><%= flash[:error] %></p>
|
|
5
|
-
<% end %>
|
|
3
|
+
<%= render({ partial: 'plan_my_stuff/partials/flash' }) %>
|
|
6
4
|
|
|
7
5
|
<%= render({ partial: 'plan_my_stuff/testing_projects/partials/form', locals: { project: @project } }) %>
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
<%# locals: (project:) %>
|
|
1
2
|
<%
|
|
2
3
|
persisted = project.persisted?
|
|
3
4
|
url =
|
|
@@ -20,17 +21,17 @@
|
|
|
20
21
|
|
|
21
22
|
<div>
|
|
22
23
|
<%= form.label(:subject_urls, 'Subject URLs (one per line)') %>
|
|
23
|
-
<%= form.text_area(:subject_urls, rows: 4, value: project.metadata
|
|
24
|
+
<%= form.text_area(:subject_urls, rows: 4, value: Array.wrap(project.metadata&.subject_urls).join("\n")) %>
|
|
24
25
|
</div>
|
|
25
26
|
|
|
26
27
|
<div>
|
|
27
28
|
<%= form.label(:due_date, 'Due Date') %>
|
|
28
|
-
<%= form.date_field(:due_date, value: project.metadata
|
|
29
|
+
<%= form.date_field(:due_date, value: project.metadata&.due_date&.strftime('%F')) %>
|
|
29
30
|
</div>
|
|
30
31
|
|
|
31
32
|
<div>
|
|
32
33
|
<%= form.label(:deadline_miss_reason, 'Deadline Miss Reason') %>
|
|
33
|
-
<%= form.text_field(:deadline_miss_reason, value: project.metadata
|
|
34
|
+
<%= form.text_field(:deadline_miss_reason, value: project.metadata&.deadline_miss_reason) %>
|
|
34
35
|
</div>
|
|
35
36
|
|
|
36
37
|
<div>
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
<% end %>
|
|
8
8
|
</p>
|
|
9
9
|
|
|
10
|
-
<% if @support_user && @project.metadata.subject_urls.
|
|
10
|
+
<% if @support_user && @project.metadata.subject_urls.present? %>
|
|
11
11
|
<p>
|
|
12
12
|
<strong>Subject URLs:</strong>
|
|
13
13
|
<% @project.metadata.subject_urls.each do |url| %>
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
<p><strong>Due:</strong> <%= @project.metadata.due_date %></p>
|
|
21
21
|
<% end %>
|
|
22
22
|
|
|
23
|
-
<% if @statuses.
|
|
23
|
+
<% if @statuses.present? %>
|
|
24
24
|
<table>
|
|
25
25
|
<thead>
|
|
26
26
|
<tr>
|
data/config/routes.rb
CHANGED
|
@@ -12,7 +12,7 @@ PlanMyStuff::Engine.routes.draw do
|
|
|
12
12
|
if config.pipeline_enabled
|
|
13
13
|
resource(
|
|
14
14
|
:take,
|
|
15
|
-
only:
|
|
15
|
+
only: %i[create destroy],
|
|
16
16
|
controller: config.controller_for(:'issues/takes'),
|
|
17
17
|
)
|
|
18
18
|
end
|
|
@@ -32,7 +32,7 @@ PlanMyStuff::Engine.routes.draw do
|
|
|
32
32
|
|
|
33
33
|
if mount_groups.fetch(:projects, true)
|
|
34
34
|
resources :projects, except: %i[destroy], controller: config.controller_for(:projects) do
|
|
35
|
-
resources :items, only: %i[create], controller: config.controller_for(:project_items) do
|
|
35
|
+
resources :items, only: %i[create destroy], controller: config.controller_for(:project_items) do
|
|
36
36
|
resource :status, only: %i[update], controller: config.controller_for(:'project_items/statuses')
|
|
37
37
|
resource :assignment, only: %i[update destroy], controller: config.controller_for(:'project_items/assignments')
|
|
38
38
|
end
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
PlanMyStuff.configure do |config|
|
|
4
4
|
# --------------------------------------------------------------------------
|
|
5
5
|
# Authentication (required)
|
|
6
6
|
# --------------------------------------------------------------------------
|
|
7
7
|
# GitHub PAT with `repo` and `project` scopes. All API calls use this token.
|
|
8
8
|
config.access_token = Rails.application.credentials.dig(:plan_my_stuff, :github_token)
|
|
9
9
|
|
|
10
|
+
# Classic PAT (requires `repo` scope) for the Issues Import API (golden-comet-preview).
|
|
11
|
+
# Fine-grained tokens are not supported by that endpoint.
|
|
12
|
+
# config.import_access_token = Rails.application.credentials.dig(:plan_my_stuff, :github_import_token)
|
|
13
|
+
|
|
10
14
|
# --------------------------------------------------------------------------
|
|
11
15
|
# Organization (required)
|
|
12
16
|
# --------------------------------------------------------------------------
|
|
@@ -97,27 +101,29 @@ PMS.configure do |config|
|
|
|
97
101
|
# number is appended to form `Issue#user_link`, which the gem also
|
|
98
102
|
# writes as the visible body of the GitHub issue.
|
|
99
103
|
# Recommended default:
|
|
104
|
+
# url_options = Rails.application.config.action_mailer.default_url_options
|
|
100
105
|
# config.issues_url_prefix =
|
|
101
|
-
# "#{
|
|
106
|
+
# "#{url_options[:protocol] || 'http'}://#{url_options[:host]}/issues"
|
|
102
107
|
|
|
103
108
|
# --------------------------------------------------------------------------
|
|
104
|
-
#
|
|
109
|
+
# Notification actor
|
|
105
110
|
# --------------------------------------------------------------------------
|
|
106
|
-
# Proc returning boolean, or nil (always send). When it returns false the
|
|
107
|
-
# request is deferred to a background job instead of hitting GitHub.
|
|
108
|
-
# config.should_send_request = -> { !MaintenanceMode.active? }
|
|
109
|
-
|
|
110
|
-
# Map of action type to job class name for deferred requests.
|
|
111
|
-
# config.job_classes = {
|
|
112
|
-
# create_ticket: 'PmsCreateTicketJob',
|
|
113
|
-
# post_comment: 'PmsPostCommentJob',
|
|
114
|
-
# update_status: 'PmsUpdateStatusJob'
|
|
115
|
-
# }
|
|
116
|
-
|
|
117
111
|
# Fallback actor for notification events (plan_my_stuff.*) when a caller
|
|
118
112
|
# does not pass an explicit user: kwarg. Proc/lambda called at event time.
|
|
119
113
|
# config.current_user = -> { Current.user }
|
|
120
114
|
|
|
115
|
+
# --------------------------------------------------------------------------
|
|
116
|
+
# Controller rescue hook
|
|
117
|
+
# --------------------------------------------------------------------------
|
|
118
|
+
# Invoked from every gem controller rescue block, after the gem logs the
|
|
119
|
+
# error class/message and stack trace via Rails.logger.error and just
|
|
120
|
+
# before the user-facing flash + redirect/render. Forwards the rescued
|
|
121
|
+
# exception so consuming apps can fire monitoring even though the rescue
|
|
122
|
+
# swallows the error. Receives the rescued exception; return value is
|
|
123
|
+
# ignored. Defaults to nil (no-op).
|
|
124
|
+
#
|
|
125
|
+
# config.controller_rescue = ->(error) { MonitoringService.notice_error(error) }
|
|
126
|
+
|
|
121
127
|
# --------------------------------------------------------------------------
|
|
122
128
|
# Custom fields
|
|
123
129
|
# --------------------------------------------------------------------------
|
|
@@ -146,6 +152,22 @@ PMS.configure do |config|
|
|
|
146
152
|
# Testing-project-only fields (merged on top of shared, context wins on conflicts):
|
|
147
153
|
# config.testing_custom_fields = {}
|
|
148
154
|
|
|
155
|
+
# --------------------------------------------------------------------------
|
|
156
|
+
# Issue types (org-side renames)
|
|
157
|
+
# --------------------------------------------------------------------------
|
|
158
|
+
# The gem speaks in canonical type names: 'Bug', 'Feature',
|
|
159
|
+
# 'IT Issue / Hardware', 'Other', 'Performance', 'Question', 'Task'.
|
|
160
|
+
# Symbol shortcuts (`:bug`, `:feature`, `:it_issue`, `:other`, `:performance`,
|
|
161
|
+
# `:question`, `:task`) resolve to those canonical names automatically.
|
|
162
|
+
# If your GitHub org uses different names for any of them, map the
|
|
163
|
+
# canonical name to your org's name here and PMS will translate on
|
|
164
|
+
# write. Missing keys pass through unchanged.
|
|
165
|
+
#
|
|
166
|
+
# config.issue_types = {
|
|
167
|
+
# 'Bug' => 'User Bug',
|
|
168
|
+
# 'Feature' => 'Enhancement',
|
|
169
|
+
# }
|
|
170
|
+
|
|
149
171
|
# --------------------------------------------------------------------------
|
|
150
172
|
# Release pipeline
|
|
151
173
|
# --------------------------------------------------------------------------
|
|
@@ -161,6 +183,22 @@ PMS.configure do |config|
|
|
|
161
183
|
# 'Completed' => 'Done',
|
|
162
184
|
# }
|
|
163
185
|
|
|
186
|
+
# Display name for the Testing single-select field on the pipeline project.
|
|
187
|
+
# config.pipeline_testing_field_name = 'Testing'
|
|
188
|
+
|
|
189
|
+
# Display labels for the canonical Testing field option keys.
|
|
190
|
+
# config.pipeline_testing_values = {
|
|
191
|
+
# active: 'Testing',
|
|
192
|
+
# inactive: 'Not testing',
|
|
193
|
+
# }
|
|
194
|
+
|
|
195
|
+
# Whether the pipeline sweep removes aged-out Completed items.
|
|
196
|
+
# config.pipeline_completion_purge_enabled = true
|
|
197
|
+
|
|
198
|
+
# Hours after a project item's last update at which the sweep removes it
|
|
199
|
+
# from the pipeline if its status is Completed.
|
|
200
|
+
# config.pipeline_completion_ttl_hours = 24
|
|
201
|
+
|
|
164
202
|
# config.main_branch = 'main'
|
|
165
203
|
# config.production_branch = 'production'
|
|
166
204
|
|