Skip to content

Commit 627bb59

Browse files
committed
Merge remote-tracking branch 'origin/koesie10/request-repo-results-message' into koesie10/view-loaded-message
2 parents 99d2df2 + 95cbe02 commit 627bb59

File tree

11 files changed

+123
-75
lines changed

11 files changed

+123
-75
lines changed

extensions/ql-vscode/src/extension.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -467,16 +467,16 @@ async function activateWithInstalledDistribution(
467467
const localQueryResultsView = new ResultsView(ctx, dbm, cliServer, queryServerLogger, labelProvider);
468468
ctx.subscriptions.push(localQueryResultsView);
469469

470-
void logger.log('Initializing remote queries manager.');
471-
const rqm = new RemoteQueriesManager(ctx, cliServer, queryStorageDir, logger);
472-
ctx.subscriptions.push(rqm);
473-
474470
void logger.log('Initializing variant analysis manager.');
475471
const variantAnalysisStorageDir = path.join(ctx.globalStorageUri.fsPath, 'variant-analyses');
476472
await fs.ensureDir(variantAnalysisStorageDir);
477473
const variantAnalysisManager = new VariantAnalysisManager(ctx, cliServer, variantAnalysisStorageDir, logger);
478474
ctx.subscriptions.push(variantAnalysisManager);
479475

476+
void logger.log('Initializing remote queries manager.');
477+
const rqm = new RemoteQueriesManager(ctx, cliServer, queryStorageDir, logger, variantAnalysisManager);
478+
ctx.subscriptions.push(rqm);
479+
480480
void logger.log('Initializing query history.');
481481
const qhm = new QueryHistoryManager(
482482
qs,

extensions/ql-vscode/src/remote-queries/gh-api/gh-api-client.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -77,12 +77,9 @@ export async function getVariantAnalysisRepo(
7777
export async function getVariantAnalysisRepoResult(
7878
credentials: Credentials,
7979
downloadUrl: string,
80-
): Promise<unknown> {
80+
): Promise<ArrayBuffer> {
8181
const octokit = await credentials.getOctokit();
82-
83-
const response: OctokitResponse<VariantAnalysisRepoTask> = await octokit.request(
84-
`GET ${downloadUrl}`
85-
);
82+
const response = await octokit.request(`GET ${downloadUrl}`);
8683

8784
return response.data;
8885
}

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import { assertNever } from '../pure/helpers-pure';
2222
import { QueryStatus } from '../query-status';
2323
import { DisposableObject } from '../pure/disposable-object';
2424
import { AnalysisResults } from './shared/analysis-result';
25+
import { VariantAnalysisManager } from './variant-analysis-manager';
2526

2627
const autoDownloadMaxSize = 300 * 1024;
2728
const autoDownloadMaxCount = 100;
@@ -56,18 +57,21 @@ export class RemoteQueriesManager extends DisposableObject {
5657

5758
private readonly remoteQueriesMonitor: RemoteQueriesMonitor;
5859
private readonly analysesResultsManager: AnalysesResultsManager;
60+
private readonly variantAnalysisManager: VariantAnalysisManager;
5961
private readonly view: RemoteQueriesView;
6062

6163
constructor(
6264
private readonly ctx: ExtensionContext,
6365
private readonly cliServer: CodeQLCliServer,
6466
private readonly storagePath: string,
6567
logger: Logger,
68+
variantAnalysisManager: VariantAnalysisManager,
6669
) {
6770
super();
6871
this.analysesResultsManager = new AnalysesResultsManager(ctx, cliServer, storagePath, logger);
6972
this.view = new RemoteQueriesView(ctx, logger, this.analysesResultsManager);
7073
this.remoteQueriesMonitor = new RemoteQueriesMonitor(ctx, logger);
74+
this.variantAnalysisManager = variantAnalysisManager;
7175

7276
this.remoteQueryAddedEventEmitter = this.push(new EventEmitter<NewQueryEvent>());
7377
this.remoteQueryRemovedEventEmitter = this.push(new EventEmitter<RemovedQueryEvent>());
@@ -123,7 +127,8 @@ export class RemoteQueriesManager extends DisposableObject {
123127
credentials, uri || window.activeTextEditor?.document.uri,
124128
false,
125129
progress,
126-
token);
130+
token,
131+
this.variantAnalysisManager);
127132

128133
if (querySubmission?.query) {
129134
const query = querySubmission.query;

extensions/ql-vscode/src/remote-queries/run-remote-query.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import { getRepositorySelection, isValidSelection, RepositorySelection } from '.
2929
import { parseVariantAnalysisQueryLanguage, VariantAnalysisSubmission } from './shared/variant-analysis';
3030
import { Repository } from './shared/repository';
3131
import { processVariantAnalysis } from './variant-analysis-processor';
32+
import { VariantAnalysisManager } from './variant-analysis-manager';
3233

3334
export interface QlPack {
3435
name: string;
@@ -182,7 +183,8 @@ export async function runRemoteQuery(
182183
uri: Uri | undefined,
183184
dryRun: boolean,
184185
progress: ProgressCallback,
185-
token: CancellationToken
186+
token: CancellationToken,
187+
variantAnalysisManager: VariantAnalysisManager
186188
): Promise<void | RemoteQuerySubmissionResult> {
187189
if (!(await cliServer.cliConstraints.supportsRemoteQueries())) {
188190
throw new Error(`Variant analysis is not supported by this version of CodeQL. Please upgrade to v${cli.CliVersionConstraint.CLI_VERSION_REMOTE_QUERIES
@@ -273,6 +275,8 @@ export async function runRemoteQuery(
273275

274276
const processedVariantAnalysis = processVariantAnalysis(variantAnalysisSubmission, variantAnalysisResponse);
275277

278+
variantAnalysisManager.onVariantAnalysisSubmitted(processedVariantAnalysis);
279+
276280
void logger.log(`Variant analysis:\n${JSON.stringify(processedVariantAnalysis, null, 2)}`);
277281

278282
void showAndLogInformationMessage(`Variant analysis ${processedVariantAnalysis.query.name} submitted for processing`);

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import * as ghApiClient from './gh-api/gh-api-client';
2-
import { CancellationToken, ExtensionContext } from 'vscode';
2+
import { CancellationToken, EventEmitter, ExtensionContext } from 'vscode';
33
import { DisposableObject } from '../pure/disposable-object';
44
import { Logger } from '../logging';
55
import { Credentials } from '../authentication';
@@ -22,6 +22,9 @@ import { VariantAnalysisResultsManager } from './variant-analysis-results-manage
2222
import { CodeQLCliServer } from '../cli';
2323

2424
export class VariantAnalysisManager extends DisposableObject implements VariantAnalysisViewManager<VariantAnalysisView> {
25+
private readonly _onVariantAnalysisAdded = this.push(new EventEmitter<VariantAnalysis | undefined>());
26+
readonly onVariantAnalysisAdded = this._onVariantAnalysisAdded.event;
27+
2528
private readonly variantAnalysisMonitor: VariantAnalysisMonitor;
2629
private readonly variantAnalysisResultsManager: VariantAnalysisResultsManager;
2730
private readonly variantAnalyses = new Map<number, VariantAnalysis>();
@@ -91,6 +94,10 @@ export class VariantAnalysisManager extends DisposableObject implements VariantA
9194
await this.getView(variantAnalysis.id)?.updateView(variantAnalysis);
9295
}
9396

97+
public onVariantAnalysisSubmitted(variantAnalysis: VariantAnalysis): void {
98+
this._onVariantAnalysisAdded.fire(variantAnalysis);
99+
}
100+
94101
private async onRepoResultLoaded(repositoryResult: VariantAnalysisScannedRepositoryResult): Promise<void> {
95102
await this.getView(repositoryResult.variantAnalysisId)?.sendRepositoryResults([repositoryResult]);
96103
}

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

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { DisposableObject, DisposeHandler } from '../pure/disposable-object';
1414
import { VariantAnalysisRepoTask } from './gh-api/variant-analysis';
1515
import * as ghApiClient from './gh-api/gh-api-client';
1616
import { EventEmitter } from 'vscode';
17+
import { unzipFile } from '../pure/zip';
1718

1819
type CacheKey = `${number}/${string}`;
1920

@@ -26,6 +27,7 @@ export type ResultDownloadedEvent = {
2627

2728
export class VariantAnalysisResultsManager extends DisposableObject {
2829
private static readonly REPO_TASK_FILENAME = 'repo_task.json';
30+
private static readonly RESULTS_DIRECTORY = 'results';
2931

3032
private readonly cachedResults: Map<CacheKey, VariantAnalysisScannedRepositoryResult>;
3133

@@ -60,9 +62,17 @@ export class VariantAnalysisResultsManager extends DisposableObject {
6062
repoTask.artifact_url
6163
);
6264

63-
fs.mkdirSync(resultDirectory, { recursive: true });
65+
if (!(await fs.pathExists(resultDirectory))) {
66+
await fs.mkdir(resultDirectory, { recursive: true });
67+
}
68+
6469
await fs.outputJson(path.join(resultDirectory, VariantAnalysisResultsManager.REPO_TASK_FILENAME), repoTask);
65-
await fs.writeFile(path.join(resultDirectory, 'results.zip'), JSON.stringify(result, null, 2), 'utf8');
70+
71+
const zipFilePath = path.join(resultDirectory, 'results.zip');
72+
const unzippedFilesDirectory = path.join(resultDirectory, VariantAnalysisResultsManager.RESULTS_DIRECTORY);
73+
74+
fs.writeFileSync(zipFilePath, Buffer.from(result));
75+
await unzipFile(zipFilePath, unzippedFilesDirectory);
6676

6777
this._onResultDownloaded.fire({
6878
variantAnalysisId,
@@ -107,8 +117,9 @@ export class VariantAnalysisResultsManager extends DisposableObject {
107117

108118
const fileLinkPrefix = this.createGitHubDotcomFileLinkPrefix(repoTask.repository.full_name, repoTask.database_commit_sha);
109119

110-
const sarifPath = path.join(storageDirectory, 'results.sarif');
111-
const bqrsPath = path.join(storageDirectory, 'results.bqrs');
120+
const resultsDirectory = path.join(storageDirectory, VariantAnalysisResultsManager.RESULTS_DIRECTORY);
121+
const sarifPath = path.join(resultsDirectory, 'results.sarif');
122+
const bqrsPath = path.join(resultsDirectory, 'results.bqrs');
112123
if (await fs.pathExists(sarifPath)) {
113124
const interpretedResults = await this.readSarifResults(sarifPath, fileLinkPrefix);
114125

@@ -161,7 +172,7 @@ export class VariantAnalysisResultsManager extends DisposableObject {
161172
);
162173
}
163174

164-
private getRepoStorageDirectory(variantAnalysisId: number, fullName: string): string {
175+
public getRepoStorageDirectory(variantAnalysisId: number, fullName: string): string {
165176
return path.join(
166177
this.getStorageDirectory(variantAnalysisId),
167178
fullName
Binary file not shown.

extensions/ql-vscode/src/vscode-tests/cli-integration/remote-queries/run-remote-query.test.ts

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { assert, expect } from 'chai';
22
import * as path from 'path';
33
import * as sinon from 'sinon';
4-
import { CancellationTokenSource, extensions, QuickPickItem, Uri, window } from 'vscode';
4+
import { CancellationTokenSource, ExtensionContext, extensions, QuickPickItem, Uri, window } from 'vscode';
55
import * as fs from 'fs-extra';
66
import * as os from 'os';
77
import * as yaml from 'js-yaml';
@@ -21,6 +21,9 @@ import {
2121
import { Repository } from '../../../remote-queries/gh-api/repository';
2222
import { VariantAnalysisStatus } from '../../../remote-queries/shared/variant-analysis';
2323
import { createMockApiResponse } from '../../factories/remote-queries/gh-api/variant-analysis-api-response';
24+
import { createMockExtensionContext } from '../../no-workspace';
25+
import { VariantAnalysisManager } from '../../../remote-queries/variant-analysis-manager';
26+
import { OutputChannelLogger } from '../../../logging';
2427

2528
describe('Remote queries', function() {
2629
const baseDir = path.join(__dirname, '../../../../src/vscode-tests/cli-integration');
@@ -37,6 +40,9 @@ describe('Remote queries', function() {
3740
let showQuickPickSpy: sinon.SinonStub;
3841
let getRepositoryFromNwoStub: sinon.SinonStub;
3942
let liveResultsStub: sinon.SinonStub;
43+
let ctx: ExtensionContext;
44+
let logger: any;
45+
let variantAnalysisManager: VariantAnalysisManager;
4046

4147
// use `function` so we have access to `this`
4248
beforeEach(async function() {
@@ -49,21 +55,18 @@ describe('Remote queries', function() {
4955
throw new Error('Extension not initialized. Make sure cli is downloaded and installed properly.');
5056
}
5157

58+
ctx = createMockExtensionContext();
59+
logger = new OutputChannelLogger('test-logger');
60+
variantAnalysisManager = new VariantAnalysisManager(ctx, cli, 'fake-storage-dir', logger);
61+
5262
if (!(await cli.cliConstraints.supportsRemoteQueries())) {
5363
console.log(`Remote queries are not supported on CodeQL CLI v${CliVersionConstraint.CLI_VERSION_REMOTE_QUERIES
5464
}. Skipping this test.`);
5565
this.skip();
5666
}
5767
credentials = {} as unknown as Credentials;
5868

59-
cancellationTokenSource = {
60-
token: {
61-
isCancellationRequested: false,
62-
onCancellationRequested: sandbox.stub()
63-
},
64-
cancel: sandbox.stub(),
65-
dispose: sandbox.stub()
66-
};
69+
cancellationTokenSource = new CancellationTokenSource();
6770

6871
progress = sandbox.spy();
6972
// Should not have asked for a language
@@ -94,7 +97,7 @@ describe('Remote queries', function() {
9497
it('should run a remote query that is part of a qlpack', async () => {
9598
const fileUri = getFile('data-remote-qlpack/in-pack.ql');
9699

97-
const querySubmissionResult = await runRemoteQuery(cli, credentials, fileUri, true, progress, cancellationTokenSource.token);
100+
const querySubmissionResult = await runRemoteQuery(cli, credentials, fileUri, true, progress, cancellationTokenSource.token, variantAnalysisManager);
98101
expect(querySubmissionResult).to.be.ok;
99102
const queryPackRootDir = querySubmissionResult!.queryDirPath!;
100103
printDirectoryContents(queryPackRootDir);
@@ -155,7 +158,7 @@ describe('Remote queries', function() {
155158
it('should run a remote query that is not part of a qlpack', async () => {
156159
const fileUri = getFile('data-remote-no-qlpack/in-pack.ql');
157160

158-
const querySubmissionResult = await runRemoteQuery(cli, credentials, fileUri, true, progress, cancellationTokenSource.token);
161+
const querySubmissionResult = await runRemoteQuery(cli, credentials, fileUri, true, progress, cancellationTokenSource.token, variantAnalysisManager);
159162
expect(querySubmissionResult).to.be.ok;
160163
const queryPackRootDir = querySubmissionResult!.queryDirPath!;
161164

@@ -218,7 +221,7 @@ describe('Remote queries', function() {
218221
it('should run a remote query that is nested inside a qlpack', async () => {
219222
const fileUri = getFile('data-remote-qlpack-nested/subfolder/in-pack.ql');
220223

221-
const querySubmissionResult = await runRemoteQuery(cli, credentials, fileUri, true, progress, cancellationTokenSource.token);
224+
const querySubmissionResult = await runRemoteQuery(cli, credentials, fileUri, true, progress, cancellationTokenSource.token, variantAnalysisManager);
222225
expect(querySubmissionResult).to.be.ok;
223226
const queryPackRootDir = querySubmissionResult!.queryDirPath!;
224227

@@ -280,9 +283,9 @@ describe('Remote queries', function() {
280283
it('should cancel a run before uploading', async () => {
281284
const fileUri = getFile('data-remote-no-qlpack/in-pack.ql');
282285

283-
const promise = runRemoteQuery(cli, credentials, fileUri, true, progress, cancellationTokenSource.token);
286+
const promise = runRemoteQuery(cli, credentials, fileUri, true, progress, cancellationTokenSource.token, variantAnalysisManager);
284287

285-
cancellationTokenSource.token.isCancellationRequested = true;
288+
cancellationTokenSource.cancel();
286289

287290
try {
288291
await promise;
@@ -306,7 +309,7 @@ describe('Remote queries', function() {
306309
it('should run a variant analysis that is part of a qlpack', async () => {
307310
const fileUri = getFile('data-remote-qlpack/in-pack.ql');
308311

309-
const querySubmissionResult = await runRemoteQuery(cli, credentials, fileUri, true, progress, cancellationTokenSource.token);
312+
const querySubmissionResult = await runRemoteQuery(cli, credentials, fileUri, true, progress, cancellationTokenSource.token, variantAnalysisManager);
310313
expect(querySubmissionResult).to.be.ok;
311314
const variantAnalysis = querySubmissionResult!.variantAnalysis!;
312315
expect(variantAnalysis.id).to.be.equal(mockApiResponse.id);
@@ -319,7 +322,7 @@ describe('Remote queries', function() {
319322
it('should run a remote query that is not part of a qlpack', async () => {
320323
const fileUri = getFile('data-remote-no-qlpack/in-pack.ql');
321324

322-
const querySubmissionResult = await runRemoteQuery(cli, credentials, fileUri, true, progress, cancellationTokenSource.token);
325+
const querySubmissionResult = await runRemoteQuery(cli, credentials, fileUri, true, progress, cancellationTokenSource.token, variantAnalysisManager);
323326
expect(querySubmissionResult).to.be.ok;
324327
const variantAnalysis = querySubmissionResult!.variantAnalysis!;
325328
expect(variantAnalysis.id).to.be.equal(mockApiResponse.id);
@@ -332,7 +335,7 @@ describe('Remote queries', function() {
332335
it('should run a remote query that is nested inside a qlpack', async () => {
333336
const fileUri = getFile('data-remote-qlpack-nested/subfolder/in-pack.ql');
334337

335-
const querySubmissionResult = await runRemoteQuery(cli, credentials, fileUri, true, progress, cancellationTokenSource.token);
338+
const querySubmissionResult = await runRemoteQuery(cli, credentials, fileUri, true, progress, cancellationTokenSource.token, variantAnalysisManager);
336339
expect(querySubmissionResult).to.be.ok;
337340
const variantAnalysis = querySubmissionResult!.variantAnalysis!;
338341
expect(variantAnalysis.id).to.be.equal(mockApiResponse.id);
@@ -345,9 +348,9 @@ describe('Remote queries', function() {
345348
it('should cancel a run before uploading', async () => {
346349
const fileUri = getFile('data-remote-no-qlpack/in-pack.ql');
347350

348-
const promise = runRemoteQuery(cli, credentials, fileUri, true, progress, cancellationTokenSource.token);
351+
const promise = runRemoteQuery(cli, credentials, fileUri, true, progress, cancellationTokenSource.token, variantAnalysisManager);
349352

350-
cancellationTokenSource.token.isCancellationRequested = true;
353+
cancellationTokenSource.cancel();
351354

352355
try {
353356
await promise;

0 commit comments

Comments
 (0)