github-issue-tower-defence-management 1.161.0 → 1.162.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 (32) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/bin/adapter/entry-points/console/consoleOperationApi.js +22 -3
  3. package/bin/adapter/entry-points/console/consoleOperationApi.js.map +1 -1
  4. package/bin/adapter/entry-points/console/ui-dist/assets/{index-CbEryCNT.js → index-CHUtr_4X.js} +2 -2
  5. package/bin/adapter/entry-points/console/ui-dist/index.html +1 -1
  6. package/bin/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.js +41 -0
  7. package/bin/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.js.map +1 -1
  8. package/package.json +1 -1
  9. package/src/adapter/entry-points/console/consoleOperationApi.test.ts +136 -8
  10. package/src/adapter/entry-points/console/consoleOperationApi.ts +25 -3
  11. package/src/adapter/entry-points/console/ui/e2e/consoleTestHarness.ts +13 -1
  12. package/src/adapter/entry-points/console/ui/src/features/console/components/operations/ConsoleOperationMenu.test.tsx +4 -4
  13. package/src/adapter/entry-points/console/ui/src/features/console/components/operations/ConsolePullRequestReviewActions.test.tsx +4 -4
  14. package/src/adapter/entry-points/console/ui/src/features/console/components/operations/ConsolePullRequestReviewActions.tsx +1 -1
  15. package/src/adapter/entry-points/console/ui/src/features/console/hooks/useConsoleOperations.test.ts +3 -3
  16. package/src/adapter/entry-points/console/ui/src/features/console/hooks/useConsoleOperations.ts +2 -2
  17. package/src/adapter/entry-points/console/ui/src/features/console/lib/consoleApi.test.ts +2 -2
  18. package/src/adapter/entry-points/console/ui/src/features/console/logic/actionToast.test.ts +17 -10
  19. package/src/adapter/entry-points/console/ui/src/features/console/logic/actionToast.ts +3 -3
  20. package/src/adapter/entry-points/console/ui/src/features/console/logic/operations.ts +1 -1
  21. package/src/adapter/entry-points/console/ui/src/features/console/pages/ConsoleItemDetailContainer.test.tsx +7 -7
  22. package/src/adapter/entry-points/console/ui/src/features/console/pages/ConsolePage.test.tsx +17 -17
  23. package/src/adapter/entry-points/console/ui-dist/assets/{index-CbEryCNT.js → index-CHUtr_4X.js} +2 -2
  24. package/src/adapter/entry-points/console/ui-dist/index.html +1 -1
  25. package/src/adapter/entry-points/console/webServer.test.ts +66 -5
  26. package/src/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.ts +57 -0
  27. package/src/domain/usecases/adapter-interfaces/IssueRepository.ts +2 -0
  28. package/types/adapter/entry-points/console/consoleOperationApi.d.ts.map +1 -1
  29. package/types/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.d.ts +2 -0
  30. package/types/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.d.ts.map +1 -1
  31. package/types/domain/usecases/adapter-interfaces/IssueRepository.d.ts +2 -0
  32. package/types/domain/usecases/adapter-interfaces/IssueRepository.d.ts.map +1 -1
@@ -379,6 +379,16 @@ const awaitingQualityCheckPullRequest: RelatedPullRequest = {
379
379
  missingRequiredCheckNames: ['build', 'test'],
380
380
  };
381
381
 
382
+ const awaitingQualityCheckPullRequestMergeReady: RelatedPullRequest = {
383
+ ...awaitingQualityCheckPullRequest,
384
+ isConflicted: false,
385
+ mergeable: 'MERGEABLE',
386
+ isPassedAllCiJob: true,
387
+ isCiStateSuccess: true,
388
+ isBranchOutOfDate: false,
389
+ missingRequiredCheckNames: [],
390
+ };
391
+
382
392
  const inlineCommentPullRequestDetail: PullRequestDetail = {
383
393
  title: 'Add inline review comments on the related pull request diff',
384
394
  state: 'open',
@@ -428,7 +438,7 @@ const createStubIssueRepository = (
428
438
  url: string,
429
439
  ): Promise<RelatedPullRequest | null> =>
430
440
  url === CONSOLE_E2E_AWAITING_QUALITY_CHECK_PR_URL
431
- ? awaitingQualityCheckPullRequest
441
+ ? awaitingQualityCheckPullRequestMergeReady
432
442
  : null,
433
443
  getOpenPullRequestCiStatus: async (
434
444
  url: string,
@@ -457,7 +467,9 @@ const createStubIssueRepository = (
457
467
  ]),
458
468
  ),
459
469
  getPullRequestChangedFilePaths: async (): Promise<string[]> => [],
470
+ getAuthenticatedUserLogin: async (): Promise<string> => 'test-user',
460
471
  approvePullRequest: async (): Promise<void> => undefined,
472
+ mergePullRequest: async (): Promise<void> => undefined,
461
473
  requestChangesWithInlineComment: async (
462
474
  prUrl: string,
463
475
  changedFilePath: string | null,
@@ -32,7 +32,7 @@ describe('ConsoleOperationMenu', () => {
32
32
  handlers={handlers}
33
33
  />,
34
34
  );
35
- expect(getByText('Approve')).toBeInTheDocument();
35
+ expect(getByText('Approve & Merge')).toBeInTheDocument();
36
36
  expect(getByText('+1 day')).toBeInTheDocument();
37
37
  expect(getByText('Awaiting Workspace')).toBeInTheDocument();
38
38
  expect(getByText('Close')).toBeInTheDocument();
@@ -100,7 +100,7 @@ describe('ConsoleOperationMenu', () => {
100
100
  handlers={handlers}
101
101
  />,
102
102
  );
103
- expect(queryByText('Approve')).toBeNull();
103
+ expect(queryByText('Approve & Merge')).toBeNull();
104
104
  expect(queryByText('Close')).not.toBeNull();
105
105
  });
106
106
 
@@ -121,7 +121,7 @@ describe('ConsoleOperationMenu', () => {
121
121
  expect(getByText('Close as not planned')).toBeInTheDocument();
122
122
  expect(getByText('+1 day')).toBeInTheDocument();
123
123
  expect(queryByText('Move to Okinawa')).toBeNull();
124
- expect(queryByText('Approve')).toBeNull();
124
+ expect(queryByText('Approve & Merge')).toBeNull();
125
125
  });
126
126
 
127
127
  it('shows the review group on the workflow-blocker tab when the item has a pull request', () => {
@@ -136,7 +136,7 @@ describe('ConsoleOperationMenu', () => {
136
136
  handlers={handlers}
137
137
  />,
138
138
  );
139
- expect(getByText('Approve')).toBeInTheDocument();
139
+ expect(getByText('Approve & Merge')).toBeInTheDocument();
140
140
  expect(getByText('Close')).toBeInTheDocument();
141
141
  });
142
142
 
@@ -13,7 +13,7 @@ describe('ConsolePullRequestReviewActions', () => {
13
13
  'Unnecessary',
14
14
  'Totally wrong',
15
15
  'Reject',
16
- 'Approve',
16
+ 'Approve & Merge',
17
17
  ]);
18
18
  });
19
19
 
@@ -25,7 +25,7 @@ describe('ConsolePullRequestReviewActions', () => {
25
25
  />,
26
26
  );
27
27
  expect(getByText('Reject')).toBeDisabled();
28
- expect(getByText('Approve')).not.toBeDisabled();
28
+ expect(getByText('Approve & Merge')).not.toBeDisabled();
29
29
  rerender(
30
30
  <ConsolePullRequestReviewActions
31
31
  onReview={() => {}}
@@ -82,12 +82,12 @@ describe('ConsolePullRequestReviewActions', () => {
82
82
  fireEvent.click(getByText('Unnecessary'));
83
83
  fireEvent.click(getByText('Totally wrong'));
84
84
  fireEvent.click(getByText('Reject'));
85
- fireEvent.click(getByText('Approve'));
85
+ fireEvent.click(getByText('Approve & Merge'));
86
86
  expect(onReview.mock.calls.map((call) => call[0])).toEqual([
87
87
  'unnecessary',
88
88
  'totally_wrong',
89
89
  'request_changes',
90
- 'approve',
90
+ 'approve_and_merge',
91
91
  ]);
92
92
  });
93
93
  });
@@ -13,7 +13,7 @@ const REVIEW_BUTTONS: {
13
13
  { action: 'unnecessary', label: 'Unnecessary', variant: 'unneeded' },
14
14
  { action: 'totally_wrong', label: 'Totally wrong', variant: 'wrong' },
15
15
  { action: 'request_changes', label: 'Reject', variant: 'reject' },
16
- { action: 'approve', label: 'Approve', variant: 'approve' },
16
+ { action: 'approve_and_merge', label: 'Approve & Merge', variant: 'approve' },
17
17
  ];
18
18
 
19
19
  const REJECT_REQUIREMENT_MESSAGE =
@@ -111,7 +111,7 @@ describe('useConsoleOperations', () => {
111
111
  await result.current.operations.reviewPullRequest(
112
112
  prItem,
113
113
  prItem.url,
114
- 'approve',
114
+ 'approve_and_merge',
115
115
  );
116
116
  });
117
117
  const stored = JSON.parse(
@@ -362,7 +362,7 @@ describe('useConsoleOperations', () => {
362
362
  await result.current.operations.reviewPullRequest(
363
363
  prItem,
364
364
  prItem.url,
365
- 'approve',
365
+ 'approve_and_merge',
366
366
  );
367
367
  });
368
368
  const key = `${prItem.repo}#${prItem.number}`;
@@ -410,7 +410,7 @@ describe('useConsoleOperations', () => {
410
410
  result.current.operations.reviewPullRequest(
411
411
  prItem,
412
412
  prItem.url,
413
- 'approve',
413
+ 'approve_and_merge',
414
414
  ),
415
415
  ).rejects.toThrow('No project specified in the URL path.');
416
416
  expect(fetchMock).not.toHaveBeenCalled();
@@ -79,10 +79,10 @@ const reviewRequest = (
79
79
  action: ConsoleReviewAction,
80
80
  pendingReviewComments: ConsolePendingReviewComment[],
81
81
  ): ConsoleReviewRequest => {
82
- if (action === 'approve') {
82
+ if (action === 'approve_and_merge') {
83
83
  return {
84
84
  pjcode,
85
- action: 'approve',
85
+ action: 'approve_and_merge',
86
86
  prUrl,
87
87
  projectItemId: item.projectItemId,
88
88
  };
@@ -257,7 +257,7 @@ describe('postConsoleOperation', () => {
257
257
  const fetchMock = mockFetchOnce({ ok: true });
258
258
  await postConsoleOperation('/api/review', {
259
259
  pjcode: 'acme',
260
- action: 'approve',
260
+ action: 'approve_and_merge',
261
261
  prUrl: 'https://github.com/o/r/pull/1',
262
262
  projectItemId: 'PVTI_1',
263
263
  });
@@ -269,7 +269,7 @@ describe('postConsoleOperation', () => {
269
269
  const failingReview = (): Promise<void> =>
270
270
  postConsoleOperation('/api/review', {
271
271
  pjcode: 'acme',
272
- action: 'approve',
272
+ action: 'approve_and_merge',
273
273
  prUrl: 'https://github.com/o/r/pull/1',
274
274
  projectItemId: 'PVTI_1',
275
275
  });
@@ -31,8 +31,11 @@ describe('itemToastLabel', () => {
31
31
  describe('actionToastMessage', () => {
32
32
  it('labels review actions', () => {
33
33
  expect(
34
- actionToastMessage({ type: 'review', action: 'approve' }, 'prs'),
35
- ).toBe('Approved');
34
+ actionToastMessage(
35
+ { type: 'review', action: 'approve_and_merge' },
36
+ 'prs',
37
+ ),
38
+ ).toBe('Approved & Merged');
36
39
  expect(
37
40
  actionToastMessage({ type: 'review', action: 'request_changes' }, 'prs'),
38
41
  ).toBe('Rejected');
@@ -105,9 +108,9 @@ describe('actionToastMessage', () => {
105
108
 
106
109
  describe('actionToastColor', () => {
107
110
  it('colors each action group like the reference', () => {
108
- expect(actionToastColor({ type: 'review', action: 'approve' })).toBe(
109
- 'green',
110
- );
111
+ expect(
112
+ actionToastColor({ type: 'review', action: 'approve_and_merge' }),
113
+ ).toBe('green');
111
114
  expect(
112
115
  actionToastColor({ type: 'review', action: 'request_changes' }),
113
116
  ).toBe('amber');
@@ -129,9 +132,9 @@ describe('actionToastColor', () => {
129
132
 
130
133
  describe('actionAdvances', () => {
131
134
  it('advances every non-snooze action in every tab', () => {
132
- expect(actionAdvances({ type: 'review', action: 'approve' }, 'prs')).toBe(
133
- true,
134
- );
135
+ expect(
136
+ actionAdvances({ type: 'review', action: 'approve_and_merge' }, 'prs'),
137
+ ).toBe(true);
135
138
  expect(actionAdvances({ type: 'set_status', optionName: 'x' }, 'prs')).toBe(
136
139
  true,
137
140
  );
@@ -151,7 +154,11 @@ describe('actionAdvances', () => {
151
154
  describe('formatActionToast', () => {
152
155
  it('combines the message and the item label', () => {
153
156
  expect(
154
- formatActionToast({ type: 'review', action: 'approve' }, prItem, 'prs'),
155
- ).toBe(`Approved PR #${prItem.number}`);
157
+ formatActionToast(
158
+ { type: 'review', action: 'approve_and_merge' },
159
+ prItem,
160
+ 'prs',
161
+ ),
162
+ ).toBe(`Approved & Merged — PR #${prItem.number}`);
156
163
  });
157
164
  });
@@ -33,8 +33,8 @@ export const actionToastMessage = (
33
33
  ): string => {
34
34
  switch (kind.type) {
35
35
  case 'review':
36
- if (kind.action === 'approve') {
37
- return 'Approved';
36
+ if (kind.action === 'approve_and_merge') {
37
+ return 'Approved & Merged';
38
38
  }
39
39
  if (kind.action === 'request_changes') {
40
40
  return 'Rejected';
@@ -66,7 +66,7 @@ export const actionToastColor = (
66
66
  ): ConsoleToastColor => {
67
67
  switch (kind.type) {
68
68
  case 'review':
69
- if (kind.action === 'approve') {
69
+ if (kind.action === 'approve_and_merge') {
70
70
  return 'green';
71
71
  }
72
72
  if (kind.action === 'request_changes') {
@@ -22,7 +22,7 @@ export const buildRequestChangesBody = (
22
22
  .join('\n\n');
23
23
 
24
24
  export type ConsoleReviewAction =
25
- | 'approve'
25
+ | 'approve_and_merge'
26
26
  | 'request_changes'
27
27
  | 'unnecessary'
28
28
  | 'totally_wrong';
@@ -117,19 +117,19 @@ describe('ConsoleItemDetailContainer', () => {
117
117
  />,
118
118
  );
119
119
  await waitFor(() => {
120
- expect(getByText('Approve')).toBeInTheDocument();
120
+ expect(getByText('Approve & Merge')).toBeInTheDocument();
121
121
  });
122
- fireEvent.click(getByText('Approve'));
122
+ fireEvent.click(getByText('Approve & Merge'));
123
123
  expect(onQueueAction).toHaveBeenCalledTimes(1);
124
124
  const input = onQueueAction.mock.calls[0][0];
125
- expect(input.kind).toEqual({ type: 'review', action: 'approve' });
125
+ expect(input.kind).toEqual({ type: 'review', action: 'approve_and_merge' });
126
126
  expect(input.item).toBe(prItem);
127
127
  expect(operations.reviewPullRequest).not.toHaveBeenCalled();
128
128
  input.commit();
129
129
  expect(operations.reviewPullRequest).toHaveBeenCalledWith(
130
130
  prItem,
131
131
  prItem.url,
132
- 'approve',
132
+ 'approve_and_merge',
133
133
  [],
134
134
  );
135
135
  });
@@ -318,14 +318,14 @@ describe('ConsoleItemDetailContainer', () => {
318
318
  />,
319
319
  );
320
320
 
321
- expect(getByText('Approve')).toBeInTheDocument();
322
- fireEvent.click(getByText('Approve'));
321
+ expect(getByText('Approve & Merge')).toBeInTheDocument();
322
+ fireEvent.click(getByText('Approve & Merge'));
323
323
  const input = onQueueAction.mock.calls[0][0];
324
324
  input.commit();
325
325
  expect(operations.reviewPullRequest).toHaveBeenCalledWith(
326
326
  itemWithBakedPullRequest,
327
327
  bakedPullRequestUrl,
328
- 'approve',
328
+ 'approve_and_merge',
329
329
  [],
330
330
  );
331
331
  });
@@ -124,7 +124,7 @@ describe('ConsolePage', () => {
124
124
  expect(getByText('Add serveConsole subcommand')).toBeInTheDocument();
125
125
  });
126
126
  fireEvent.click(getByText('Add serveConsole subcommand'));
127
- expect(await findByText('Approve')).toBeInTheDocument();
127
+ expect(await findByText('Approve & Merge')).toBeInTheDocument();
128
128
  expect(queryByText('In Tmux by human')).toBeNull();
129
129
  const chip = container.querySelector('.console-detail-status-chip');
130
130
  expect(chip?.textContent).toBe('Awaiting Quality Check');
@@ -146,7 +146,7 @@ describe('ConsolePage', () => {
146
146
  expect(getByText('Add serveConsole subcommand')).toBeInTheDocument();
147
147
  });
148
148
  fireEvent.click(getByText('Add serveConsole subcommand'));
149
- expect(await findByText('Approve')).toBeInTheDocument();
149
+ expect(await findByText('Approve & Merge')).toBeInTheDocument();
150
150
  expect(
151
151
  container.querySelector('.console-detail-status-chip')?.textContent,
152
152
  ).toBe('In Tmux by human');
@@ -158,7 +158,7 @@ describe('ConsolePage', () => {
158
158
  expect(getByText('Add serveConsole subcommand')).toBeInTheDocument();
159
159
  });
160
160
  fireEvent.click(getByText('Add serveConsole subcommand'));
161
- expect(await findByText('Approve')).toBeInTheDocument();
161
+ expect(await findByText('Approve & Merge')).toBeInTheDocument();
162
162
  expect(window.location.hash).toBe('#item/PVTI_1');
163
163
  });
164
164
 
@@ -186,10 +186,10 @@ describe('ConsolePage', () => {
186
186
  ).toBe('1');
187
187
 
188
188
  fireEvent.click(getByText('Add serveConsole subcommand'));
189
- expect(await findByText('Approve')).toBeInTheDocument();
190
- fireEvent.click(getByText('Approve'));
189
+ expect(await findByText('Approve & Merge')).toBeInTheDocument();
190
+ fireEvent.click(getByText('Approve & Merge'));
191
191
 
192
- expect(getByText('Approved — PR #851')).toBeInTheDocument();
192
+ expect(getByText('Approved & Merged — PR #851')).toBeInTheDocument();
193
193
  expect(getByText('Undo')).toBeInTheDocument();
194
194
  expect(
195
195
  within(tabBar())
@@ -242,8 +242,8 @@ describe('ConsolePage', () => {
242
242
  expect(getByText('Add serveConsole subcommand')).toBeInTheDocument();
243
243
  });
244
244
  fireEvent.click(getByText('Add serveConsole subcommand'));
245
- expect(await findByText('Approve')).toBeInTheDocument();
246
- fireEvent.click(getByText('Approve'));
245
+ expect(await findByText('Approve & Merge')).toBeInTheDocument();
246
+ fireEvent.click(getByText('Approve & Merge'));
247
247
 
248
248
  fireEvent.click(getByText('Undo'));
249
249
  act(() => {
@@ -486,7 +486,7 @@ describe('ConsolePage', () => {
486
486
  expect(getByText('Add serveConsole subcommand')).toBeInTheDocument();
487
487
  });
488
488
  fireEvent.click(getByText('Add serveConsole subcommand'));
489
- fireEvent.click(await findByText('Approve'));
489
+ fireEvent.click(await findByText('Approve & Merge'));
490
490
 
491
491
  await act(async () => {
492
492
  jest.advanceTimersByTime(5100);
@@ -603,7 +603,7 @@ describe('ConsolePage swipe navigation', () => {
603
603
  expect(getByText('Add serveConsole subcommand')).toBeInTheDocument();
604
604
  });
605
605
  fireEvent.click(getByText('Add serveConsole subcommand'));
606
- expect(await findByText('Approve')).toBeInTheDocument();
606
+ expect(await findByText('Approve & Merge')).toBeInTheDocument();
607
607
  expect(window.location.hash).toBe('#item/PVTI_1');
608
608
 
609
609
  const detailScreen = container.querySelector('.console-detail-screen');
@@ -627,7 +627,7 @@ describe('ConsolePage swipe navigation', () => {
627
627
  ).toBeInTheDocument();
628
628
  });
629
629
  fireEvent.click(getByText('Add server-side console API handlers'));
630
- expect(await findByText('Approve')).toBeInTheDocument();
630
+ expect(await findByText('Approve & Merge')).toBeInTheDocument();
631
631
  expect(window.location.hash).toBe('#item/PVTI_2');
632
632
 
633
633
  const detailScreen = container.querySelector('.console-detail-screen');
@@ -673,10 +673,10 @@ describe('ConsolePage auto-advance', () => {
673
673
  expect(getByText('Add serveConsole subcommand')).toBeInTheDocument();
674
674
  });
675
675
  fireEvent.click(getByText('Add serveConsole subcommand'));
676
- expect(await findByText('Approve')).toBeInTheDocument();
676
+ expect(await findByText('Approve & Merge')).toBeInTheDocument();
677
677
  expect(window.location.hash).toBe('#item/PVTI_1');
678
678
 
679
- fireEvent.click(getByText('Approve'));
679
+ fireEvent.click(getByText('Approve & Merge'));
680
680
 
681
681
  await waitFor(() => {
682
682
  expect(window.location.hash).toBe('#item/PVTI_2');
@@ -717,7 +717,7 @@ describe('ConsolePage scroll reset', () => {
717
717
  });
718
718
 
719
719
  fireEvent.click(getByText('Add serveConsole subcommand'));
720
- expect(await findByText('Approve')).toBeInTheDocument();
720
+ expect(await findByText('Approve & Merge')).toBeInTheDocument();
721
721
 
722
722
  expect(scrollTo).toHaveBeenCalledWith({ top: 0 });
723
723
  });
@@ -731,7 +731,7 @@ describe('ConsolePage scroll reset', () => {
731
731
  });
732
732
 
733
733
  fireEvent.click(getByText('Add serveConsole subcommand'));
734
- expect(await findByText('Approve')).toBeInTheDocument();
734
+ expect(await findByText('Approve & Merge')).toBeInTheDocument();
735
735
  scrollTo.mockClear();
736
736
 
737
737
  const detailScreen = container.querySelector('.console-detail-screen');
@@ -800,7 +800,7 @@ describe('ConsolePage comment composer isolation', () => {
800
800
  });
801
801
 
802
802
  fireEvent.click(getByText('Add serveConsole subcommand'));
803
- expect(await findByText('Approve')).toBeInTheDocument();
803
+ expect(await findByText('Approve & Merge')).toBeInTheDocument();
804
804
 
805
805
  fireEvent.change(getByPlaceholderText('Leave a comment…'), {
806
806
  target: { value: 'first item only comment' },
@@ -842,7 +842,7 @@ describe('ConsolePage auto-advance tab', () => {
842
842
  });
843
843
 
844
844
  fireEvent.click(getByText('Add serveConsole subcommand'));
845
- fireEvent.click(await findByText('Approve'));
845
+ fireEvent.click(await findByText('Approve & Merge'));
846
846
 
847
847
  act(() => {
848
848
  jest.advanceTimersByTime(5100);