Skip to content

Commit bbdad0a

Browse files
authored
Merge pull request #1720 from github/koesie10/stop-query-button
Add cancelling of variant analysis to view
2 parents 4c0c93d + 89359e3 commit bbdad0a

File tree

10 files changed

+134
-25
lines changed

10 files changed

+134
-25
lines changed

extensions/ql-vscode/src/extension.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -953,6 +953,14 @@ async function activateWithInstalledDistribution(
953953
})
954954
);
955955

956+
ctx.subscriptions.push(
957+
commandRunner('codeQL.cancelVariantAnalysis', async (
958+
variantAnalysisId: number,
959+
) => {
960+
await variantAnalysisManager.cancelVariantAnalysis(variantAnalysisId);
961+
})
962+
);
963+
956964
ctx.subscriptions.push(
957965
commandRunner('codeQL.openVariantAnalysis', async () => {
958966
await variantAnalysisManager.promptOpenVariantAnalysis();

extensions/ql-vscode/src/pure/interface-types.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -445,11 +445,6 @@ export interface SetVariantAnalysisMessage {
445445
variantAnalysis: VariantAnalysis;
446446
}
447447

448-
export type StopVariantAnalysisMessage = {
449-
t: 'stopVariantAnalysis';
450-
variantAnalysisId: number;
451-
}
452-
453448
export type VariantAnalysisState = {
454449
variantAnalysisId: number;
455450
}
@@ -481,15 +476,19 @@ export interface OpenLogsMessage {
481476
t: 'openLogs';
482477
}
483478

479+
export interface CancelVariantAnalysisMessage {
480+
t: 'cancelVariantAnalysis';
481+
}
482+
484483
export type ToVariantAnalysisMessage =
485484
| SetVariantAnalysisMessage
486485
| SetRepoResultsMessage
487486
| SetRepoStatesMessage;
488487

489488
export type FromVariantAnalysisMessage =
490489
| ViewLoadedMsg
491-
| StopVariantAnalysisMessage
492490
| RequestRepositoryResultsMessage
493491
| OpenQueryFileMessage
494492
| OpenQueryTextMessage
495-
| OpenLogsMessage;
493+
| OpenLogsMessage
494+
| CancelVariantAnalysisMessage;

extensions/ql-vscode/src/query-history.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ import * as fs from 'fs-extra';
4040
import { CliVersionConstraint } from './cli';
4141
import { HistoryItemLabelProvider } from './history-item-label-provider';
4242
import { Credentials } from './authentication';
43-
import { cancelRemoteQuery, cancelVariantAnalysis } from './remote-queries/gh-api/gh-actions-api-client';
43+
import { cancelRemoteQuery } from './remote-queries/gh-api/gh-actions-api-client';
4444
import { RemoteQueriesManager } from './remote-queries/remote-queries-manager';
4545
import { RemoteQueryHistoryItem } from './remote-queries/remote-query-history-item';
4646
import { ResultsView } from './interface';
@@ -1119,9 +1119,7 @@ export class QueryHistoryManager extends DisposableObject {
11191119
const credentials = await this.getCredentials();
11201120
await cancelRemoteQuery(credentials, item.remoteQuery);
11211121
} else if (item.t === 'variant-analysis') {
1122-
void showAndLogInformationMessage('Cancelling variant analysis. This may take a while.');
1123-
const credentials = await this.getCredentials();
1124-
await cancelVariantAnalysis(credentials, item.variantAnalysis);
1122+
await commands.executeCommand('codeQL.cancelVariantAnalysis', item.variantAnalysis.id);
11251123
}
11261124
}
11271125
});

extensions/ql-vscode/src/remote-queries/variant-analysis-manager.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,9 @@ import { VariantAnalysisResultsManager } from './variant-analysis-results-manage
2222
import { getControllerRepo } from './run-remote-query';
2323
import { processUpdatedVariantAnalysis, processVariantAnalysisRepositoryTask } from './variant-analysis-processor';
2424
import PQueue from 'p-queue';
25-
import { createTimestampFile, showAndLogErrorMessage } from '../helpers';
25+
import { createTimestampFile, showAndLogErrorMessage, showAndLogInformationMessage } from '../helpers';
2626
import * as fs from 'fs-extra';
27+
import { cancelVariantAnalysis } from './gh-api/gh-actions-api-client';
2728

2829
export class VariantAnalysisManager extends DisposableObject implements VariantAnalysisViewManager<VariantAnalysisView> {
2930
private static readonly REPO_STATES_FILENAME = 'repo_states.json';
@@ -281,6 +282,25 @@ export class VariantAnalysisManager extends DisposableObject implements VariantA
281282
);
282283
}
283284

285+
public async cancelVariantAnalysis(variantAnalysisId: number) {
286+
const variantAnalysis = this.variantAnalyses.get(variantAnalysisId);
287+
if (!variantAnalysis) {
288+
throw new Error(`No variant analysis with id: ${variantAnalysisId}`);
289+
}
290+
291+
if (!variantAnalysis.actionsWorkflowRunId) {
292+
throw new Error(`No workflow run id for variant analysis with id: ${variantAnalysis.id}`);
293+
}
294+
295+
const credentials = await Credentials.initialize(this.ctx);
296+
if (!credentials) {
297+
throw Error('Error authenticating with GitHub');
298+
}
299+
300+
void showAndLogInformationMessage('Cancelling variant analysis. This may take a while.');
301+
await cancelVariantAnalysis(credentials, variantAnalysis);
302+
}
303+
284304
private getRepoStatesStoragePath(variantAnalysisId: number): string {
285305
return path.join(
286306
this.getVariantAnalysisStorageLocation(variantAnalysisId),

extensions/ql-vscode/src/remote-queries/variant-analysis-view.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,8 @@ export class VariantAnalysisView extends AbstractWebview<ToVariantAnalysisMessag
9191
await this.onWebViewLoaded();
9292

9393
break;
94-
case 'stopVariantAnalysis':
95-
void logger.log(`Stop variant analysis: ${msg.variantAnalysisId}`);
94+
case 'cancelVariantAnalysis':
95+
void commands.executeCommand('codeQL.cancelVariantAnalysis', this.variantAnalysisId);
9696
break;
9797
case 'requestRepositoryResults':
9898
void commands.executeCommand('codeQL.loadVariantAnalysisRepoResults', this.variantAnalysisId, msg.repositoryFullName);

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,12 @@ const openQueryText = () => {
3030
});
3131
};
3232

33+
const stopQuery = () => {
34+
vscode.postMessage({
35+
t: 'cancelVariantAnalysis',
36+
});
37+
};
38+
3339
const openLogs = () => {
3440
vscode.postMessage({
3541
t: 'openLogs',
@@ -88,7 +94,7 @@ export function VariantAnalysis({
8894
variantAnalysis={variantAnalysis}
8995
onOpenQueryFileClick={openQueryFile}
9096
onViewQueryTextClick={openQueryText}
91-
onStopQueryClick={() => console.log('Stop query')}
97+
onStopQueryClick={stopQuery}
9298
onCopyRepositoryListClick={() => console.log('Copy repository list')}
9399
onExportResultsClick={() => console.log('Export results')}
94100
onViewLogsClick={openLogs}

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ type Props = {
77
variantAnalysisStatus: VariantAnalysisStatus;
88

99
onStopQueryClick: () => void;
10+
stopQueryDisabled?: boolean;
1011

1112
onCopyRepositoryListClick: () => void;
1213
onExportResultsClick: () => void;
@@ -26,12 +27,13 @@ export const VariantAnalysisActions = ({
2627
variantAnalysisStatus,
2728
onStopQueryClick,
2829
onCopyRepositoryListClick,
29-
onExportResultsClick
30+
onExportResultsClick,
31+
stopQueryDisabled,
3032
}: Props) => {
3133
return (
3234
<Container>
3335
{variantAnalysisStatus === VariantAnalysisStatus.InProgress && (
34-
<Button appearance="secondary" onClick={onStopQueryClick}>
36+
<Button appearance="secondary" onClick={onStopQueryClick} disabled={stopQueryDisabled}>
3537
Stop query
3638
</Button>
3739
)}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ export const VariantAnalysisHeader = ({
7373
onStopQueryClick={onStopQueryClick}
7474
onCopyRepositoryListClick={onCopyRepositoryListClick}
7575
onExportResultsClick={onExportResultsClick}
76+
stopQueryDisabled={!variantAnalysis.actionsWorkflowRunId}
7677
/>
7778
</Row>
7879
<VariantAnalysisStats

extensions/ql-vscode/src/vscode-tests/cli-integration/remote-queries/variant-analysis-manager.test.ts

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { CodeQLExtensionInterface } from '../../../extension';
55
import { logger } from '../../../logging';
66
import * as config from '../../../config';
77
import * as ghApiClient from '../../../remote-queries/gh-api/gh-api-client';
8+
import * as ghActionsApiClient from '../../../remote-queries/gh-api/gh-actions-api-client';
89
import { Credentials } from '../../../authentication';
910
import * as fs from 'fs-extra';
1011
import * as path from 'path';
@@ -508,4 +509,80 @@ describe('Variant Analysis Manager', async function() {
508509
});
509510
});
510511
});
512+
513+
describe('cancelVariantAnalysis', async () => {
514+
let variantAnalysis: VariantAnalysis;
515+
let mockCancelVariantAnalysis: sinon.SinonStub;
516+
let getOctokitStub: sinon.SinonStub;
517+
518+
let variantAnalysisStorageLocation: string;
519+
520+
beforeEach(async () => {
521+
variantAnalysis = createMockVariantAnalysis({});
522+
523+
mockCancelVariantAnalysis = sandbox.stub(ghActionsApiClient, 'cancelVariantAnalysis');
524+
525+
variantAnalysisStorageLocation = variantAnalysisManager.getVariantAnalysisStorageLocation(variantAnalysis.id);
526+
await createTimestampFile(variantAnalysisStorageLocation);
527+
await variantAnalysisManager.rehydrateVariantAnalysis(variantAnalysis);
528+
});
529+
530+
afterEach(() => {
531+
fs.rmSync(variantAnalysisStorageLocation, { recursive: true });
532+
});
533+
534+
describe('when the credentials are invalid', () => {
535+
beforeEach(async () => {
536+
sandbox.stub(Credentials, 'initialize').resolves(undefined);
537+
});
538+
539+
it('should return early', async () => {
540+
try {
541+
await variantAnalysisManager.cancelVariantAnalysis(variantAnalysis.id);
542+
} catch (error: any) {
543+
expect(error.message).to.equal('Error authenticating with GitHub');
544+
}
545+
});
546+
});
547+
548+
describe('when the credentials are valid', () => {
549+
let mockCredentials: Credentials;
550+
551+
beforeEach(async () => {
552+
mockCredentials = {
553+
getOctokit: () => Promise.resolve({
554+
request: getOctokitStub
555+
})
556+
} as unknown as Credentials;
557+
sandbox.stub(Credentials, 'initialize').resolves(mockCredentials);
558+
});
559+
560+
it('should return early if the variant analysis is not found', async () => {
561+
try {
562+
await variantAnalysisManager.cancelVariantAnalysis(variantAnalysis.id + 100);
563+
} catch (error: any) {
564+
expect(error.message).to.equal('No variant analysis with id: ' + (variantAnalysis.id + 100));
565+
}
566+
});
567+
568+
it('should return early if the variant analysis does not have an actions workflow run id', async () => {
569+
await variantAnalysisManager.onVariantAnalysisUpdated({
570+
...variantAnalysis,
571+
actionsWorkflowRunId: undefined,
572+
});
573+
574+
try {
575+
await variantAnalysisManager.cancelVariantAnalysis(variantAnalysis.id);
576+
} catch (error: any) {
577+
expect(error.message).to.equal(`No workflow run id for variant analysis with id: ${variantAnalysis.id}`);
578+
}
579+
});
580+
581+
it('should return cancel if valid', async () => {
582+
await variantAnalysisManager.cancelVariantAnalysis(variantAnalysis.id);
583+
584+
expect(mockCancelVariantAnalysis).to.have.been.calledWith(mockCredentials, variantAnalysis);
585+
});
586+
});
587+
});
511588
});

extensions/ql-vscode/src/vscode-tests/no-workspace/query-history.test.ts

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,6 @@ describe('query-history', () => {
338338
describe('handleCancel', () => {
339339
let mockCredentials: Credentials;
340340
let mockCancelRemoteQuery: sinon.SinonStub;
341-
let mockCancelVariantAnalysis: sinon.SinonStub;
342341
let getOctokitStub: sinon.SinonStub;
343342

344343
beforeEach(async () => {
@@ -349,7 +348,6 @@ describe('query-history', () => {
349348
} as unknown as Credentials;
350349
sandbox.stub(Credentials, 'initialize').resolves(mockCredentials);
351350
mockCancelRemoteQuery = sandbox.stub(ghActionsApiClient, 'cancelRemoteQuery');
352-
mockCancelVariantAnalysis = sandbox.stub(ghActionsApiClient, 'cancelVariantAnalysis');
353351
});
354352

355353
describe('if the item is in progress', async () => {
@@ -408,7 +406,7 @@ describe('query-history', () => {
408406
const inProgress1 = variantAnalysisHistory[1];
409407

410408
await queryHistoryManager.handleCancel(inProgress1, [inProgress1]);
411-
expect(mockCancelVariantAnalysis).to.have.been.calledWith(mockCredentials, inProgress1.variantAnalysis);
409+
expect(executeCommandSpy).to.have.been.calledWith('codeQL.cancelVariantAnalysis', inProgress1.variantAnalysis.id);
412410
});
413411

414412
it('should cancel multiple variant analyses', async () => {
@@ -419,8 +417,8 @@ describe('query-history', () => {
419417
const inProgress2 = variantAnalysisHistory[3];
420418

421419
await queryHistoryManager.handleCancel(inProgress1, [inProgress1, inProgress2]);
422-
expect(mockCancelVariantAnalysis).to.have.been.calledWith(mockCredentials, inProgress1.variantAnalysis);
423-
expect(mockCancelVariantAnalysis).to.have.been.calledWith(mockCredentials, inProgress2.variantAnalysis);
420+
expect(executeCommandSpy).to.have.been.calledWith('codeQL.cancelVariantAnalysis', inProgress1.variantAnalysis.id);
421+
expect(executeCommandSpy).to.have.been.calledWith('codeQL.cancelVariantAnalysis', inProgress2.variantAnalysis.id);
424422
});
425423
});
426424

@@ -480,7 +478,7 @@ describe('query-history', () => {
480478
const completedVariantAnalysis = variantAnalysisHistory[0];
481479

482480
await queryHistoryManager.handleCancel(completedVariantAnalysis, [completedVariantAnalysis]);
483-
expect(mockCancelVariantAnalysis).to.not.have.been.calledWith(mockCredentials, completedVariantAnalysis.variantAnalysis);
481+
expect(executeCommandSpy).to.not.have.been.calledWith('codeQL.cancelVariantAnalysis', completedVariantAnalysis.variantAnalysis);
484482
});
485483

486484
it('should not cancel multiple variant analyses', async () => {
@@ -491,8 +489,8 @@ describe('query-history', () => {
491489
const failedVariantAnalysis = variantAnalysisHistory[2];
492490

493491
await queryHistoryManager.handleCancel(completedVariantAnalysis, [completedVariantAnalysis, failedVariantAnalysis]);
494-
expect(mockCancelVariantAnalysis).to.not.have.been.calledWith(mockCredentials, completedVariantAnalysis.variantAnalysis);
495-
expect(mockCancelVariantAnalysis).to.not.have.been.calledWith(mockCredentials, failedVariantAnalysis.variantAnalysis);
492+
expect(executeCommandSpy).to.not.have.been.calledWith('codeQL.cancelVariantAnalysis', completedVariantAnalysis.variantAnalysis.id);
493+
expect(executeCommandSpy).to.not.have.been.calledWith('codeQL.cancelVariantAnalysis', failedVariantAnalysis.variantAnalysis.id);
496494
});
497495
});
498496
});

0 commit comments

Comments
 (0)