Skip to content

Commit c9d6bfd

Browse files
authored
Merge pull request #1820 from github/koesie10/export-progress
Add progress notification to exporting results
2 parents 8b35435 + dc2bb3a commit c9d6bfd

2 files changed

Lines changed: 102 additions & 14 deletions

File tree

extensions/ql-vscode/src/extension.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1235,9 +1235,11 @@ async function activateWithInstalledDistribution(
12351235
);
12361236

12371237
ctx.subscriptions.push(
1238-
commandRunner(
1238+
commandRunnerWithProgress(
12391239
"codeQL.exportVariantAnalysisResults",
12401240
async (
1241+
progress: ProgressCallback,
1242+
token: CancellationToken,
12411243
variantAnalysisId: number,
12421244
filterSort?: RepositoriesFilterSortStateWithIds,
12431245
) => {
@@ -1246,8 +1248,14 @@ async function activateWithInstalledDistribution(
12461248
variantAnalysisManager,
12471249
variantAnalysisId,
12481250
filterSort,
1251+
progress,
1252+
token,
12491253
);
12501254
},
1255+
{
1256+
title: "Exporting variant analysis results",
1257+
cancellable: true,
1258+
},
12511259
),
12521260
);
12531261

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

Lines changed: 93 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,15 @@ import { ensureDir, writeFile } from "fs-extra";
33

44
import {
55
commands,
6+
CancellationToken,
67
ExtensionContext,
78
Uri,
89
ViewColumn,
910
window,
1011
workspace,
1112
} from "vscode";
1213
import { Credentials } from "../authentication";
13-
import { UserCancellationException } from "../commandRunner";
14+
import { ProgressCallback, UserCancellationException } from "../commandRunner";
1415
import { showInformationMessageWithAction } from "../helpers";
1516
import { extLogger } from "../common";
1617
import { QueryHistoryManager } from "../query-history";
@@ -133,6 +134,8 @@ export async function exportRemoteQueryAnalysisResults(
133134
);
134135
}
135136

137+
const MAX_VARIANT_ANALYSIS_EXPORT_PROGRESS_STEPS = 2;
138+
136139
/**
137140
* Exports the results of the given or currently-selected remote query.
138141
* The user is prompted to select the export format.
@@ -141,7 +144,9 @@ export async function exportVariantAnalysisResults(
141144
ctx: ExtensionContext,
142145
variantAnalysisManager: VariantAnalysisManager,
143146
variantAnalysisId: number,
144-
filterSort?: RepositoriesFilterSortStateWithIds,
147+
filterSort: RepositoriesFilterSortStateWithIds | undefined,
148+
progress: ProgressCallback,
149+
token: CancellationToken,
145150
): Promise<void> {
146151
const variantAnalysis = await variantAnalysisManager.getVariantAnalysis(
147152
variantAnalysisId,
@@ -155,6 +160,10 @@ export async function exportVariantAnalysisResults(
155160
);
156161
}
157162

163+
if (token.isCancellationRequested) {
164+
throw new UserCancellationException("Cancelled");
165+
}
166+
158167
const repoStates = await variantAnalysisManager.getRepoStates(
159168
variantAnalysisId,
160169
);
@@ -163,11 +172,21 @@ export async function exportVariantAnalysisResults(
163172
`Exporting variant analysis results for variant analysis with id ${variantAnalysis.id}`,
164173
);
165174

175+
progress({
176+
maxStep: MAX_VARIANT_ANALYSIS_EXPORT_PROGRESS_STEPS,
177+
step: 0,
178+
message: "Determining export format",
179+
});
180+
166181
const exportFormat = await determineExportFormat();
167182
if (!exportFormat) {
168183
return;
169184
}
170185

186+
if (token.isCancellationRequested) {
187+
throw new UserCancellationException("Cancelled");
188+
}
189+
171190
async function* getAnalysesResults(): AsyncGenerator<
172191
[VariantAnalysisScannedRepository, VariantAnalysisScannedRepositoryResult]
173192
> {
@@ -241,6 +260,8 @@ export async function exportVariantAnalysisResults(
241260
variantAnalysis,
242261
getAnalysesResults(),
243262
exportFormat,
263+
progress,
264+
token,
244265
);
245266
}
246267

@@ -252,7 +273,19 @@ export async function exportVariantAnalysisAnalysisResults(
252273
[VariantAnalysisScannedRepository, VariantAnalysisScannedRepositoryResult]
253274
>,
254275
exportFormat: "gist" | "local",
276+
progress: ProgressCallback,
277+
token: CancellationToken,
255278
) {
279+
if (token.isCancellationRequested) {
280+
throw new UserCancellationException("Cancelled");
281+
}
282+
283+
progress({
284+
maxStep: MAX_VARIANT_ANALYSIS_EXPORT_PROGRESS_STEPS,
285+
step: 1,
286+
message: "Generating Markdown files",
287+
});
288+
256289
const { markdownFiles, summaries } = await generateVariantAnalysisMarkdown(
257290
variantAnalysis,
258291
analysesResults,
@@ -269,6 +302,8 @@ export async function exportVariantAnalysisAnalysisResults(
269302
description,
270303
markdownFiles,
271304
exportFormat,
305+
progress,
306+
token,
272307
);
273308
}
274309

@@ -311,21 +346,44 @@ export async function exportResults(
311346
description: string,
312347
markdownFiles: MarkdownFile[],
313348
exportFormat: "gist" | "local",
349+
progress?: ProgressCallback,
350+
token?: CancellationToken,
314351
) {
352+
if (token?.isCancellationRequested) {
353+
throw new UserCancellationException("Cancelled");
354+
}
355+
315356
if (exportFormat === "gist") {
316-
await exportToGist(ctx, description, markdownFiles);
357+
await exportToGist(ctx, description, markdownFiles, progress, token);
317358
} else if (exportFormat === "local") {
318-
await exportToLocalMarkdown(exportedResultsPath, markdownFiles);
359+
await exportToLocalMarkdown(
360+
exportedResultsPath,
361+
markdownFiles,
362+
progress,
363+
token,
364+
);
319365
}
320366
}
321367

322368
export async function exportToGist(
323369
ctx: ExtensionContext,
324370
description: string,
325371
markdownFiles: MarkdownFile[],
372+
progress?: ProgressCallback,
373+
token?: CancellationToken,
326374
) {
375+
progress?.({
376+
maxStep: MAX_VARIANT_ANALYSIS_EXPORT_PROGRESS_STEPS,
377+
step: 2,
378+
message: "Creating Gist",
379+
});
380+
327381
const credentials = await Credentials.initialize(ctx);
328382

383+
if (token?.isCancellationRequested) {
384+
throw new UserCancellationException("Cancelled");
385+
}
386+
329387
// Convert markdownFiles to the appropriate format for uploading to gist
330388
const gistFiles = markdownFiles.reduce((acc, cur) => {
331389
acc[`${cur.fileName}.md`] = { content: cur.content.join("\n") };
@@ -334,13 +392,17 @@ export async function exportToGist(
334392

335393
const gistUrl = await createGist(credentials, description, gistFiles);
336394
if (gistUrl) {
337-
const shouldOpenGist = await showInformationMessageWithAction(
395+
// This needs to use .then to ensure we aren't keeping the progress notification open. We shouldn't await the
396+
// "Open gist" button click.
397+
void showInformationMessageWithAction(
338398
"Variant analysis results exported to gist.",
339399
"Open gist",
340-
);
341-
if (shouldOpenGist) {
342-
await commands.executeCommand("vscode.open", Uri.parse(gistUrl));
343-
}
400+
).then((shouldOpenGist) => {
401+
if (!shouldOpenGist) {
402+
return;
403+
}
404+
return commands.executeCommand("vscode.open", Uri.parse(gistUrl));
405+
});
344406
}
345407
}
346408

@@ -386,20 +448,38 @@ const buildVariantAnalysisGistDescription = (
386448
async function exportToLocalMarkdown(
387449
exportedResultsPath: string,
388450
markdownFiles: MarkdownFile[],
451+
progress?: ProgressCallback,
452+
token?: CancellationToken,
389453
) {
454+
if (token?.isCancellationRequested) {
455+
throw new UserCancellationException("Cancelled");
456+
}
457+
458+
progress?.({
459+
maxStep: MAX_VARIANT_ANALYSIS_EXPORT_PROGRESS_STEPS,
460+
step: 2,
461+
message: "Creating local Markdown files",
462+
});
463+
390464
await ensureDir(exportedResultsPath);
391465
for (const markdownFile of markdownFiles) {
392466
const filePath = join(exportedResultsPath, `${markdownFile.fileName}.md`);
393467
await writeFile(filePath, markdownFile.content.join("\n"), "utf8");
394468
}
395-
const shouldOpenExportedResults = await showInformationMessageWithAction(
469+
470+
// This needs to use .then to ensure we aren't keeping the progress notification open. We shouldn't await the
471+
// "Open exported results" button click.
472+
void showInformationMessageWithAction(
396473
`Variant analysis results exported to \"${exportedResultsPath}\".`,
397474
"Open exported results",
398-
);
399-
if (shouldOpenExportedResults) {
475+
).then(async (shouldOpenExportedResults) => {
476+
if (!shouldOpenExportedResults) {
477+
return;
478+
}
479+
400480
const summaryFilePath = join(exportedResultsPath, "_summary.md");
401481
const summaryFile = await workspace.openTextDocument(summaryFilePath);
402482
await window.showTextDocument(summaryFile, ViewColumn.One);
403483
await commands.executeCommand("revealFileInOS", Uri.file(summaryFilePath));
404-
}
484+
});
405485
}

0 commit comments

Comments
 (0)