Skip to content

Commit 72f253e

Browse files
committed
Add exporting of in-progress/cancelled results
This will allow exporting results for a variant analysis which is cancelled or in-progress. Repositories for which the results are not yet available or which have not yet been downloaded will not be exported. The header of the summary file is incorrect, but this will be fixed in a follow-up PR.
1 parent b273db1 commit 72f253e

7 files changed

Lines changed: 111 additions & 25 deletions

File tree

extensions/ql-vscode/src/remote-queries/export-results.ts

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@ import * as path from "path";
22
import * as fs from "fs-extra";
33

44
import {
5-
window,
65
commands,
7-
Uri,
86
ExtensionContext,
9-
workspace,
7+
Uri,
108
ViewColumn,
9+
window,
10+
workspace,
1111
} from "vscode";
1212
import { Credentials } from "../authentication";
1313
import { UserCancellationException } from "../commandRunner";
@@ -29,6 +29,7 @@ import { assertNever } from "../pure/helpers-pure";
2929
import {
3030
VariantAnalysis,
3131
VariantAnalysisScannedRepository,
32+
VariantAnalysisScannedRepositoryDownloadStatus,
3233
VariantAnalysisScannedRepositoryResult,
3334
} from "./shared/variant-analysis";
3435
import {
@@ -156,6 +157,10 @@ export async function exportVariantAnalysisResults(
156157
);
157158
}
158159

160+
const repoStates = await variantAnalysisManager.getRepoStates(
161+
variantAnalysisId,
162+
);
163+
159164
void extLogger.log(
160165
`Exporting variant analysis results for variant analysis with id ${variantAnalysis.id}`,
161166
);
@@ -181,6 +186,18 @@ export async function exportVariantAnalysisResults(
181186
}
182187

183188
for (const repo of repositories) {
189+
const repoState = repoStates.find(
190+
(r) => r.repositoryId === repo.repository.id,
191+
);
192+
193+
// Do not export if it has not yet completed or the download has not yet succeeded.
194+
if (
195+
repoState?.downloadStatus !==
196+
VariantAnalysisScannedRepositoryDownloadStatus.Succeeded
197+
) {
198+
continue;
199+
}
200+
184201
if (repo.resultCount == 0) {
185202
yield [
186203
repo,

extensions/ql-vscode/src/stories/variant-analysis/VariantAnalysis.stories.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ const variantAnalysis: VariantAnalysisDomainModel = {
4343
private: false,
4444
},
4545
analysisStatus: VariantAnalysisRepoStatus.Succeeded,
46+
resultCount: 100,
4647
},
4748
{
4849
repository: {

extensions/ql-vscode/src/stories/variant-analysis/VariantAnalysisActions.stories.tsx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,24 @@ InProgress.args = {
4747
variantAnalysisStatus: VariantAnalysisStatus.InProgress,
4848
};
4949

50+
export const InProgressWithResults = Template.bind({});
51+
InProgressWithResults.args = {
52+
variantAnalysisStatus: VariantAnalysisStatus.InProgress,
53+
showResultActions: true,
54+
};
55+
56+
export const InProgressWithoutDownloadedRepos = Template.bind({});
57+
InProgressWithoutDownloadedRepos.args = {
58+
variantAnalysisStatus: VariantAnalysisStatus.InProgress,
59+
showResultActions: true,
60+
exportResultsDisabled: true,
61+
};
62+
5063
export const Succeeded = Template.bind({});
5164
Succeeded.args = {
5265
...InProgress.args,
5366
variantAnalysisStatus: VariantAnalysisStatus.Succeeded,
67+
showResultActions: true,
5468
};
5569

5670
export const Failed = Template.bind({});

extensions/ql-vscode/src/view/variant-analysis/VariantAnalysis.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ export function VariantAnalysis({
144144
<>
145145
<VariantAnalysisHeader
146146
variantAnalysis={variantAnalysis}
147+
repositoryStates={repoStates}
147148
onOpenQueryFileClick={openQueryFile}
148149
onViewQueryTextClick={openQueryText}
149150
onStopQueryClick={stopQuery}

extensions/ql-vscode/src/view/variant-analysis/VariantAnalysisActions.tsx

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,16 @@ import styled from "styled-components";
33
import { VSCodeButton } from "@vscode/webview-ui-toolkit/react";
44
import { VariantAnalysisStatus } from "../../remote-queries/shared/variant-analysis";
55

6-
type Props = {
6+
export type VariantAnalysisActionsProps = {
77
variantAnalysisStatus: VariantAnalysisStatus;
88

99
onStopQueryClick: () => void;
1010
stopQueryDisabled?: boolean;
1111

12+
showResultActions?: boolean;
1213
onCopyRepositoryListClick: () => void;
1314
onExportResultsClick: () => void;
15+
exportResultsDisabled?: boolean;
1416
};
1517

1618
const Container = styled.div`
@@ -26,12 +28,28 @@ const Button = styled(VSCodeButton)`
2628
export const VariantAnalysisActions = ({
2729
variantAnalysisStatus,
2830
onStopQueryClick,
31+
stopQueryDisabled,
32+
showResultActions,
2933
onCopyRepositoryListClick,
3034
onExportResultsClick,
31-
stopQueryDisabled,
32-
}: Props) => {
35+
exportResultsDisabled,
36+
}: VariantAnalysisActionsProps) => {
3337
return (
3438
<Container>
39+
{showResultActions && (
40+
<>
41+
<Button appearance="secondary" onClick={onCopyRepositoryListClick}>
42+
Copy repository list
43+
</Button>
44+
<Button
45+
appearance="primary"
46+
onClick={onExportResultsClick}
47+
disabled={exportResultsDisabled}
48+
>
49+
Export results
50+
</Button>
51+
</>
52+
)}
3553
{variantAnalysisStatus === VariantAnalysisStatus.InProgress && (
3654
<Button
3755
appearance="secondary"
@@ -41,16 +59,6 @@ export const VariantAnalysisActions = ({
4159
Stop query
4260
</Button>
4361
)}
44-
{variantAnalysisStatus === VariantAnalysisStatus.Succeeded && (
45-
<>
46-
<Button appearance="secondary" onClick={onCopyRepositoryListClick}>
47-
Copy repository list
48-
</Button>
49-
<Button appearance="primary" onClick={onExportResultsClick}>
50-
Export results
51-
</Button>
52-
</>
53-
)}
5462
</Container>
5563
);
5664
};

extensions/ql-vscode/src/view/variant-analysis/VariantAnalysisHeader.tsx

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import {
66
getTotalResultCount,
77
hasRepoScanCompleted,
88
VariantAnalysis,
9+
VariantAnalysisScannedRepositoryDownloadStatus,
10+
VariantAnalysisScannedRepositoryState,
911
} from "../../remote-queries/shared/variant-analysis";
1012
import { QueryDetails } from "./QueryDetails";
1113
import { VariantAnalysisActions } from "./VariantAnalysisActions";
@@ -15,6 +17,7 @@ import { basename } from "../common/path";
1517

1618
export type VariantAnalysisHeaderProps = {
1719
variantAnalysis: VariantAnalysis;
20+
repositoryStates?: VariantAnalysisScannedRepositoryState[];
1821

1922
onOpenQueryFileClick: () => void;
2023
onViewQueryTextClick: () => void;
@@ -40,6 +43,7 @@ const Row = styled.div`
4043

4144
export const VariantAnalysisHeader = ({
4245
variantAnalysis,
46+
repositoryStates,
4347
onOpenQueryFileClick,
4448
onViewQueryTextClick,
4549
onStopQueryClick,
@@ -62,6 +66,15 @@ export const VariantAnalysisHeader = ({
6266
const hasSkippedRepos = useMemo(() => {
6367
return getSkippedRepoCount(variantAnalysis.skippedRepos) > 0;
6468
}, [variantAnalysis.skippedRepos]);
69+
const hasDownloadedRepos = useMemo(() => {
70+
return (
71+
repositoryStates?.some(
72+
(repo) =>
73+
repo.downloadStatus ===
74+
VariantAnalysisScannedRepositoryDownloadStatus.Succeeded,
75+
) ?? false
76+
);
77+
}, [repositoryStates]);
6578

6679
return (
6780
<Container>
@@ -74,10 +87,12 @@ export const VariantAnalysisHeader = ({
7487
/>
7588
<VariantAnalysisActions
7689
variantAnalysisStatus={variantAnalysis.status}
90+
showResultActions={(resultCount ?? 0) > 0}
7791
onStopQueryClick={onStopQueryClick}
7892
onCopyRepositoryListClick={onCopyRepositoryListClick}
7993
onExportResultsClick={onExportResultsClick}
8094
stopQueryDisabled={!variantAnalysis.actionsWorkflowRunId}
95+
exportResultsDisabled={!hasDownloadedRepos}
8196
/>
8297
</Row>
8398
<VariantAnalysisStats

extensions/ql-vscode/src/view/variant-analysis/__tests__/VariantAnalysisActions.spec.tsx

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ import * as React from "react";
22
import { render as reactRender, screen } from "@testing-library/react";
33
import userEvent from "@testing-library/user-event";
44
import { VariantAnalysisStatus } from "../../../remote-queries/shared/variant-analysis";
5-
import { VariantAnalysisActions } from "../VariantAnalysisActions";
5+
import {
6+
VariantAnalysisActions,
7+
VariantAnalysisActionsProps,
8+
} from "../VariantAnalysisActions";
69

710
describe(VariantAnalysisActions.name, () => {
811
const onStopQueryClick = jest.fn();
@@ -15,51 +18,78 @@ describe(VariantAnalysisActions.name, () => {
1518
onExportResultsClick.mockReset();
1619
});
1720

18-
const render = (variantAnalysisStatus: VariantAnalysisStatus) =>
21+
const render = (
22+
props: Pick<VariantAnalysisActionsProps, "variantAnalysisStatus"> &
23+
Partial<VariantAnalysisActionsProps>,
24+
) =>
1925
reactRender(
2026
<VariantAnalysisActions
21-
variantAnalysisStatus={variantAnalysisStatus}
2227
onStopQueryClick={onStopQueryClick}
2328
onCopyRepositoryListClick={onCopyRepositoryListClick}
2429
onExportResultsClick={onExportResultsClick}
30+
{...props}
2531
/>,
2632
);
2733

2834
it("renders 1 button when in progress", async () => {
29-
const { container } = render(VariantAnalysisStatus.InProgress);
35+
const { container } = render({
36+
variantAnalysisStatus: VariantAnalysisStatus.InProgress,
37+
});
3038

3139
expect(container.querySelectorAll("vscode-button").length).toEqual(1);
3240
});
3341

3442
it("renders the stop query button when in progress", async () => {
35-
render(VariantAnalysisStatus.InProgress);
43+
render({
44+
variantAnalysisStatus: VariantAnalysisStatus.InProgress,
45+
});
3646

3747
await userEvent.click(screen.getByText("Stop query"));
3848
expect(onStopQueryClick).toHaveBeenCalledTimes(1);
3949
});
4050

51+
it("renders 3 buttons when in progress with results", async () => {
52+
const { container } = render({
53+
variantAnalysisStatus: VariantAnalysisStatus.InProgress,
54+
showResultActions: true,
55+
});
56+
57+
expect(container.querySelectorAll("vscode-button").length).toEqual(3);
58+
});
59+
4160
it("renders 2 buttons when succeeded", async () => {
42-
const { container } = render(VariantAnalysisStatus.Succeeded);
61+
const { container } = render({
62+
variantAnalysisStatus: VariantAnalysisStatus.Succeeded,
63+
showResultActions: true,
64+
});
4365

4466
expect(container.querySelectorAll("vscode-button").length).toEqual(2);
4567
});
4668

4769
it("renders the copy repository list button when succeeded", async () => {
48-
render(VariantAnalysisStatus.Succeeded);
70+
render({
71+
variantAnalysisStatus: VariantAnalysisStatus.Succeeded,
72+
showResultActions: true,
73+
});
4974

5075
await userEvent.click(screen.getByText("Copy repository list"));
5176
expect(onCopyRepositoryListClick).toHaveBeenCalledTimes(1);
5277
});
5378

5479
it("renders the export results button when succeeded", async () => {
55-
render(VariantAnalysisStatus.Succeeded);
80+
render({
81+
variantAnalysisStatus: VariantAnalysisStatus.Succeeded,
82+
showResultActions: true,
83+
});
5684

5785
await userEvent.click(screen.getByText("Export results"));
5886
expect(onExportResultsClick).toHaveBeenCalledTimes(1);
5987
});
6088

6189
it("does not render any buttons when failed", () => {
62-
const { container } = render(VariantAnalysisStatus.Failed);
90+
const { container } = render({
91+
variantAnalysisStatus: VariantAnalysisStatus.Failed,
92+
});
6393

6494
expect(container.querySelectorAll("vscode-button").length).toEqual(0);
6595
});

0 commit comments

Comments
 (0)