github-issue-tower-defence-management 1.112.5 → 1.113.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.
- package/CHANGELOG.md +14 -0
- package/bin/adapter/entry-points/cli/index.js +1 -0
- package/bin/adapter/entry-points/cli/index.js.map +1 -1
- package/bin/adapter/entry-points/console/consoleReadApi.js +47 -1
- package/bin/adapter/entry-points/console/consoleReadApi.js.map +1 -1
- package/bin/adapter/entry-points/console/ui-dist/assets/{index-BvWrFBsC.css → index-CEJmPNRK.css} +1 -1
- package/bin/adapter/entry-points/console/ui-dist/assets/index-DfNrA5uV.js +101 -0
- package/bin/adapter/entry-points/console/ui-dist/index.html +2 -2
- package/bin/adapter/entry-points/console/webServer.js +6 -0
- package/bin/adapter/entry-points/console/webServer.js.map +1 -1
- package/package.json +1 -1
- package/src/adapter/entry-points/cli/index.ts +5 -1
- package/src/adapter/entry-points/console/consoleReadApi.test.ts +89 -0
- package/src/adapter/entry-points/console/consoleReadApi.ts +71 -0
- package/src/adapter/entry-points/console/ui/e2e/consoleScenario.spec.ts +98 -0
- package/src/adapter/entry-points/console/ui/e2e/consoleTestHarness.ts +135 -10
- package/src/adapter/entry-points/console/ui/src/features/console/components/detail/ConsoleItemDetail.stories.tsx +44 -0
- package/src/adapter/entry-points/console/ui/src/features/console/components/detail/ConsoleItemDetail.test.tsx +56 -0
- package/src/adapter/entry-points/console/ui/src/features/console/components/detail/ConsoleItemDetail.tsx +22 -0
- package/src/adapter/entry-points/console/ui/src/features/console/components/detail/ConsolePullRequestDetail.stories.tsx +17 -0
- package/src/adapter/entry-points/console/ui/src/features/console/components/detail/ConsolePullRequestDetail.test.tsx +46 -0
- package/src/adapter/entry-points/console/ui/src/features/console/components/detail/ConsolePullRequestDetail.tsx +12 -0
- package/src/adapter/entry-points/console/ui/src/features/console/components/detail/ConsolePullRequestStatusBadges.stories.tsx +41 -0
- package/src/adapter/entry-points/console/ui/src/features/console/components/detail/ConsolePullRequestStatusBadges.test.tsx +72 -0
- package/src/adapter/entry-points/console/ui/src/features/console/components/detail/ConsolePullRequestStatusBadges.tsx +71 -0
- package/src/adapter/entry-points/console/ui/src/features/console/hooks/useConsoleCaches.ts +5 -0
- package/src/adapter/entry-points/console/ui/src/features/console/hooks/useConsoleItemDetailData.test.ts +20 -0
- package/src/adapter/entry-points/console/ui/src/features/console/hooks/useConsoleItemDetailData.ts +17 -0
- package/src/adapter/entry-points/console/ui/src/features/console/lib/consoleApi.test.ts +41 -0
- package/src/adapter/entry-points/console/ui/src/features/console/lib/consoleApi.ts +36 -5
- package/src/adapter/entry-points/console/ui/src/features/console/logic/types.ts +9 -0
- package/src/adapter/entry-points/console/ui/src/features/console/pages/ConsoleItemDetailContainer.test.tsx +77 -3
- package/src/adapter/entry-points/console/ui/src/features/console/pages/ConsoleItemDetailContainer.tsx +17 -9
- package/src/adapter/entry-points/console/ui/src/index.css +15 -1
- package/src/adapter/entry-points/console/ui-dist/assets/{index-BvWrFBsC.css → index-CEJmPNRK.css} +1 -1
- package/src/adapter/entry-points/console/ui-dist/assets/index-DfNrA5uV.js +101 -0
- package/src/adapter/entry-points/console/ui-dist/index.html +2 -2
- package/src/adapter/entry-points/console/webServer.test.ts +52 -1
- package/src/adapter/entry-points/console/webServer.ts +13 -0
- package/types/adapter/entry-points/cli/index.d.ts.map +1 -1
- package/types/adapter/entry-points/console/consoleReadApi.d.ts +20 -0
- package/types/adapter/entry-points/console/consoleReadApi.d.ts.map +1 -1
- package/types/adapter/entry-points/console/webServer.d.ts +2 -1
- package/types/adapter/entry-points/console/webServer.d.ts.map +1 -1
- package/bin/adapter/entry-points/console/ui-dist/assets/index-DNBjBIvK.js +0 -101
- package/src/adapter/entry-points/console/ui-dist/assets/index-DNBjBIvK.js +0 -101
|
@@ -9,15 +9,27 @@ import type {
|
|
|
9
9
|
IssueRepository,
|
|
10
10
|
PullRequestCommit,
|
|
11
11
|
PullRequestDetail,
|
|
12
|
+
PullRequestFile,
|
|
12
13
|
RelatedPullRequest,
|
|
13
14
|
} from '../../../../../domain/usecases/adapter-interfaces/IssueRepository';
|
|
14
15
|
import type { ConsoleProjectBinding } from '../../consoleOperationApi';
|
|
15
|
-
import {
|
|
16
|
+
import {
|
|
17
|
+
IssueTitleStateCache,
|
|
18
|
+
PullRequestStatusCache,
|
|
19
|
+
} from '../../consoleReadApi';
|
|
16
20
|
import { startWebServer } from '../../webServer';
|
|
17
21
|
|
|
18
22
|
export const CONSOLE_E2E_PJCODE = 'umino';
|
|
19
23
|
export const CONSOLE_E2E_TOKEN = 'console-e2e-fixture-token-3f9c1a';
|
|
20
24
|
|
|
25
|
+
export type ConsoleE2eReviewCommentCall = {
|
|
26
|
+
url: string;
|
|
27
|
+
path: string;
|
|
28
|
+
line: number;
|
|
29
|
+
side: string;
|
|
30
|
+
body: string;
|
|
31
|
+
};
|
|
32
|
+
|
|
21
33
|
type ConsoleFixtureListItem = {
|
|
22
34
|
number: number;
|
|
23
35
|
title: string;
|
|
@@ -54,6 +66,26 @@ type ConsoleFixtureSnapshot = {
|
|
|
54
66
|
const REPO_NAME_WITH_OWNER =
|
|
55
67
|
'HiromiShikata/npm-cli-github-issue-tower-defence-management';
|
|
56
68
|
|
|
69
|
+
export const CONSOLE_E2E_AWAITING_QUALITY_CHECK_PR_URL = `https://github.com/${REPO_NAME_WITH_OWNER}/pull/867`;
|
|
70
|
+
export const CONSOLE_E2E_INLINE_COMMENT_ISSUE_URL = `https://github.com/${REPO_NAME_WITH_OWNER}/issues/911`;
|
|
71
|
+
export const CONSOLE_E2E_INLINE_COMMENT_PR_URL = `https://github.com/${REPO_NAME_WITH_OWNER}/pull/912`;
|
|
72
|
+
|
|
73
|
+
const INLINE_COMMENT_PR_FILE: PullRequestFile = {
|
|
74
|
+
filename: 'src/adapter/entry-points/console/ui/src/index.css',
|
|
75
|
+
status: 'modified',
|
|
76
|
+
additions: 3,
|
|
77
|
+
deletions: 1,
|
|
78
|
+
patch: `@@ -959,7 +959,9 @@
|
|
79
|
+
background: transparent;
|
|
80
|
+
color: #6e7681;
|
|
81
|
+
font-size: 0.875rem;
|
|
82
|
+
cursor: pointer;
|
|
83
|
+
- opacity: 0;
|
|
84
|
+
+ opacity: 0.6;
|
|
85
|
+
+ border-color: #30363d;
|
|
86
|
+
}`,
|
|
87
|
+
};
|
|
88
|
+
|
|
57
89
|
const AWAITING_WORKSPACE_OPTION: ConsoleFixtureFieldOption = {
|
|
58
90
|
id: 'd1c19cce',
|
|
59
91
|
name: 'Awaiting Workspace',
|
|
@@ -198,7 +230,15 @@ export const CONSOLE_E2E_TAB_ITEMS: Record<string, ConsoleFixtureListItem[]> = {
|
|
|
198
230
|
'2026-06-17T05:48:09.000Z',
|
|
199
231
|
),
|
|
200
232
|
],
|
|
201
|
-
'failed-preparation': [
|
|
233
|
+
'failed-preparation': [
|
|
234
|
+
issueItem(
|
|
235
|
+
911,
|
|
236
|
+
'Add inline review comments on the related pull request diff',
|
|
237
|
+
'FPR00911',
|
|
238
|
+
'TDPM Console port',
|
|
239
|
+
'2026-06-18T03:12:00.000Z',
|
|
240
|
+
),
|
|
241
|
+
],
|
|
202
242
|
'todo-by-human': [
|
|
203
243
|
issueItem(
|
|
204
244
|
869,
|
|
@@ -286,7 +326,49 @@ const notImplemented = (method: string): never => {
|
|
|
286
326
|
throw new Error(`console E2E stub does not implement ${method}`);
|
|
287
327
|
};
|
|
288
328
|
|
|
289
|
-
const
|
|
329
|
+
const inlineCommentRelatedPullRequest: RelatedPullRequest = {
|
|
330
|
+
url: CONSOLE_E2E_INLINE_COMMENT_PR_URL,
|
|
331
|
+
branchName: 'feature/911-related-pr-inline-comments',
|
|
332
|
+
createdAt: new Date('2026-06-18T03:30:00.000Z'),
|
|
333
|
+
isDraft: false,
|
|
334
|
+
isConflicted: true,
|
|
335
|
+
isPassedAllCiJob: false,
|
|
336
|
+
isCiStateSuccess: false,
|
|
337
|
+
isResolvedAllReviewComments: false,
|
|
338
|
+
isBranchOutOfDate: true,
|
|
339
|
+
missingRequiredCheckNames: ['build', 'test'],
|
|
340
|
+
};
|
|
341
|
+
|
|
342
|
+
const awaitingQualityCheckPullRequest: RelatedPullRequest = {
|
|
343
|
+
url: CONSOLE_E2E_AWAITING_QUALITY_CHECK_PR_URL,
|
|
344
|
+
branchName: 'i867-serve-committed-console-ui-bundle',
|
|
345
|
+
createdAt: new Date('2026-06-17T23:41:08.000Z'),
|
|
346
|
+
isDraft: false,
|
|
347
|
+
isConflicted: true,
|
|
348
|
+
isPassedAllCiJob: false,
|
|
349
|
+
isCiStateSuccess: false,
|
|
350
|
+
isResolvedAllReviewComments: false,
|
|
351
|
+
isBranchOutOfDate: true,
|
|
352
|
+
missingRequiredCheckNames: ['build', 'test'],
|
|
353
|
+
};
|
|
354
|
+
|
|
355
|
+
const inlineCommentPullRequestDetail: PullRequestDetail = {
|
|
356
|
+
title: 'Add inline review comments on the related pull request diff',
|
|
357
|
+
state: 'open',
|
|
358
|
+
merged: false,
|
|
359
|
+
isDraft: false,
|
|
360
|
+
additions: 3,
|
|
361
|
+
deletions: 1,
|
|
362
|
+
changedFiles: 1,
|
|
363
|
+
headRefName: 'feature/911-related-pr-inline-comments',
|
|
364
|
+
baseRefName: 'main',
|
|
365
|
+
author: 'HiromiShikata',
|
|
366
|
+
files: [INLINE_COMMENT_PR_FILE],
|
|
367
|
+
};
|
|
368
|
+
|
|
369
|
+
const createStubIssueRepository = (
|
|
370
|
+
reviewCommentCalls: ConsoleE2eReviewCommentCall[],
|
|
371
|
+
): IssueRepository => ({
|
|
290
372
|
getAllIssues: () => notImplemented('getAllIssues'),
|
|
291
373
|
getIssueByUrl: async (url: string): Promise<Issue | null> =>
|
|
292
374
|
buildIssueForUrl(url),
|
|
@@ -306,12 +388,34 @@ const createStubIssueRepository = (): IssueRepository => ({
|
|
|
306
388
|
get: async (issueUrl: string): Promise<Issue | null> =>
|
|
307
389
|
buildIssueForUrl(issueUrl),
|
|
308
390
|
update: () => notImplemented('update'),
|
|
309
|
-
findRelatedOpenPRs: async (): Promise<RelatedPullRequest[]> =>
|
|
310
|
-
|
|
391
|
+
findRelatedOpenPRs: async (url: string): Promise<RelatedPullRequest[]> =>
|
|
392
|
+
url === CONSOLE_E2E_INLINE_COMMENT_ISSUE_URL
|
|
393
|
+
? [inlineCommentRelatedPullRequest]
|
|
394
|
+
: [],
|
|
395
|
+
getOpenPullRequest: async (
|
|
396
|
+
url: string,
|
|
397
|
+
): Promise<RelatedPullRequest | null> =>
|
|
398
|
+
url === CONSOLE_E2E_AWAITING_QUALITY_CHECK_PR_URL
|
|
399
|
+
? awaitingQualityCheckPullRequest
|
|
400
|
+
: null,
|
|
311
401
|
getPullRequestChangedFilePaths: async (): Promise<string[]> => [],
|
|
312
402
|
approvePullRequest: async (): Promise<void> => undefined,
|
|
313
403
|
requestChangesWithInlineComment: async (): Promise<void> => undefined,
|
|
314
|
-
createPullRequestReviewComment: async (
|
|
404
|
+
createPullRequestReviewComment: async (
|
|
405
|
+
prUrl: string,
|
|
406
|
+
filePath: string,
|
|
407
|
+
line: number,
|
|
408
|
+
side: string,
|
|
409
|
+
commentBody: string,
|
|
410
|
+
): Promise<void> => {
|
|
411
|
+
reviewCommentCalls.push({
|
|
412
|
+
url: prUrl,
|
|
413
|
+
path: filePath,
|
|
414
|
+
line,
|
|
415
|
+
side,
|
|
416
|
+
body: commentBody,
|
|
417
|
+
});
|
|
418
|
+
},
|
|
315
419
|
closePullRequest: async (): Promise<void> => undefined,
|
|
316
420
|
closeIssueByUrl: async (): Promise<void> => undefined,
|
|
317
421
|
deletePullRequestBranch: () => notImplemented('deletePullRequestBranch'),
|
|
@@ -323,7 +427,12 @@ const createStubIssueRepository = (): IssueRepository => ({
|
|
|
323
427
|
getIssueOrPullRequestBody: async (): Promise<string> =>
|
|
324
428
|
'## Console E2E fixture\n\nThis body is served by the isolated E2E stub.',
|
|
325
429
|
getIssueOrPullRequestComments: async (): Promise<IssueComment[]> => [],
|
|
326
|
-
getPullRequestDetail: async (
|
|
430
|
+
getPullRequestDetail: async (
|
|
431
|
+
url: string,
|
|
432
|
+
): Promise<PullRequestDetail | null> =>
|
|
433
|
+
url === CONSOLE_E2E_INLINE_COMMENT_PR_URL
|
|
434
|
+
? inlineCommentPullRequestDetail
|
|
435
|
+
: null,
|
|
327
436
|
getPullRequestCommits: async (): Promise<PullRequestCommit[]> => [],
|
|
328
437
|
getIssueOrPullRequestState: async (
|
|
329
438
|
url: string,
|
|
@@ -332,13 +441,24 @@ const createStubIssueRepository = (): IssueRepository => ({
|
|
|
332
441
|
merged: false,
|
|
333
442
|
isPullRequest: url.includes('/pull/'),
|
|
334
443
|
}),
|
|
335
|
-
getPullRequestSummary: async (
|
|
444
|
+
getPullRequestSummary: async (
|
|
445
|
+
url: string,
|
|
446
|
+
): Promise<{
|
|
336
447
|
title: string;
|
|
337
448
|
body: string;
|
|
338
449
|
additions: number;
|
|
339
450
|
deletions: number;
|
|
340
451
|
changedFiles: number;
|
|
341
|
-
} | null> =>
|
|
452
|
+
} | null> =>
|
|
453
|
+
url === CONSOLE_E2E_INLINE_COMMENT_PR_URL
|
|
454
|
+
? {
|
|
455
|
+
title: 'Add inline review comments on the related pull request diff',
|
|
456
|
+
body: 'Wires the add-comment handler on the related pull request diff path.',
|
|
457
|
+
additions: 3,
|
|
458
|
+
deletions: 1,
|
|
459
|
+
changedFiles: 1,
|
|
460
|
+
}
|
|
461
|
+
: null,
|
|
342
462
|
});
|
|
343
463
|
|
|
344
464
|
export type ConsoleE2eHarness = {
|
|
@@ -346,6 +466,7 @@ export type ConsoleE2eHarness = {
|
|
|
346
466
|
appUrl: string;
|
|
347
467
|
appRootUrl: string;
|
|
348
468
|
consoleDataOutputDir: string;
|
|
469
|
+
reviewCommentCalls: ConsoleE2eReviewCommentCall[];
|
|
349
470
|
stop: () => Promise<void>;
|
|
350
471
|
};
|
|
351
472
|
|
|
@@ -362,13 +483,16 @@ export const startConsoleE2eHarness = async (): Promise<ConsoleE2eHarness> => {
|
|
|
362
483
|
): Promise<ConsoleProjectBinding | null> =>
|
|
363
484
|
pjcode === CONSOLE_E2E_PJCODE ? { pjcode, project } : null;
|
|
364
485
|
|
|
486
|
+
const reviewCommentCalls: ConsoleE2eReviewCommentCall[] = [];
|
|
487
|
+
|
|
365
488
|
const server = await startWebServer({
|
|
366
489
|
accessToken: CONSOLE_E2E_TOKEN,
|
|
367
490
|
uiDistDir,
|
|
368
491
|
consoleDataOutputDir,
|
|
369
|
-
issueRepository: createStubIssueRepository(),
|
|
492
|
+
issueRepository: createStubIssueRepository(reviewCommentCalls),
|
|
370
493
|
resolveProject,
|
|
371
494
|
issueTitleStateCache: new IssueTitleStateCache(),
|
|
495
|
+
pullRequestStatusCache: new PullRequestStatusCache(),
|
|
372
496
|
inTmuxDataDir: null,
|
|
373
497
|
dashboardDir: null,
|
|
374
498
|
dashboardDataDir: null,
|
|
@@ -391,6 +515,7 @@ export const startConsoleE2eHarness = async (): Promise<ConsoleE2eHarness> => {
|
|
|
391
515
|
appUrl,
|
|
392
516
|
appRootUrl,
|
|
393
517
|
consoleDataOutputDir,
|
|
518
|
+
reviewCommentCalls,
|
|
394
519
|
stop: async (): Promise<void> => {
|
|
395
520
|
await closeServer(server);
|
|
396
521
|
fs.rmSync(tmpRoot, { recursive: true, force: true });
|
|
@@ -81,6 +81,45 @@ export const PullRequestItem: Story = {
|
|
|
81
81
|
commits: consoleCommitsFixture,
|
|
82
82
|
commitsAreLoading: false,
|
|
83
83
|
commitsError: null,
|
|
84
|
+
pullRequestStatus: {
|
|
85
|
+
found: true,
|
|
86
|
+
isConflicted: false,
|
|
87
|
+
isPassedAllCiJob: true,
|
|
88
|
+
isCiStateSuccess: true,
|
|
89
|
+
isBranchOutOfDate: false,
|
|
90
|
+
missingRequiredCheckNames: [],
|
|
91
|
+
},
|
|
92
|
+
relatedPullRequests: [],
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
export const PullRequestItemFailingCiWithConflict: Story = {
|
|
97
|
+
args: {
|
|
98
|
+
item: consoleListItemsFixture[0],
|
|
99
|
+
storyName: 'TDPM Console port',
|
|
100
|
+
storyColorEnum: 'BLUE',
|
|
101
|
+
overlayStatus: { name: 'Awaiting Quality Check', color: 'YELLOW' },
|
|
102
|
+
state: { state: 'open', merged: false, isPullRequest: true },
|
|
103
|
+
body: consoleMermaidBodyFixture,
|
|
104
|
+
bodyIsLoading: false,
|
|
105
|
+
bodyError: null,
|
|
106
|
+
comments: consoleCommentsFixture,
|
|
107
|
+
commentsAreLoading: false,
|
|
108
|
+
commentsError: null,
|
|
109
|
+
files: consoleChangedFilesFixture,
|
|
110
|
+
filesAreLoading: false,
|
|
111
|
+
filesError: null,
|
|
112
|
+
commits: consoleCommitsFixture,
|
|
113
|
+
commitsAreLoading: false,
|
|
114
|
+
commitsError: null,
|
|
115
|
+
pullRequestStatus: {
|
|
116
|
+
found: true,
|
|
117
|
+
isConflicted: true,
|
|
118
|
+
isPassedAllCiJob: false,
|
|
119
|
+
isCiStateSuccess: false,
|
|
120
|
+
isBranchOutOfDate: true,
|
|
121
|
+
missingRequiredCheckNames: ['build', 'test'],
|
|
122
|
+
},
|
|
84
123
|
relatedPullRequests: [],
|
|
85
124
|
},
|
|
86
125
|
};
|
|
@@ -104,6 +143,7 @@ export const IssueWithRichMarkdownBody: Story = {
|
|
|
104
143
|
commits: [],
|
|
105
144
|
commitsAreLoading: false,
|
|
106
145
|
commitsError: null,
|
|
146
|
+
pullRequestStatus: null,
|
|
107
147
|
relatedPullRequests: [],
|
|
108
148
|
operationBar: (
|
|
109
149
|
<ConsoleOperationMenu
|
|
@@ -137,6 +177,7 @@ export const IssueWithLinkedPullRequest: Story = {
|
|
|
137
177
|
commits: [],
|
|
138
178
|
commitsAreLoading: false,
|
|
139
179
|
commitsError: null,
|
|
180
|
+
pullRequestStatus: null,
|
|
140
181
|
relatedPullRequests: [
|
|
141
182
|
{
|
|
142
183
|
pullRequest: consoleRelatedPullRequestsFixture[0],
|
|
@@ -148,5 +189,8 @@ export const IssueWithLinkedPullRequest: Story = {
|
|
|
148
189
|
commitsError: null,
|
|
149
190
|
},
|
|
150
191
|
],
|
|
192
|
+
buildAddInlineComment: (prUrl) => async (path, line, side, body) => {
|
|
193
|
+
window.alert(`comment on ${prUrl} ${path}:${line} (${side})\n${body}`);
|
|
194
|
+
},
|
|
151
195
|
},
|
|
152
196
|
};
|
|
@@ -32,6 +32,7 @@ const baseProps = {
|
|
|
32
32
|
commits: consoleCommitsFixture,
|
|
33
33
|
commitsAreLoading: false,
|
|
34
34
|
commitsError: null,
|
|
35
|
+
pullRequestStatus: null,
|
|
35
36
|
relatedPullRequests: [],
|
|
36
37
|
now,
|
|
37
38
|
commentComposer: <div>comment-composer</div>,
|
|
@@ -115,4 +116,59 @@ describe('ConsoleItemDetail', () => {
|
|
|
115
116
|
expect(title).not.toBeNull();
|
|
116
117
|
expect(title?.contains(getByText('Awaiting Workspace'))).toBe(true);
|
|
117
118
|
});
|
|
119
|
+
|
|
120
|
+
it('renders failing CI, missing checks, and conflict badges in the PR header', () => {
|
|
121
|
+
const { getByText, container } = render(
|
|
122
|
+
<ConsoleItemDetail
|
|
123
|
+
item={prItem}
|
|
124
|
+
{...baseProps}
|
|
125
|
+
pullRequestStatus={{
|
|
126
|
+
found: true,
|
|
127
|
+
isConflicted: true,
|
|
128
|
+
isPassedAllCiJob: false,
|
|
129
|
+
isCiStateSuccess: false,
|
|
130
|
+
isBranchOutOfDate: true,
|
|
131
|
+
missingRequiredCheckNames: ['build', 'test'],
|
|
132
|
+
}}
|
|
133
|
+
/>,
|
|
134
|
+
);
|
|
135
|
+
const title = container.querySelector('.console-detail-title');
|
|
136
|
+
expect(title?.contains(getByText('CI failing'))).toBe(true);
|
|
137
|
+
expect(getByText(/missing: build, test/)).toBeInTheDocument();
|
|
138
|
+
expect(getByText('Conflict')).toBeInTheDocument();
|
|
139
|
+
expect(getByText('Out of date')).toBeInTheDocument();
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it('renders a passing CI badge and no conflict badge when the PR is healthy', () => {
|
|
143
|
+
const { getByText, queryByText } = render(
|
|
144
|
+
<ConsoleItemDetail
|
|
145
|
+
item={prItem}
|
|
146
|
+
{...baseProps}
|
|
147
|
+
pullRequestStatus={{
|
|
148
|
+
found: true,
|
|
149
|
+
isConflicted: false,
|
|
150
|
+
isPassedAllCiJob: true,
|
|
151
|
+
isCiStateSuccess: true,
|
|
152
|
+
isBranchOutOfDate: false,
|
|
153
|
+
missingRequiredCheckNames: [],
|
|
154
|
+
}}
|
|
155
|
+
/>,
|
|
156
|
+
);
|
|
157
|
+
expect(getByText('CI passing')).toBeInTheDocument();
|
|
158
|
+
expect(queryByText('Conflict')).toBeNull();
|
|
159
|
+
expect(queryByText('Out of date')).toBeNull();
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
it('does not render PR status badges for an issue item', () => {
|
|
163
|
+
const { queryByText } = render(
|
|
164
|
+
<ConsoleItemDetail
|
|
165
|
+
item={issueItem}
|
|
166
|
+
{...baseProps}
|
|
167
|
+
state={{ state: 'open', merged: false, isPullRequest: false }}
|
|
168
|
+
pullRequestStatus={null}
|
|
169
|
+
/>,
|
|
170
|
+
);
|
|
171
|
+
expect(queryByText('CI passing')).toBeNull();
|
|
172
|
+
expect(queryByText('CI failing')).toBeNull();
|
|
173
|
+
});
|
|
118
174
|
});
|
|
@@ -13,6 +13,7 @@ import type {
|
|
|
13
13
|
ConsoleIssueState,
|
|
14
14
|
ConsoleListItem,
|
|
15
15
|
ConsoleOverlayStatus,
|
|
16
|
+
ConsolePullRequestStatus,
|
|
16
17
|
ConsoleRelatedPullRequest,
|
|
17
18
|
} from '../../logic/types';
|
|
18
19
|
import { ConsoleMarkdownContent } from '../content/ConsoleMarkdownContent';
|
|
@@ -24,6 +25,7 @@ import { ConsoleCopyUrlButton } from './ConsoleCopyUrlButton';
|
|
|
24
25
|
import type { ConsoleAddInlineComment } from './ConsoleFileDiff';
|
|
25
26
|
import { ConsoleItemIcon } from './ConsoleItemIcon';
|
|
26
27
|
import { ConsolePullRequestDetail } from './ConsolePullRequestDetail';
|
|
28
|
+
import { ConsolePullRequestStatusBadges } from './ConsolePullRequestStatusBadges';
|
|
27
29
|
|
|
28
30
|
export type ConsoleRelatedPullRequestView = {
|
|
29
31
|
pullRequest: ConsoleRelatedPullRequest;
|
|
@@ -53,12 +55,14 @@ export type ConsoleItemDetailProps = {
|
|
|
53
55
|
commits: ConsoleCommit[];
|
|
54
56
|
commitsAreLoading: boolean;
|
|
55
57
|
commitsError: string | null;
|
|
58
|
+
pullRequestStatus: ConsolePullRequestStatus | null;
|
|
56
59
|
relatedPullRequests: ConsoleRelatedPullRequestView[];
|
|
57
60
|
now: number;
|
|
58
61
|
commentComposer: ReactNode;
|
|
59
62
|
operationBar: ReactNode;
|
|
60
63
|
buildImageProxyUrl?: ImageProxyUrlBuilder;
|
|
61
64
|
onAddInlineComment?: ConsoleAddInlineComment;
|
|
65
|
+
buildAddInlineComment?: (prUrl: string) => ConsoleAddInlineComment;
|
|
62
66
|
};
|
|
63
67
|
|
|
64
68
|
export const ConsoleItemDetail = ({
|
|
@@ -79,12 +83,14 @@ export const ConsoleItemDetail = ({
|
|
|
79
83
|
commits,
|
|
80
84
|
commitsAreLoading,
|
|
81
85
|
commitsError,
|
|
86
|
+
pullRequestStatus,
|
|
82
87
|
relatedPullRequests,
|
|
83
88
|
now,
|
|
84
89
|
commentComposer,
|
|
85
90
|
operationBar,
|
|
86
91
|
buildImageProxyUrl,
|
|
87
92
|
onAddInlineComment,
|
|
93
|
+
buildAddInlineComment,
|
|
88
94
|
}: ConsoleItemDetailProps) => {
|
|
89
95
|
const resolvedState = state?.state ?? 'open';
|
|
90
96
|
const merged = state?.merged ?? false;
|
|
@@ -128,6 +134,17 @@ export const ConsoleItemDetail = ({
|
|
|
128
134
|
{overlayStatus.name}
|
|
129
135
|
</span>
|
|
130
136
|
)}
|
|
137
|
+
{item.isPr && pullRequestStatus?.found && (
|
|
138
|
+
<ConsolePullRequestStatusBadges
|
|
139
|
+
isConflicted={pullRequestStatus.isConflicted}
|
|
140
|
+
isPassedAllCiJob={pullRequestStatus.isPassedAllCiJob}
|
|
141
|
+
isCiStateSuccess={pullRequestStatus.isCiStateSuccess}
|
|
142
|
+
isBranchOutOfDate={pullRequestStatus.isBranchOutOfDate}
|
|
143
|
+
missingRequiredCheckNames={
|
|
144
|
+
pullRequestStatus.missingRequiredCheckNames
|
|
145
|
+
}
|
|
146
|
+
/>
|
|
147
|
+
)}
|
|
131
148
|
<ConsoleItemIcon
|
|
132
149
|
isPr={item.isPr}
|
|
133
150
|
state={resolvedState}
|
|
@@ -257,6 +274,11 @@ export const ConsoleItemDetail = ({
|
|
|
257
274
|
commitsError={related.commitsError}
|
|
258
275
|
now={now}
|
|
259
276
|
buildImageProxyUrl={buildImageProxyUrl}
|
|
277
|
+
onAddInlineComment={
|
|
278
|
+
buildAddInlineComment
|
|
279
|
+
? buildAddInlineComment(related.pullRequest.url)
|
|
280
|
+
: undefined
|
|
281
|
+
}
|
|
260
282
|
/>
|
|
261
283
|
))}
|
|
262
284
|
|
|
@@ -29,3 +29,20 @@ export const WithDetail: Story = {
|
|
|
29
29
|
commitsError: null,
|
|
30
30
|
},
|
|
31
31
|
};
|
|
32
|
+
|
|
33
|
+
export const WithInlineComments: Story = {
|
|
34
|
+
args: {
|
|
35
|
+
pullRequest: consoleRelatedPullRequestsFixture[0],
|
|
36
|
+
body: consoleRelatedPullRequestsFixture[0].summary?.body ?? '',
|
|
37
|
+
bodyIsLoading: false,
|
|
38
|
+
files: consoleChangedFilesFixture,
|
|
39
|
+
filesAreLoading: false,
|
|
40
|
+
filesError: null,
|
|
41
|
+
commits: consoleCommitsFixture,
|
|
42
|
+
commitsAreLoading: false,
|
|
43
|
+
commitsError: null,
|
|
44
|
+
onAddInlineComment: async (path, line, side, body) => {
|
|
45
|
+
window.alert(`comment on ${path}:${line} (${side})\n${body}`);
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
};
|
|
@@ -38,6 +38,52 @@ describe('ConsolePullRequestDetail', () => {
|
|
|
38
38
|
expect(getByText('27 files')).toBeInTheDocument();
|
|
39
39
|
});
|
|
40
40
|
|
|
41
|
+
it('renders the CI status badge derived from the pull request fields', () => {
|
|
42
|
+
const { getByText } = render(
|
|
43
|
+
<ConsolePullRequestDetail
|
|
44
|
+
pullRequest={pullRequest}
|
|
45
|
+
body={pullRequest.summary?.body ?? ''}
|
|
46
|
+
bodyIsLoading={false}
|
|
47
|
+
files={consoleChangedFilesFixture}
|
|
48
|
+
filesAreLoading={false}
|
|
49
|
+
filesError={null}
|
|
50
|
+
commits={consoleCommitsFixture}
|
|
51
|
+
commitsAreLoading={false}
|
|
52
|
+
commitsError={null}
|
|
53
|
+
now={now}
|
|
54
|
+
/>,
|
|
55
|
+
);
|
|
56
|
+
expect(getByText('CI passing')).toBeInTheDocument();
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('renders failing CI, conflict and out-of-date badges for an unhealthy pull request', () => {
|
|
60
|
+
const { getByText } = render(
|
|
61
|
+
<ConsolePullRequestDetail
|
|
62
|
+
pullRequest={{
|
|
63
|
+
...pullRequest,
|
|
64
|
+
isConflicted: true,
|
|
65
|
+
isPassedAllCiJob: false,
|
|
66
|
+
isCiStateSuccess: false,
|
|
67
|
+
isBranchOutOfDate: true,
|
|
68
|
+
missingRequiredCheckNames: ['build'],
|
|
69
|
+
}}
|
|
70
|
+
body={pullRequest.summary?.body ?? ''}
|
|
71
|
+
bodyIsLoading={false}
|
|
72
|
+
files={consoleChangedFilesFixture}
|
|
73
|
+
filesAreLoading={false}
|
|
74
|
+
filesError={null}
|
|
75
|
+
commits={consoleCommitsFixture}
|
|
76
|
+
commitsAreLoading={false}
|
|
77
|
+
commitsError={null}
|
|
78
|
+
now={now}
|
|
79
|
+
/>,
|
|
80
|
+
);
|
|
81
|
+
expect(getByText('CI failing')).toBeInTheDocument();
|
|
82
|
+
expect(getByText(/missing: build/)).toBeInTheDocument();
|
|
83
|
+
expect(getByText('Conflict')).toBeInTheDocument();
|
|
84
|
+
expect(getByText('Out of date')).toBeInTheDocument();
|
|
85
|
+
});
|
|
86
|
+
|
|
41
87
|
it('renders a copy URL button for the pull request url', () => {
|
|
42
88
|
const { getByRole } = render(
|
|
43
89
|
<ConsolePullRequestDetail
|
|
@@ -9,6 +9,8 @@ import { ConsolePanel } from '../layout/ConsolePanel';
|
|
|
9
9
|
import { ConsoleChangedFileList } from './ConsoleChangedFileList';
|
|
10
10
|
import { ConsoleCommitList } from './ConsoleCommitList';
|
|
11
11
|
import { ConsoleCopyUrlButton } from './ConsoleCopyUrlButton';
|
|
12
|
+
import type { ConsoleAddInlineComment } from './ConsoleFileDiff';
|
|
13
|
+
import { ConsolePullRequestStatusBadges } from './ConsolePullRequestStatusBadges';
|
|
12
14
|
|
|
13
15
|
export type ConsolePullRequestSectionProps = {
|
|
14
16
|
pullRequest: ConsoleRelatedPullRequest;
|
|
@@ -22,6 +24,7 @@ export type ConsolePullRequestSectionProps = {
|
|
|
22
24
|
commitsError: string | null;
|
|
23
25
|
now: number;
|
|
24
26
|
buildImageProxyUrl?: ImageProxyUrlBuilder;
|
|
27
|
+
onAddInlineComment?: ConsoleAddInlineComment;
|
|
25
28
|
};
|
|
26
29
|
|
|
27
30
|
export const ConsolePullRequestDetail = ({
|
|
@@ -36,6 +39,7 @@ export const ConsolePullRequestDetail = ({
|
|
|
36
39
|
commitsError,
|
|
37
40
|
now,
|
|
38
41
|
buildImageProxyUrl,
|
|
42
|
+
onAddInlineComment,
|
|
39
43
|
}: ConsolePullRequestSectionProps) => {
|
|
40
44
|
const summary = pullRequest.summary;
|
|
41
45
|
const filesCount =
|
|
@@ -56,6 +60,13 @@ export const ConsolePullRequestDetail = ({
|
|
|
56
60
|
{pullRequest.isDraft && (
|
|
57
61
|
<span className="console-pr-section-state">draft</span>
|
|
58
62
|
)}
|
|
63
|
+
<ConsolePullRequestStatusBadges
|
|
64
|
+
isConflicted={pullRequest.isConflicted}
|
|
65
|
+
isPassedAllCiJob={pullRequest.isPassedAllCiJob}
|
|
66
|
+
isCiStateSuccess={pullRequest.isCiStateSuccess}
|
|
67
|
+
isBranchOutOfDate={pullRequest.isBranchOutOfDate}
|
|
68
|
+
missingRequiredCheckNames={pullRequest.missingRequiredCheckNames}
|
|
69
|
+
/>
|
|
59
70
|
<ConsoleCopyUrlButton url={pullRequest.url} label="Copy PR URL" />
|
|
60
71
|
<div className="console-pr-statbar">
|
|
61
72
|
{pullRequest.branchName !== null && (
|
|
@@ -87,6 +98,7 @@ export const ConsolePullRequestDetail = ({
|
|
|
87
98
|
files={files}
|
|
88
99
|
isLoading={filesAreLoading}
|
|
89
100
|
error={filesError}
|
|
101
|
+
onAddInlineComment={onAddInlineComment}
|
|
90
102
|
/>
|
|
91
103
|
</ConsolePanel>
|
|
92
104
|
<ConsolePanel title="Commits" count={commitsCount} defaultCollapsed>
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
2
|
+
import { ConsolePullRequestStatusBadges } from './ConsolePullRequestStatusBadges';
|
|
3
|
+
|
|
4
|
+
const meta: Meta<typeof ConsolePullRequestStatusBadges> = {
|
|
5
|
+
title: 'Console/ConsolePullRequestStatusBadges',
|
|
6
|
+
component: ConsolePullRequestStatusBadges,
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export default meta;
|
|
10
|
+
|
|
11
|
+
type Story = StoryObj<typeof ConsolePullRequestStatusBadges>;
|
|
12
|
+
|
|
13
|
+
export const Passing: Story = {
|
|
14
|
+
args: {
|
|
15
|
+
isConflicted: false,
|
|
16
|
+
isPassedAllCiJob: true,
|
|
17
|
+
isCiStateSuccess: true,
|
|
18
|
+
isBranchOutOfDate: false,
|
|
19
|
+
missingRequiredCheckNames: [],
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export const FailingWithMissingChecks: Story = {
|
|
24
|
+
args: {
|
|
25
|
+
isConflicted: false,
|
|
26
|
+
isPassedAllCiJob: false,
|
|
27
|
+
isCiStateSuccess: false,
|
|
28
|
+
isBranchOutOfDate: false,
|
|
29
|
+
missingRequiredCheckNames: ['build', 'test'],
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export const ConflictedAndOutOfDate: Story = {
|
|
34
|
+
args: {
|
|
35
|
+
isConflicted: true,
|
|
36
|
+
isPassedAllCiJob: false,
|
|
37
|
+
isCiStateSuccess: false,
|
|
38
|
+
isBranchOutOfDate: true,
|
|
39
|
+
missingRequiredCheckNames: ['build', 'test'],
|
|
40
|
+
},
|
|
41
|
+
};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { render } from '@testing-library/react';
|
|
2
|
+
import { ConsolePullRequestStatusBadges } from './ConsolePullRequestStatusBadges';
|
|
3
|
+
|
|
4
|
+
describe('ConsolePullRequestStatusBadges', () => {
|
|
5
|
+
it('renders a passing CI badge when all CI jobs passed and the CI state is success', () => {
|
|
6
|
+
const { getByText, queryByText } = render(
|
|
7
|
+
<ConsolePullRequestStatusBadges
|
|
8
|
+
isConflicted={false}
|
|
9
|
+
isPassedAllCiJob={true}
|
|
10
|
+
isCiStateSuccess={true}
|
|
11
|
+
isBranchOutOfDate={false}
|
|
12
|
+
missingRequiredCheckNames={[]}
|
|
13
|
+
/>,
|
|
14
|
+
);
|
|
15
|
+
expect(getByText('CI passing')).toBeInTheDocument();
|
|
16
|
+
expect(queryByText('Conflict')).toBeNull();
|
|
17
|
+
expect(queryByText('Out of date')).toBeNull();
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('renders a failing CI badge with missing required checks', () => {
|
|
21
|
+
const { getByText } = render(
|
|
22
|
+
<ConsolePullRequestStatusBadges
|
|
23
|
+
isConflicted={false}
|
|
24
|
+
isPassedAllCiJob={false}
|
|
25
|
+
isCiStateSuccess={true}
|
|
26
|
+
isBranchOutOfDate={false}
|
|
27
|
+
missingRequiredCheckNames={['build', 'test']}
|
|
28
|
+
/>,
|
|
29
|
+
);
|
|
30
|
+
expect(getByText('CI failing')).toBeInTheDocument();
|
|
31
|
+
expect(getByText(/missing: build, test/)).toBeInTheDocument();
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('renders the conflict badge when the pull request is conflicted', () => {
|
|
35
|
+
const { getByText } = render(
|
|
36
|
+
<ConsolePullRequestStatusBadges
|
|
37
|
+
isConflicted={true}
|
|
38
|
+
isPassedAllCiJob={true}
|
|
39
|
+
isCiStateSuccess={true}
|
|
40
|
+
isBranchOutOfDate={false}
|
|
41
|
+
missingRequiredCheckNames={[]}
|
|
42
|
+
/>,
|
|
43
|
+
);
|
|
44
|
+
expect(getByText('Conflict')).toBeInTheDocument();
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('renders the out-of-date badge when the branch is behind the base branch', () => {
|
|
48
|
+
const { getByText } = render(
|
|
49
|
+
<ConsolePullRequestStatusBadges
|
|
50
|
+
isConflicted={false}
|
|
51
|
+
isPassedAllCiJob={true}
|
|
52
|
+
isCiStateSuccess={true}
|
|
53
|
+
isBranchOutOfDate={true}
|
|
54
|
+
missingRequiredCheckNames={[]}
|
|
55
|
+
/>,
|
|
56
|
+
);
|
|
57
|
+
expect(getByText('Out of date')).toBeInTheDocument();
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('treats a successful CI state but unfinished jobs as failing', () => {
|
|
61
|
+
const { getByText } = render(
|
|
62
|
+
<ConsolePullRequestStatusBadges
|
|
63
|
+
isConflicted={false}
|
|
64
|
+
isPassedAllCiJob={false}
|
|
65
|
+
isCiStateSuccess={true}
|
|
66
|
+
isBranchOutOfDate={false}
|
|
67
|
+
missingRequiredCheckNames={[]}
|
|
68
|
+
/>,
|
|
69
|
+
);
|
|
70
|
+
expect(getByText('CI failing')).toBeInTheDocument();
|
|
71
|
+
});
|
|
72
|
+
});
|