Skip to content

Commit 57ee00e

Browse files
authored
Merge pull request #1631 from github/shati-patel/storage-dir
Get `variantAnalysisStoragePath` from the variant analysis manager + create `timestamp` file
2 parents 4bc7992 + cc74533 commit 57ee00e

File tree

4 files changed

+59
-30
lines changed

4 files changed

+59
-30
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,7 @@ export async function runRemoteQuery(
278278

279279
const processedVariantAnalysis = processVariantAnalysis(variantAnalysisSubmission, variantAnalysisResponse);
280280

281-
variantAnalysisManager.onVariantAnalysisSubmitted(processedVariantAnalysis);
281+
await variantAnalysisManager.onVariantAnalysisSubmitted(processedVariantAnalysis);
282282

283283
void logger.log(`Variant analysis:\n${JSON.stringify(processedVariantAnalysis, null, 2)}`);
284284

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

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import * as path from 'path';
2+
13
import * as ghApiClient from './gh-api/gh-api-client';
24
import { CancellationToken, commands, EventEmitter, ExtensionContext, window } from 'vscode';
35
import { DisposableObject } from '../pure/disposable-object';
@@ -23,6 +25,7 @@ import { CodeQLCliServer } from '../cli';
2325
import { getControllerRepo } from './run-remote-query';
2426
import { processUpdatedVariantAnalysis } from './variant-analysis-processor';
2527
import PQueue from 'p-queue';
28+
import { createTimestampFile } from '../helpers';
2629

2730
export class VariantAnalysisManager extends DisposableObject implements VariantAnalysisViewManager<VariantAnalysisView> {
2831
private readonly _onVariantAnalysisAdded = this.push(new EventEmitter<VariantAnalysis>());
@@ -38,14 +41,14 @@ export class VariantAnalysisManager extends DisposableObject implements VariantA
3841
constructor(
3942
private readonly ctx: ExtensionContext,
4043
cliServer: CodeQLCliServer,
41-
storagePath: string,
44+
private readonly storagePath: string,
4245
logger: Logger,
4346
) {
4447
super();
4548
this.variantAnalysisMonitor = this.push(new VariantAnalysisMonitor(ctx));
4649
this.variantAnalysisMonitor.onVariantAnalysisChange(this.onVariantAnalysisUpdated.bind(this));
4750

48-
this.variantAnalysisResultsManager = this.push(new VariantAnalysisResultsManager(cliServer, storagePath, logger));
51+
this.variantAnalysisResultsManager = this.push(new VariantAnalysisResultsManager(cliServer, logger));
4952
this.variantAnalysisResultsManager.onResultLoaded(this.onRepoResultLoaded.bind(this));
5053
}
5154

@@ -86,7 +89,7 @@ export class VariantAnalysisManager extends DisposableObject implements VariantA
8689
throw new Error(`No variant analysis with id: ${variantAnalysisId}`);
8790
}
8891

89-
await this.variantAnalysisResultsManager.loadResults(variantAnalysisId, repositoryFullName);
92+
await this.variantAnalysisResultsManager.loadResults(variantAnalysisId, this.getVariantAnalysisStorageLocation(variantAnalysisId), repositoryFullName);
9093
}
9194

9295
private async onVariantAnalysisUpdated(variantAnalysis: VariantAnalysis | undefined): Promise<void> {
@@ -99,7 +102,9 @@ export class VariantAnalysisManager extends DisposableObject implements VariantA
99102
await this.getView(variantAnalysis.id)?.updateView(variantAnalysis);
100103
}
101104

102-
public onVariantAnalysisSubmitted(variantAnalysis: VariantAnalysis): void {
105+
public async onVariantAnalysisSubmitted(variantAnalysis: VariantAnalysis): Promise<void> {
106+
await this.prepareStorageDirectory(variantAnalysis.id);
107+
103108
this._onVariantAnalysisAdded.fire(variantAnalysis);
104109
}
105110

@@ -157,7 +162,7 @@ export class VariantAnalysisManager extends DisposableObject implements VariantA
157162
repoState.downloadStatus = VariantAnalysisScannedRepositoryDownloadStatus.InProgress;
158163
await this.onRepoStateUpdated(variantAnalysisSummary.id, repoState);
159164

160-
await this.variantAnalysisResultsManager.download(credentials, variantAnalysisSummary.id, repoTask);
165+
await this.variantAnalysisResultsManager.download(credentials, variantAnalysisSummary.id, repoTask, this.getVariantAnalysisStorageLocation(variantAnalysisSummary.id));
161166
}
162167

163168
repoState.downloadStatus = VariantAnalysisScannedRepositoryDownloadStatus.Succeeded;
@@ -176,6 +181,23 @@ export class VariantAnalysisManager extends DisposableObject implements VariantA
176181
return this.queue.pending;
177182
}
178183

184+
public getVariantAnalysisStorageLocation(variantAnalysisId: number): string {
185+
return path.join(
186+
this.storagePath,
187+
`${variantAnalysisId}`
188+
);
189+
}
190+
191+
/**
192+
* Prepares a directory for storing results for a variant analysis.
193+
* This directory contains a timestamp file, which will be
194+
* used by the query history manager to determine when the directory
195+
* should be deleted.
196+
*/
197+
private async prepareStorageDirectory(variantAnalysisId: number): Promise<void> {
198+
await createTimestampFile(this.getVariantAnalysisStorageLocation(variantAnalysisId));
199+
}
200+
179201
public async promptOpenVariantAnalysis() {
180202
const credentials = await Credentials.initialize(this.ctx);
181203
if (!credentials) { throw Error('Error authenticating with GitHub'); }

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

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ export class VariantAnalysisResultsManager extends DisposableObject {
3939

4040
constructor(
4141
private readonly cliServer: CodeQLCliServer,
42-
private readonly storagePath: string,
4342
private readonly logger: Logger,
4443
) {
4544
super();
@@ -50,12 +49,13 @@ export class VariantAnalysisResultsManager extends DisposableObject {
5049
credentials: Credentials,
5150
variantAnalysisId: number,
5251
repoTask: VariantAnalysisRepoTask,
52+
variantAnalysisStoragePath: string,
5353
): Promise<void> {
5454
if (!repoTask.artifact_url) {
5555
throw new Error('Missing artifact URL');
5656
}
5757

58-
const resultDirectory = this.getRepoStorageDirectory(variantAnalysisId, repoTask.repository.full_name);
58+
const resultDirectory = this.getRepoStorageDirectory(variantAnalysisStoragePath, repoTask.repository.full_name);
5959

6060
const result = await ghApiClient.getVariantAnalysisRepoResult(
6161
credentials,
@@ -82,32 +82,35 @@ export class VariantAnalysisResultsManager extends DisposableObject {
8282

8383
public async loadResults(
8484
variantAnalysisId: number,
85+
variantAnalysisStoragePath: string,
8586
repositoryFullName: string
8687
): Promise<VariantAnalysisScannedRepositoryResult> {
8788
const result = this.cachedResults.get(createCacheKey(variantAnalysisId, repositoryFullName));
8889

89-
return result ?? await this.loadResultsIntoMemory(variantAnalysisId, repositoryFullName);
90+
return result ?? await this.loadResultsIntoMemory(variantAnalysisId, variantAnalysisStoragePath, repositoryFullName);
9091
}
9192

9293
private async loadResultsIntoMemory(
9394
variantAnalysisId: number,
95+
variantAnalysisStoragePath: string,
9496
repositoryFullName: string,
9597
): Promise<VariantAnalysisScannedRepositoryResult> {
96-
const result = await this.loadResultsFromStorage(variantAnalysisId, repositoryFullName);
98+
const result = await this.loadResultsFromStorage(variantAnalysisId, variantAnalysisStoragePath, repositoryFullName);
9799
this.cachedResults.set(createCacheKey(variantAnalysisId, repositoryFullName), result);
98100
this._onResultLoaded.fire(result);
99101
return result;
100102
}
101103

102104
private async loadResultsFromStorage(
103105
variantAnalysisId: number,
106+
variantAnalysisStoragePath: string,
104107
repositoryFullName: string,
105108
): Promise<VariantAnalysisScannedRepositoryResult> {
106-
if (!(await this.isVariantAnalysisRepoDownloaded(variantAnalysisId, repositoryFullName))) {
109+
if (!(await this.isVariantAnalysisRepoDownloaded(variantAnalysisStoragePath, repositoryFullName))) {
107110
throw new Error('Variant analysis results not downloaded');
108111
}
109112

110-
const storageDirectory = this.getRepoStorageDirectory(variantAnalysisId, repositoryFullName);
113+
const storageDirectory = this.getRepoStorageDirectory(variantAnalysisStoragePath, repositoryFullName);
111114

112115
const repoTask: VariantAnalysisRepoTask = await fs.readJson(path.join(storageDirectory, VariantAnalysisResultsManager.REPO_TASK_FILENAME));
113116

@@ -144,10 +147,10 @@ export class VariantAnalysisResultsManager extends DisposableObject {
144147
}
145148

146149
private async isVariantAnalysisRepoDownloaded(
147-
variantAnalysisId: number,
150+
variantAnalysisStoragePath: string,
148151
repositoryFullName: string,
149152
): Promise<boolean> {
150-
return await fs.pathExists(this.getRepoStorageDirectory(variantAnalysisId, repositoryFullName));
153+
return await fs.pathExists(this.getRepoStorageDirectory(variantAnalysisStoragePath, repositoryFullName));
151154
}
152155

153156
private async readBqrsResults(filePath: string, fileLinkPrefix: string, sourceLocationPrefix: string): Promise<AnalysisRawResults> {
@@ -165,16 +168,9 @@ export class VariantAnalysisResultsManager extends DisposableObject {
165168
return processedSarif.alerts;
166169
}
167170

168-
private getStorageDirectory(variantAnalysisId: number): string {
169-
return path.join(
170-
this.storagePath,
171-
`${variantAnalysisId}`
172-
);
173-
}
174-
175-
public getRepoStorageDirectory(variantAnalysisId: number, fullName: string): string {
171+
public getRepoStorageDirectory(variantAnalysisStoragePath: string, fullName: string): string {
176172
return path.join(
177-
this.getStorageDirectory(variantAnalysisId),
173+
variantAnalysisStoragePath,
178174
fullName
179175
);
180176
}

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

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ import { faker } from '@faker-js/faker';
1515
import * as ghApiClient from '../../../remote-queries/gh-api/gh-api-client';
1616
import { VariantAnalysisRepoTask } from '../../../remote-queries/gh-api/variant-analysis';
1717

18-
describe(VariantAnalysisResultsManager.name, () => {
18+
describe(VariantAnalysisResultsManager.name, function() {
19+
this.timeout(10000);
20+
1921
let sandbox: sinon.SinonSandbox;
2022
let cli: CodeQLCliServer;
2123
let variantAnalysisId: number;
@@ -33,7 +35,7 @@ describe(VariantAnalysisResultsManager.name, () => {
3335
try {
3436
const extension = await extensions.getExtension<CodeQLExtensionInterface | Record<string, never>>('GitHub.vscode-codeql')!.activate();
3537
cli = extension.cliServer;
36-
variantAnalysisResultsManager = new VariantAnalysisResultsManager(cli, storagePath, logger);
38+
variantAnalysisResultsManager = new VariantAnalysisResultsManager(cli, logger);
3739
} catch (e) {
3840
fail(e as Error);
3941
}
@@ -45,12 +47,17 @@ describe(VariantAnalysisResultsManager.name, () => {
4547

4648
describe('download', () => {
4749
let getOctokitStub: sinon.SinonStub;
50+
let variantAnalysisStoragePath: string;
4851
const mockCredentials = {
4952
getOctokit: () => Promise.resolve({
5053
request: getOctokitStub
5154
})
5255
} as unknown as Credentials;
5356

57+
beforeEach(async () => {
58+
variantAnalysisStoragePath = path.join(storagePath, variantAnalysisId.toString());
59+
});
60+
5461
describe('when the artifact_url is missing', async () => {
5562
it('should not try to download the result', async () => {
5663
const dummyRepoTask = createMockVariantAnalysisRepoTask();
@@ -60,7 +67,8 @@ describe(VariantAnalysisResultsManager.name, () => {
6067
await variantAnalysisResultsManager.download(
6168
mockCredentials,
6269
variantAnalysisId,
63-
dummyRepoTask
70+
dummyRepoTask,
71+
variantAnalysisStoragePath
6472
);
6573

6674
expect.fail('Expected an error to be thrown');
@@ -78,7 +86,7 @@ describe(VariantAnalysisResultsManager.name, () => {
7886
beforeEach(async () => {
7987
dummyRepoTask = createMockVariantAnalysisRepoTask();
8088

81-
storageDirectory = variantAnalysisResultsManager.getRepoStorageDirectory(variantAnalysisId, dummyRepoTask.repository.full_name);
89+
storageDirectory = variantAnalysisResultsManager.getRepoStorageDirectory(variantAnalysisStoragePath, dummyRepoTask.repository.full_name);
8290
const sourceFilePath = path.join(__dirname, '../../../../src/vscode-tests/cli-integration/data/variant-analysis-results.zip');
8391
arrayBuffer = fs.readFileSync(sourceFilePath).buffer;
8492

@@ -97,7 +105,8 @@ describe(VariantAnalysisResultsManager.name, () => {
97105
await variantAnalysisResultsManager.download(
98106
mockCredentials,
99107
variantAnalysisId,
100-
dummyRepoTask
108+
dummyRepoTask,
109+
variantAnalysisStoragePath
101110
);
102111

103112
expect(getVariantAnalysisRepoResultStub.calledOnce).to.be.true;
@@ -107,7 +116,8 @@ describe(VariantAnalysisResultsManager.name, () => {
107116
await variantAnalysisResultsManager.download(
108117
mockCredentials,
109118
variantAnalysisId,
110-
dummyRepoTask
119+
dummyRepoTask,
120+
variantAnalysisStoragePath
111121
);
112122

113123
expect(fs.existsSync(`${storageDirectory}/results.zip`)).to.be.true;
@@ -117,7 +127,8 @@ describe(VariantAnalysisResultsManager.name, () => {
117127
await variantAnalysisResultsManager.download(
118128
mockCredentials,
119129
variantAnalysisId,
120-
dummyRepoTask
130+
dummyRepoTask,
131+
variantAnalysisStoragePath
121132
);
122133

123134
expect(fs.existsSync(`${storageDirectory}/results/results.sarif`)).to.be.true;

0 commit comments

Comments
 (0)