github-issue-tower-defence-management 1.112.6 → 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 +7 -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-DKFbU8lr.css → index-CEJmPNRK.css} +1 -1
- package/bin/adapter/entry-points/console/ui-dist/assets/{index-DUygHx5u.js → index-DfNrA5uV.js} +36 -36
- 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 +44 -0
- package/src/adapter/entry-points/console/ui/e2e/consoleTestHarness.ts +31 -8
- package/src/adapter/entry-points/console/ui/src/features/console/components/detail/ConsoleItemDetail.stories.tsx +41 -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 +15 -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 +8 -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 +9 -0
- package/src/adapter/entry-points/console/ui/src/features/console/pages/ConsoleItemDetailContainer.tsx +1 -0
- package/src/adapter/entry-points/console/ui/src/index.css +12 -0
- package/src/adapter/entry-points/console/ui-dist/assets/{index-DKFbU8lr.css → index-CEJmPNRK.css} +1 -1
- package/src/adapter/entry-points/console/ui-dist/assets/{index-DUygHx5u.js → index-DfNrA5uV.js} +36 -36
- 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
|
@@ -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
|
|
@@ -10,6 +10,7 @@ import { ConsoleChangedFileList } from './ConsoleChangedFileList';
|
|
|
10
10
|
import { ConsoleCommitList } from './ConsoleCommitList';
|
|
11
11
|
import { ConsoleCopyUrlButton } from './ConsoleCopyUrlButton';
|
|
12
12
|
import type { ConsoleAddInlineComment } from './ConsoleFileDiff';
|
|
13
|
+
import { ConsolePullRequestStatusBadges } from './ConsolePullRequestStatusBadges';
|
|
13
14
|
|
|
14
15
|
export type ConsolePullRequestSectionProps = {
|
|
15
16
|
pullRequest: ConsoleRelatedPullRequest;
|
|
@@ -59,6 +60,13 @@ export const ConsolePullRequestDetail = ({
|
|
|
59
60
|
{pullRequest.isDraft && (
|
|
60
61
|
<span className="console-pr-section-state">draft</span>
|
|
61
62
|
)}
|
|
63
|
+
<ConsolePullRequestStatusBadges
|
|
64
|
+
isConflicted={pullRequest.isConflicted}
|
|
65
|
+
isPassedAllCiJob={pullRequest.isPassedAllCiJob}
|
|
66
|
+
isCiStateSuccess={pullRequest.isCiStateSuccess}
|
|
67
|
+
isBranchOutOfDate={pullRequest.isBranchOutOfDate}
|
|
68
|
+
missingRequiredCheckNames={pullRequest.missingRequiredCheckNames}
|
|
69
|
+
/>
|
|
62
70
|
<ConsoleCopyUrlButton url={pullRequest.url} label="Copy PR URL" />
|
|
63
71
|
<div className="console-pr-statbar">
|
|
64
72
|
{pullRequest.branchName !== null && (
|
|
@@ -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
|
+
});
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { colorFromEnum } from '../../logic/colors';
|
|
2
|
+
import type { ConsoleColor } from '../../logic/types';
|
|
3
|
+
|
|
4
|
+
export type ConsolePullRequestStatusBadgesProps = {
|
|
5
|
+
isConflicted: boolean;
|
|
6
|
+
isPassedAllCiJob: boolean;
|
|
7
|
+
isCiStateSuccess: boolean;
|
|
8
|
+
isBranchOutOfDate: boolean;
|
|
9
|
+
missingRequiredCheckNames: string[];
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const badgeStyle = (color: ConsoleColor) => {
|
|
13
|
+
const palette = colorFromEnum(color);
|
|
14
|
+
return {
|
|
15
|
+
color: palette.fg,
|
|
16
|
+
borderColor: palette.border,
|
|
17
|
+
backgroundColor: palette.bg,
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export const ConsolePullRequestStatusBadges = ({
|
|
22
|
+
isConflicted,
|
|
23
|
+
isPassedAllCiJob,
|
|
24
|
+
isCiStateSuccess,
|
|
25
|
+
isBranchOutOfDate,
|
|
26
|
+
missingRequiredCheckNames,
|
|
27
|
+
}: ConsolePullRequestStatusBadgesProps) => {
|
|
28
|
+
const ciPassing = isPassedAllCiJob && isCiStateSuccess;
|
|
29
|
+
const ciColor: ConsoleColor = ciPassing ? 'GREEN' : 'RED';
|
|
30
|
+
const ciLabel = ciPassing ? 'CI passing' : 'CI failing';
|
|
31
|
+
const missingChecksLabel =
|
|
32
|
+
!ciPassing && missingRequiredCheckNames.length > 0
|
|
33
|
+
? `missing: ${missingRequiredCheckNames.join(', ')}`
|
|
34
|
+
: null;
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<span className="console-detail-pr-status">
|
|
38
|
+
<span
|
|
39
|
+
className="console-detail-status-chip console-detail-ci-chip"
|
|
40
|
+
style={badgeStyle(ciColor)}
|
|
41
|
+
title={missingChecksLabel ?? ciLabel}
|
|
42
|
+
>
|
|
43
|
+
{ciLabel}
|
|
44
|
+
{missingChecksLabel !== null && (
|
|
45
|
+
<span className="console-detail-ci-missing">
|
|
46
|
+
{' '}
|
|
47
|
+
({missingChecksLabel})
|
|
48
|
+
</span>
|
|
49
|
+
)}
|
|
50
|
+
</span>
|
|
51
|
+
{isConflicted && (
|
|
52
|
+
<span
|
|
53
|
+
className="console-detail-status-chip console-detail-conflict-chip"
|
|
54
|
+
style={badgeStyle('RED')}
|
|
55
|
+
title="This pull request has merge conflicts"
|
|
56
|
+
>
|
|
57
|
+
Conflict
|
|
58
|
+
</span>
|
|
59
|
+
)}
|
|
60
|
+
{isBranchOutOfDate && (
|
|
61
|
+
<span
|
|
62
|
+
className="console-detail-status-chip console-detail-outofdate-chip"
|
|
63
|
+
style={badgeStyle('YELLOW')}
|
|
64
|
+
title="This branch is out of date with the base branch"
|
|
65
|
+
>
|
|
66
|
+
Out of date
|
|
67
|
+
</span>
|
|
68
|
+
)}
|
|
69
|
+
</span>
|
|
70
|
+
);
|
|
71
|
+
};
|
|
@@ -9,6 +9,7 @@ import type {
|
|
|
9
9
|
ConsoleComment,
|
|
10
10
|
ConsoleCommit,
|
|
11
11
|
ConsoleIssueState,
|
|
12
|
+
ConsolePullRequestStatus,
|
|
12
13
|
ConsoleRelatedPullRequest,
|
|
13
14
|
} from '../logic/types';
|
|
14
15
|
import { useConsoleToken } from './useConsoleToken';
|
|
@@ -20,6 +21,7 @@ export type ConsoleCaches = {
|
|
|
20
21
|
commits: ResourceCache<ConsoleCommit[]>;
|
|
21
22
|
relatedPrs: ResourceCache<ConsoleRelatedPullRequest[]>;
|
|
22
23
|
state: ResourceCache<ConsoleIssueState>;
|
|
24
|
+
prStatus: ResourceCache<ConsolePullRequestStatus>;
|
|
23
25
|
client: ConsoleApiClient;
|
|
24
26
|
};
|
|
25
27
|
|
|
@@ -37,6 +39,9 @@ export const useConsoleCaches = (): ConsoleCaches => {
|
|
|
37
39
|
client.fetchRelatedPrs,
|
|
38
40
|
),
|
|
39
41
|
state: new ResourceCache<ConsoleIssueState>(client.fetchIssueState),
|
|
42
|
+
prStatus: new ResourceCache<ConsolePullRequestStatus>(
|
|
43
|
+
client.fetchPullRequestStatus,
|
|
44
|
+
),
|
|
40
45
|
};
|
|
41
46
|
}, [appendToken]);
|
|
42
47
|
};
|
|
@@ -6,6 +6,7 @@ import type {
|
|
|
6
6
|
ConsoleCommit,
|
|
7
7
|
ConsoleIssueState,
|
|
8
8
|
ConsoleListItem,
|
|
9
|
+
ConsolePullRequestStatus,
|
|
9
10
|
ConsoleRelatedPullRequest,
|
|
10
11
|
} from '../logic/types';
|
|
11
12
|
import type { ConsoleCaches } from './useConsoleCaches';
|
|
@@ -63,6 +64,14 @@ const buildCaches = (related: ConsoleRelatedPullRequest[]): ConsoleCaches => {
|
|
|
63
64
|
merged: false,
|
|
64
65
|
isPullRequest: true,
|
|
65
66
|
}),
|
|
67
|
+
fetchPullRequestStatus: async (): Promise<ConsolePullRequestStatus> => ({
|
|
68
|
+
found: true,
|
|
69
|
+
isConflicted: true,
|
|
70
|
+
isPassedAllCiJob: false,
|
|
71
|
+
isCiStateSuccess: false,
|
|
72
|
+
isBranchOutOfDate: true,
|
|
73
|
+
missingRequiredCheckNames: ['build'],
|
|
74
|
+
}),
|
|
66
75
|
};
|
|
67
76
|
return {
|
|
68
77
|
client,
|
|
@@ -72,6 +81,7 @@ const buildCaches = (related: ConsoleRelatedPullRequest[]): ConsoleCaches => {
|
|
|
72
81
|
commits: new ResourceCache(client.fetchPrCommits),
|
|
73
82
|
relatedPrs: new ResourceCache(client.fetchRelatedPrs),
|
|
74
83
|
state: new ResourceCache(client.fetchIssueState),
|
|
84
|
+
prStatus: new ResourceCache(client.fetchPullRequestStatus),
|
|
75
85
|
};
|
|
76
86
|
};
|
|
77
87
|
|
|
@@ -85,9 +95,19 @@ describe('useConsoleItemDetailData', () => {
|
|
|
85
95
|
expect(result.current.body).toBe('body');
|
|
86
96
|
expect(result.current.files.length).toBe(1);
|
|
87
97
|
expect(result.current.commits.length).toBe(1);
|
|
98
|
+
expect(result.current.pullRequestStatus?.found).toBe(true);
|
|
99
|
+
expect(result.current.pullRequestStatus?.isConflicted).toBe(true);
|
|
88
100
|
});
|
|
89
101
|
});
|
|
90
102
|
|
|
103
|
+
it('does not expose pull request status for an issue item', () => {
|
|
104
|
+
const caches = buildCaches([]);
|
|
105
|
+
const { result } = renderHook(() =>
|
|
106
|
+
useConsoleItemDetailData(caches, issueItem),
|
|
107
|
+
);
|
|
108
|
+
expect(result.current.pullRequestStatus).toBeNull();
|
|
109
|
+
});
|
|
110
|
+
|
|
91
111
|
it('loads related pull request views for an issue item', async () => {
|
|
92
112
|
const related: ConsoleRelatedPullRequest[] = [
|
|
93
113
|
{
|
package/src/adapter/entry-points/console/ui/src/features/console/hooks/useConsoleItemDetailData.ts
CHANGED
|
@@ -6,6 +6,7 @@ import type {
|
|
|
6
6
|
ConsoleCommit,
|
|
7
7
|
ConsoleIssueState,
|
|
8
8
|
ConsoleListItem,
|
|
9
|
+
ConsolePullRequestStatus,
|
|
9
10
|
ConsoleRelatedPullRequest,
|
|
10
11
|
} from '../logic/types';
|
|
11
12
|
import type { ConsoleCaches } from './useConsoleCaches';
|
|
@@ -20,6 +21,14 @@ const DEFAULT_STATE: ConsoleIssueState = {
|
|
|
20
21
|
merged: false,
|
|
21
22
|
isPullRequest: false,
|
|
22
23
|
};
|
|
24
|
+
const DEFAULT_PR_STATUS: ConsolePullRequestStatus = {
|
|
25
|
+
found: false,
|
|
26
|
+
isConflicted: false,
|
|
27
|
+
isPassedAllCiJob: false,
|
|
28
|
+
isCiStateSuccess: false,
|
|
29
|
+
isBranchOutOfDate: false,
|
|
30
|
+
missingRequiredCheckNames: [],
|
|
31
|
+
};
|
|
23
32
|
|
|
24
33
|
export type ConsoleItemDetailData = {
|
|
25
34
|
state: ConsoleIssueState | null;
|
|
@@ -35,6 +44,7 @@ export type ConsoleItemDetailData = {
|
|
|
35
44
|
commits: ConsoleCommit[];
|
|
36
45
|
commitsAreLoading: boolean;
|
|
37
46
|
commitsError: string | null;
|
|
47
|
+
pullRequestStatus: ConsolePullRequestStatus | null;
|
|
38
48
|
relatedPullRequests: ConsoleRelatedPullRequestView[];
|
|
39
49
|
};
|
|
40
50
|
|
|
@@ -66,6 +76,12 @@ export const useConsoleItemDetailData = (
|
|
|
66
76
|
isPr ? url : null,
|
|
67
77
|
EMPTY_COMMITS,
|
|
68
78
|
);
|
|
79
|
+
const prStatus = useConsoleResource(
|
|
80
|
+
caches.prStatus,
|
|
81
|
+
isPr ? key : null,
|
|
82
|
+
isPr ? url : null,
|
|
83
|
+
DEFAULT_PR_STATUS,
|
|
84
|
+
);
|
|
69
85
|
const relatedPrs = useConsoleResource(
|
|
70
86
|
caches.relatedPrs,
|
|
71
87
|
!isPr ? key : null,
|
|
@@ -162,6 +178,7 @@ export const useConsoleItemDetailData = (
|
|
|
162
178
|
commits: commits.data,
|
|
163
179
|
commitsAreLoading: commits.isLoading,
|
|
164
180
|
commitsError: commits.error,
|
|
181
|
+
pullRequestStatus: isPr ? prStatus.data : null,
|
|
165
182
|
relatedPullRequests: relatedViews,
|
|
166
183
|
};
|
|
167
184
|
};
|
|
@@ -48,6 +48,7 @@ describe('createConsoleApiClient', () => {
|
|
|
48
48
|
readers.push((url) => client.fetchPrCommits(url));
|
|
49
49
|
readers.push((url) => client.fetchRelatedPrs(url));
|
|
50
50
|
readers.push((url) => client.fetchIssueState(url));
|
|
51
|
+
readers.push((url) => client.fetchPullRequestStatus(url));
|
|
51
52
|
const expectedPaths = [
|
|
52
53
|
'/api/itembody',
|
|
53
54
|
'/api/comments',
|
|
@@ -55,6 +56,7 @@ describe('createConsoleApiClient', () => {
|
|
|
55
56
|
'/api/prcommits',
|
|
56
57
|
'/api/relatedprs',
|
|
57
58
|
'/api/issuetitle',
|
|
59
|
+
'/api/pullrequeststatus',
|
|
58
60
|
];
|
|
59
61
|
for (let index = 0; index < readers.length; index += 1) {
|
|
60
62
|
const fetchMock = mockFetchOnce({});
|
|
@@ -161,6 +163,45 @@ describe('createConsoleApiClient', () => {
|
|
|
161
163
|
expect(related[0].missingRequiredCheckNames).toEqual(['build']);
|
|
162
164
|
});
|
|
163
165
|
|
|
166
|
+
it('parses the pull request status when found', async () => {
|
|
167
|
+
mockFetchOnce({
|
|
168
|
+
found: true,
|
|
169
|
+
status: {
|
|
170
|
+
isConflicted: true,
|
|
171
|
+
isPassedAllCiJob: false,
|
|
172
|
+
isCiStateSuccess: false,
|
|
173
|
+
isBranchOutOfDate: true,
|
|
174
|
+
missingRequiredCheckNames: ['build', 'test'],
|
|
175
|
+
},
|
|
176
|
+
});
|
|
177
|
+
const client = createConsoleApiClient(appendToken);
|
|
178
|
+
expect(
|
|
179
|
+
await client.fetchPullRequestStatus('https://github.com/o/r/pull/1'),
|
|
180
|
+
).toEqual({
|
|
181
|
+
found: true,
|
|
182
|
+
isConflicted: true,
|
|
183
|
+
isPassedAllCiJob: false,
|
|
184
|
+
isCiStateSuccess: false,
|
|
185
|
+
isBranchOutOfDate: true,
|
|
186
|
+
missingRequiredCheckNames: ['build', 'test'],
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
it('returns a not-found pull request status when the server reports none', async () => {
|
|
191
|
+
mockFetchOnce({ found: false, status: null });
|
|
192
|
+
const client = createConsoleApiClient(appendToken);
|
|
193
|
+
expect(
|
|
194
|
+
await client.fetchPullRequestStatus('https://github.com/o/r/pull/1'),
|
|
195
|
+
).toEqual({
|
|
196
|
+
found: false,
|
|
197
|
+
isConflicted: false,
|
|
198
|
+
isPassedAllCiJob: false,
|
|
199
|
+
isCiStateSuccess: false,
|
|
200
|
+
isBranchOutOfDate: false,
|
|
201
|
+
missingRequiredCheckNames: [],
|
|
202
|
+
});
|
|
203
|
+
});
|
|
204
|
+
|
|
164
205
|
it('throws on a non-ok response', async () => {
|
|
165
206
|
mockFetchOnce({}, false);
|
|
166
207
|
const client = createConsoleApiClient(appendToken);
|
|
@@ -3,6 +3,7 @@ import type {
|
|
|
3
3
|
ConsoleComment,
|
|
4
4
|
ConsoleCommit,
|
|
5
5
|
ConsoleIssueState,
|
|
6
|
+
ConsolePullRequestStatus,
|
|
6
7
|
ConsoleRelatedPullRequest,
|
|
7
8
|
} from '../logic/types';
|
|
8
9
|
|
|
@@ -13,6 +14,7 @@ export type ConsoleApiClient = {
|
|
|
13
14
|
fetchPrCommits: (url: string) => Promise<ConsoleCommit[]>;
|
|
14
15
|
fetchRelatedPrs: (url: string) => Promise<ConsoleRelatedPullRequest[]>;
|
|
15
16
|
fetchIssueState: (url: string) => Promise<ConsoleIssueState>;
|
|
17
|
+
fetchPullRequestStatus: (url: string) => Promise<ConsolePullRequestStatus>;
|
|
16
18
|
};
|
|
17
19
|
|
|
18
20
|
export type ConsoleReviewRequest = {
|
|
@@ -129,6 +131,11 @@ const parseSummary = (value: unknown): ConsoleRelatedPullRequest['summary'] => {
|
|
|
129
131
|
};
|
|
130
132
|
};
|
|
131
133
|
|
|
134
|
+
const parseStringArray = (value: unknown): string[] =>
|
|
135
|
+
Array.isArray(value)
|
|
136
|
+
? value.filter((name): name is string => typeof name === 'string')
|
|
137
|
+
: [];
|
|
138
|
+
|
|
132
139
|
const parseRelatedPrs = (payload: unknown): ConsoleRelatedPullRequest[] => {
|
|
133
140
|
if (!isRecord(payload) || !Array.isArray(payload.relatedPullRequests)) {
|
|
134
141
|
return [];
|
|
@@ -143,15 +150,35 @@ const parseRelatedPrs = (payload: unknown): ConsoleRelatedPullRequest[] => {
|
|
|
143
150
|
isCiStateSuccess: getBoolean(pr.isCiStateSuccess),
|
|
144
151
|
isResolvedAllReviewComments: getBoolean(pr.isResolvedAllReviewComments),
|
|
145
152
|
isBranchOutOfDate: getBoolean(pr.isBranchOutOfDate),
|
|
146
|
-
missingRequiredCheckNames:
|
|
147
|
-
? pr.missingRequiredCheckNames.filter(
|
|
148
|
-
(name): name is string => typeof name === 'string',
|
|
149
|
-
)
|
|
150
|
-
: [],
|
|
153
|
+
missingRequiredCheckNames: parseStringArray(pr.missingRequiredCheckNames),
|
|
151
154
|
summary: parseSummary(pr.summary),
|
|
152
155
|
}));
|
|
153
156
|
};
|
|
154
157
|
|
|
158
|
+
const parsePullRequestStatus = (payload: unknown): ConsolePullRequestStatus => {
|
|
159
|
+
if (!isRecord(payload) || !isRecord(payload.status)) {
|
|
160
|
+
return {
|
|
161
|
+
found: false,
|
|
162
|
+
isConflicted: false,
|
|
163
|
+
isPassedAllCiJob: false,
|
|
164
|
+
isCiStateSuccess: false,
|
|
165
|
+
isBranchOutOfDate: false,
|
|
166
|
+
missingRequiredCheckNames: [],
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
const status = payload.status;
|
|
170
|
+
return {
|
|
171
|
+
found: true,
|
|
172
|
+
isConflicted: getBoolean(status.isConflicted),
|
|
173
|
+
isPassedAllCiJob: getBoolean(status.isPassedAllCiJob),
|
|
174
|
+
isCiStateSuccess: getBoolean(status.isCiStateSuccess),
|
|
175
|
+
isBranchOutOfDate: getBoolean(status.isBranchOutOfDate),
|
|
176
|
+
missingRequiredCheckNames: parseStringArray(
|
|
177
|
+
status.missingRequiredCheckNames,
|
|
178
|
+
),
|
|
179
|
+
};
|
|
180
|
+
};
|
|
181
|
+
|
|
155
182
|
const parseState = (payload: unknown): ConsoleIssueState => {
|
|
156
183
|
if (!isRecord(payload)) {
|
|
157
184
|
return { state: 'open', merged: false, isPullRequest: false };
|
|
@@ -180,6 +207,10 @@ export const createConsoleApiClient = (
|
|
|
180
207
|
parseRelatedPrs(await requestJson(appendToken, '/api/relatedprs', url)),
|
|
181
208
|
fetchIssueState: async (url) =>
|
|
182
209
|
parseState(await requestJson(appendToken, '/api/issuetitle', url)),
|
|
210
|
+
fetchPullRequestStatus: async (url) =>
|
|
211
|
+
parsePullRequestStatus(
|
|
212
|
+
await requestJson(appendToken, '/api/pullrequeststatus', url),
|
|
213
|
+
),
|
|
183
214
|
});
|
|
184
215
|
|
|
185
216
|
const readOperationErrorReason = async (
|
|
@@ -63,6 +63,15 @@ export type ConsoleIssueState = {
|
|
|
63
63
|
isPullRequest: boolean;
|
|
64
64
|
};
|
|
65
65
|
|
|
66
|
+
export type ConsolePullRequestStatus = {
|
|
67
|
+
found: boolean;
|
|
68
|
+
isConflicted: boolean;
|
|
69
|
+
isPassedAllCiJob: boolean;
|
|
70
|
+
isCiStateSuccess: boolean;
|
|
71
|
+
isBranchOutOfDate: boolean;
|
|
72
|
+
missingRequiredCheckNames: string[];
|
|
73
|
+
};
|
|
74
|
+
|
|
66
75
|
export type ConsoleComment = {
|
|
67
76
|
author: string;
|
|
68
77
|
body: string;
|
|
@@ -40,6 +40,14 @@ const buildCaches = (overrides: CachesOverrides = {}): ConsoleCaches => {
|
|
|
40
40
|
merged: false,
|
|
41
41
|
isPullRequest: true,
|
|
42
42
|
}),
|
|
43
|
+
fetchPullRequestStatus: async () => ({
|
|
44
|
+
found: true,
|
|
45
|
+
isConflicted: false,
|
|
46
|
+
isPassedAllCiJob: true,
|
|
47
|
+
isCiStateSuccess: true,
|
|
48
|
+
isBranchOutOfDate: false,
|
|
49
|
+
missingRequiredCheckNames: [],
|
|
50
|
+
}),
|
|
43
51
|
};
|
|
44
52
|
return {
|
|
45
53
|
client,
|
|
@@ -49,6 +57,7 @@ const buildCaches = (overrides: CachesOverrides = {}): ConsoleCaches => {
|
|
|
49
57
|
commits: new ResourceCache(client.fetchPrCommits),
|
|
50
58
|
relatedPrs: new ResourceCache(client.fetchRelatedPrs),
|
|
51
59
|
state: new ResourceCache(client.fetchIssueState),
|
|
60
|
+
prStatus: new ResourceCache(client.fetchPullRequestStatus),
|
|
52
61
|
};
|
|
53
62
|
};
|
|
54
63
|
|
|
@@ -150,6 +150,7 @@ export const ConsoleItemDetailContainer = ({
|
|
|
150
150
|
commits={detail.commits}
|
|
151
151
|
commitsAreLoading={detail.commitsAreLoading}
|
|
152
152
|
commitsError={detail.commitsError}
|
|
153
|
+
pullRequestStatus={detail.pullRequestStatus}
|
|
153
154
|
relatedPullRequests={detail.relatedPullRequests}
|
|
154
155
|
now={now}
|
|
155
156
|
buildImageProxyUrl={resolveImageProxyUrl}
|
|
@@ -335,6 +335,18 @@ body {
|
|
|
335
335
|
font-size: 0.75rem;
|
|
336
336
|
}
|
|
337
337
|
|
|
338
|
+
.console-detail-pr-status {
|
|
339
|
+
display: inline-flex;
|
|
340
|
+
flex-wrap: wrap;
|
|
341
|
+
align-items: center;
|
|
342
|
+
gap: 6px;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
.console-detail-ci-missing {
|
|
346
|
+
font-weight: 400;
|
|
347
|
+
opacity: 0.85;
|
|
348
|
+
}
|
|
349
|
+
|
|
338
350
|
.console-detail-labels {
|
|
339
351
|
display: flex;
|
|
340
352
|
flex-wrap: wrap;
|