Merge pull request #1559 from github/elenatanasoiu/download-variant-analysis-results

Download variant analysis results
This commit is contained in:
Elena Tanasoiu
2022-10-05 11:43:05 +01:00
committed by GitHub
14 changed files with 463 additions and 51 deletions

View File

@@ -105,8 +105,12 @@ import { createInitialQueryInfo } from './run-queries-shared';
import { LegacyQueryRunner } from './legacy-query-server/legacyRunner';
import { QueryRunner } from './queryRunner';
import { VariantAnalysisView } from './remote-queries/variant-analysis-view';
import { VariantAnalysisMonitor } from './remote-queries/variant-analysis-monitor';
import { VariantAnalysis } from './remote-queries/shared/variant-analysis';
import {
VariantAnalysis as VariantAnalysisApiResponse,
VariantAnalysisScannedRepository as ApiVariantAnalysisScannedRepository
} from './remote-queries/gh-api/variant-analysis';
import { VariantAnalysisManager } from './remote-queries/variant-analysis-manager';
/**
* extension.ts
@@ -896,13 +900,23 @@ async function activateWithInstalledDistribution(
})
);
const variantAnalysisMonitor = new VariantAnalysisMonitor(ctx, logger);
const variantAnalysisManager = new VariantAnalysisManager(ctx, logger);
ctx.subscriptions.push(
commandRunner('codeQL.monitorVariantAnalysis', async (
variantAnalysis: VariantAnalysis,
token: CancellationToken
) => {
await variantAnalysisMonitor.monitorVariantAnalysis(variantAnalysis, token);
await variantAnalysisManager.monitorVariantAnalysis(variantAnalysis, token);
})
);
ctx.subscriptions.push(
commandRunner('codeQL.autoDownloadVariantAnalysisResult', async (
scannedRepo: ApiVariantAnalysisScannedRepository,
variantAnalysisSummary: VariantAnalysisApiResponse,
token: CancellationToken
) => {
await variantAnalysisManager.autoDownloadVariantAnalysisResult(scannedRepo, variantAnalysisSummary, token);
})
);

View File

@@ -74,6 +74,19 @@ export async function getVariantAnalysisRepo(
return response.data;
}
export async function getVariantAnalysisRepoResult(
credentials: Credentials,
downloadUrl: string,
): Promise<unknown> {
const octokit = await credentials.getOctokit();
const response: OctokitResponse<VariantAnalysisRepoTask> = await octokit.request(
`GET ${downloadUrl}`
);
return response.data;
}
export async function getRepositoryFromNwo(
credentials: Credentials,
owner: string,

View File

@@ -0,0 +1,81 @@
import * as ghApiClient from './gh-api/gh-api-client';
import * as path from 'path';
import * as fs from 'fs-extra';
import { CancellationToken, ExtensionContext } from 'vscode';
import { DisposableObject } from '../pure/disposable-object';
import { Logger } from '../logging';
import { Credentials } from '../authentication';
import { VariantAnalysisMonitor } from './variant-analysis-monitor';
import {
VariantAnalysis as VariantAnalysisApiResponse,
VariantAnalysisRepoTask,
VariantAnalysisScannedRepository as ApiVariantAnalysisScannedRepository
} from './gh-api/variant-analysis';
import { VariantAnalysis } from './shared/variant-analysis';
import { getErrorMessage } from '../pure/helpers-pure';
export class VariantAnalysisManager extends DisposableObject {
private readonly variantAnalysisMonitor: VariantAnalysisMonitor;
constructor(
private readonly ctx: ExtensionContext,
logger: Logger,
) {
super();
this.variantAnalysisMonitor = new VariantAnalysisMonitor(ctx, logger);
}
public async monitorVariantAnalysis(
variantAnalysis: VariantAnalysis,
cancellationToken: CancellationToken
): Promise<void> {
await this.variantAnalysisMonitor.monitorVariantAnalysis(variantAnalysis, cancellationToken);
}
public async autoDownloadVariantAnalysisResult(
scannedRepo: ApiVariantAnalysisScannedRepository,
variantAnalysisSummary: VariantAnalysisApiResponse,
cancellationToken: CancellationToken
): Promise<void> {
const credentials = await Credentials.initialize(this.ctx);
if (!credentials) { throw Error('Error authenticating with GitHub'); }
if (cancellationToken && cancellationToken.isCancellationRequested) {
return;
}
let repoTask: VariantAnalysisRepoTask;
try {
repoTask = await ghApiClient.getVariantAnalysisRepo(
credentials,
variantAnalysisSummary.controller_repo.id,
variantAnalysisSummary.id,
scannedRepo.repository.id
);
}
catch (e) { throw new Error(`Could not download the results for variant analysis with id: ${variantAnalysisSummary.id}. Error: ${getErrorMessage(e)}`); }
if (repoTask.artifact_url) {
const resultDirectory = path.join(
this.ctx.globalStorageUri.fsPath,
'variant-analyses',
`${variantAnalysisSummary.id}`,
scannedRepo.repository.full_name
);
const storagePath = path.join(
resultDirectory,
scannedRepo.repository.full_name
);
const result = await ghApiClient.getVariantAnalysisRepoResult(
credentials,
repoTask.artifact_url
);
fs.mkdirSync(resultDirectory, { recursive: true });
await fs.writeFile(storagePath, JSON.stringify(result, null, 2), 'utf8');
}
}
}

View File

@@ -1,4 +1,4 @@
import * as vscode from 'vscode';
import { ExtensionContext, CancellationToken, commands } from 'vscode';
import { Credentials } from '../authentication';
import { Logger } from '../logging';
import * as ghApiClient from './gh-api/gh-api-client';
@@ -17,14 +17,14 @@ export class VariantAnalysisMonitor {
public static sleepTime = 5000;
constructor(
private readonly extensionContext: vscode.ExtensionContext,
private readonly extensionContext: ExtensionContext,
private readonly logger: Logger
) {
}
public async monitorVariantAnalysis(
variantAnalysis: VariantAnalysis,
cancellationToken: vscode.CancellationToken
cancellationToken: CancellationToken
): Promise<VariantAnalysisMonitorResult> {
const credentials = await Credentials.initialize(this.extensionContext);
@@ -64,6 +64,7 @@ export class VariantAnalysisMonitor {
if (variantAnalysisSummary.scanned_repositories) {
variantAnalysisSummary.scanned_repositories.forEach(scannedRepo => {
if (!scannedReposDownloaded.includes(scannedRepo.repository.id) && scannedRepo.analysis_status === 'succeeded') {
void commands.executeCommand('codeQL.autoDownloadVariantAnalysisResult', scannedRepo, variantAnalysisSummary);
scannedReposDownloaded.push(scannedRepo.repository.id);
}
});

View File

@@ -1,7 +1,7 @@
import { assert, expect } from 'chai';
import * as path from 'path';
import * as sinon from 'sinon';
import { CancellationToken, extensions, QuickPickItem, Uri, window } from 'vscode';
import { CancellationTokenSource, extensions, QuickPickItem, Uri, window } from 'vscode';
import * as fs from 'fs-extra';
import * as os from 'os';
import * as yaml from 'js-yaml';
@@ -32,7 +32,7 @@ describe('Remote queries', function() {
let cli: CodeQLCliServer;
let credentials: Credentials = {} as unknown as Credentials;
let token: CancellationToken;
let cancellationTokenSource: CancellationTokenSource;
let progress: sinon.SinonSpy;
let showQuickPickSpy: sinon.SinonStub;
let getRepositoryFromNwoStub: sinon.SinonStub;
@@ -55,9 +55,15 @@ describe('Remote queries', function() {
this.skip();
}
credentials = {} as unknown as Credentials;
token = {
isCancellationRequested: false
} as unknown as CancellationToken;
cancellationTokenSource = {
token: {
isCancellationRequested: false,
onCancellationRequested: sandbox.stub()
},
cancel: sandbox.stub(),
dispose: sandbox.stub()
};
progress = sandbox.spy();
// Should not have asked for a language
@@ -88,7 +94,7 @@ describe('Remote queries', function() {
it('should run a remote query that is part of a qlpack', async () => {
const fileUri = getFile('data-remote-qlpack/in-pack.ql');
const querySubmissionResult = await runRemoteQuery(cli, credentials, fileUri, true, progress, token);
const querySubmissionResult = await runRemoteQuery(cli, credentials, fileUri, true, progress, cancellationTokenSource.token);
expect(querySubmissionResult).to.be.ok;
const queryPackRootDir = querySubmissionResult!.queryDirPath!;
printDirectoryContents(queryPackRootDir);
@@ -149,7 +155,7 @@ describe('Remote queries', function() {
it('should run a remote query that is not part of a qlpack', async () => {
const fileUri = getFile('data-remote-no-qlpack/in-pack.ql');
const querySubmissionResult = await runRemoteQuery(cli, credentials, fileUri, true, progress, token);
const querySubmissionResult = await runRemoteQuery(cli, credentials, fileUri, true, progress, cancellationTokenSource.token);
expect(querySubmissionResult).to.be.ok;
const queryPackRootDir = querySubmissionResult!.queryDirPath!;
@@ -212,7 +218,7 @@ describe('Remote queries', function() {
it('should run a remote query that is nested inside a qlpack', async () => {
const fileUri = getFile('data-remote-qlpack-nested/subfolder/in-pack.ql');
const querySubmissionResult = await runRemoteQuery(cli, credentials, fileUri, true, progress, token);
const querySubmissionResult = await runRemoteQuery(cli, credentials, fileUri, true, progress, cancellationTokenSource.token);
expect(querySubmissionResult).to.be.ok;
const queryPackRootDir = querySubmissionResult!.queryDirPath!;
@@ -274,9 +280,9 @@ describe('Remote queries', function() {
it('should cancel a run before uploading', async () => {
const fileUri = getFile('data-remote-no-qlpack/in-pack.ql');
const promise = runRemoteQuery(cli, credentials, fileUri, true, progress, token);
const promise = runRemoteQuery(cli, credentials, fileUri, true, progress, cancellationTokenSource.token);
token.isCancellationRequested = true;
cancellationTokenSource.token.isCancellationRequested = true;
try {
await promise;
@@ -300,7 +306,7 @@ describe('Remote queries', function() {
it('should run a variant analysis that is part of a qlpack', async () => {
const fileUri = getFile('data-remote-qlpack/in-pack.ql');
const querySubmissionResult = await runRemoteQuery(cli, credentials, fileUri, true, progress, token);
const querySubmissionResult = await runRemoteQuery(cli, credentials, fileUri, true, progress, cancellationTokenSource.token);
expect(querySubmissionResult).to.be.ok;
const variantAnalysis = querySubmissionResult!.variantAnalysis!;
expect(variantAnalysis.id).to.be.equal(mockApiResponse.id);
@@ -313,7 +319,7 @@ describe('Remote queries', function() {
it('should run a remote query that is not part of a qlpack', async () => {
const fileUri = getFile('data-remote-no-qlpack/in-pack.ql');
const querySubmissionResult = await runRemoteQuery(cli, credentials, fileUri, true, progress, token);
const querySubmissionResult = await runRemoteQuery(cli, credentials, fileUri, true, progress, cancellationTokenSource.token);
expect(querySubmissionResult).to.be.ok;
const variantAnalysis = querySubmissionResult!.variantAnalysis!;
expect(variantAnalysis.id).to.be.equal(mockApiResponse.id);
@@ -326,7 +332,7 @@ describe('Remote queries', function() {
it('should run a remote query that is nested inside a qlpack', async () => {
const fileUri = getFile('data-remote-qlpack-nested/subfolder/in-pack.ql');
const querySubmissionResult = await runRemoteQuery(cli, credentials, fileUri, true, progress, token);
const querySubmissionResult = await runRemoteQuery(cli, credentials, fileUri, true, progress, cancellationTokenSource.token);
expect(querySubmissionResult).to.be.ok;
const variantAnalysis = querySubmissionResult!.variantAnalysis!;
expect(variantAnalysis.id).to.be.equal(mockApiResponse.id);
@@ -339,9 +345,9 @@ describe('Remote queries', function() {
it('should cancel a run before uploading', async () => {
const fileUri = getFile('data-remote-no-qlpack/in-pack.ql');
const promise = runRemoteQuery(cli, credentials, fileUri, true, progress, token);
const promise = runRemoteQuery(cli, credentials, fileUri, true, progress, cancellationTokenSource.token);
token.isCancellationRequested = true;
cancellationTokenSource.token.isCancellationRequested = true;
try {
await promise;

View File

@@ -0,0 +1,161 @@
import * as sinon from 'sinon';
import { expect } from 'chai';
import { CancellationTokenSource, extensions } from 'vscode';
import { CodeQLExtensionInterface } from '../../../extension';
import { logger } from '../../../logging';
import * as config from '../../../config';
import * as ghApiClient from '../../../remote-queries/gh-api/gh-api-client';
import { Credentials } from '../../../authentication';
import * as fs from 'fs-extra';
import { VariantAnalysisManager } from '../../../remote-queries/variant-analysis-manager';
import {
VariantAnalysis as VariantAnalysisApiResponse,
VariantAnalysisScannedRepository as ApiVariantAnalysisScannedRepository
} from '../../../remote-queries/gh-api/variant-analysis';
import { createMockApiResponse } from '../../factories/remote-queries/gh-api/variant-analysis-api-response';
import { createMockScannedRepos } from '../../factories/remote-queries/gh-api/scanned-repositories';
import { createMockVariantAnalysisRepoTask } from '../../factories/remote-queries/gh-api/variant-analysis-repo-task';
describe('Variant Analysis Manager', async function() {
let sandbox: sinon.SinonSandbox;
let cancellationTokenSource: CancellationTokenSource;
let variantAnalysisManager: VariantAnalysisManager;
let variantAnalysis: VariantAnalysisApiResponse;
let scannedRepos: ApiVariantAnalysisScannedRepository[];
let getVariantAnalysisRepoStub: sinon.SinonStub;
let getVariantAnalysisRepoResultStub: sinon.SinonStub;
beforeEach(async () => {
sandbox = sinon.createSandbox();
sandbox.stub(logger, 'log');
sandbox.stub(config, 'isVariantAnalysisLiveResultsEnabled').returns(false);
sandbox.stub(fs, 'mkdirSync');
sandbox.stub(fs, 'writeFile');
cancellationTokenSource = {
token: {
isCancellationRequested: false,
onCancellationRequested: sandbox.stub()
},
cancel: sandbox.stub(),
dispose: sandbox.stub()
};
scannedRepos = createMockScannedRepos();
variantAnalysis = createMockApiResponse('in_progress', scannedRepos);
try {
const extension = await extensions.getExtension<CodeQLExtensionInterface | Record<string, never>>('GitHub.vscode-codeql')!.activate();
variantAnalysisManager = new VariantAnalysisManager(extension.ctx, logger);
} catch (e) {
fail(e as Error);
}
});
afterEach(async () => {
sandbox.restore();
});
describe('when credentials are invalid', async () => {
beforeEach(async () => { sandbox.stub(Credentials, 'initialize').resolves(undefined); });
it('should return early if credentials are wrong', async () => {
try {
await variantAnalysisManager.autoDownloadVariantAnalysisResult(
scannedRepos[0],
variantAnalysis,
cancellationTokenSource.token
);
} catch (error: any) {
expect(error.message).to.equal('Error authenticating with GitHub');
}
});
});
describe('when credentials are valid', async () => {
let getOctokitStub: sinon.SinonStub;
beforeEach(async () => {
const mockCredentials = {
getOctokit: () => Promise.resolve({
request: getOctokitStub
})
} as unknown as Credentials;
sandbox.stub(Credentials, 'initialize').resolves(mockCredentials);
});
describe('when the artifact_url is missing', async () => {
beforeEach(async () => {
const dummyRepoTask = createMockVariantAnalysisRepoTask();
delete dummyRepoTask.artifact_url;
getVariantAnalysisRepoStub = sandbox.stub(ghApiClient, 'getVariantAnalysisRepo').resolves(dummyRepoTask);
const dummyResult = 'this-is-a-repo-result';
getVariantAnalysisRepoResultStub = sandbox.stub(ghApiClient, 'getVariantAnalysisRepoResult').resolves(dummyResult);
});
it('should not try to download the result', async () => {
await variantAnalysisManager.autoDownloadVariantAnalysisResult(
scannedRepos[0],
variantAnalysis,
cancellationTokenSource.token
);
expect(getVariantAnalysisRepoResultStub.notCalled).to.be.true;
});
});
describe('when the artifact_url is present', async () => {
beforeEach(async () => {
const dummyRepoTask = createMockVariantAnalysisRepoTask();
getVariantAnalysisRepoStub = sandbox.stub(ghApiClient, 'getVariantAnalysisRepo').resolves(dummyRepoTask);
const dummyResult = 'this-is-a-repo-result';
getVariantAnalysisRepoResultStub = sandbox.stub(ghApiClient, 'getVariantAnalysisRepoResult').resolves(dummyResult);
});
it('should return early if variant analysis is cancelled', async () => {
cancellationTokenSource.token.isCancellationRequested = true;
await variantAnalysisManager.autoDownloadVariantAnalysisResult(
scannedRepos[0],
variantAnalysis,
cancellationTokenSource.token
);
expect(getVariantAnalysisRepoStub.notCalled).to.be.true;
});
it('should fetch a repo task', async () => {
await variantAnalysisManager.autoDownloadVariantAnalysisResult(
scannedRepos[0],
variantAnalysis,
cancellationTokenSource.token
);
expect(getVariantAnalysisRepoStub.calledOnce).to.be.true;
});
it('should fetch a repo result', async () => {
await variantAnalysisManager.autoDownloadVariantAnalysisResult(
scannedRepos[0],
variantAnalysis,
cancellationTokenSource.token
);
expect(getVariantAnalysisRepoResultStub.calledOnce).to.be.true;
});
it('should save the result to disk', async () => {
await variantAnalysisManager.autoDownloadVariantAnalysisResult(
scannedRepos[0],
variantAnalysis,
cancellationTokenSource.token
);
expect(getVariantAnalysisRepoResultStub.calledOnce).to.be.true;
});
});
});
});

View File

@@ -1,6 +1,6 @@
import * as sinon from 'sinon';
import { expect } from 'chai';
import { CancellationToken, extensions } from 'vscode';
import { CancellationTokenSource, extensions } from 'vscode';
import { CodeQLExtensionInterface } from '../../../extension';
import { logger } from '../../../logging';
import * as config from '../../../config';
@@ -13,32 +13,35 @@ import {
VariantAnalysisFailureReason
} from '../../../remote-queries/gh-api/variant-analysis';
import { createFailedMockApiResponse, createMockApiResponse } from '../../factories/remote-queries/gh-api/variant-analysis-api-response';
import { VariantAnalysisStatus } from '../../../remote-queries/shared/variant-analysis';
import { VariantAnalysis, VariantAnalysisStatus } from '../../../remote-queries/shared/variant-analysis';
import { createMockScannedRepos } from '../../factories/remote-queries/gh-api/scanned-repositories';
import { processFailureReason } from '../../../remote-queries/variant-analysis-processor';
import { Credentials } from '../../../authentication';
import { createMockVariantAnalysis } from '../../factories/remote-queries/shared/variant-analysis';
describe('Variant Analysis Monitor', async function() {
let sandbox: sinon.SinonSandbox;
let mockGetVariantAnalysis: sinon.SinonStub;
let cancellationToken: CancellationToken;
let cancellationTokenSource: CancellationTokenSource;
let variantAnalysisMonitor: VariantAnalysisMonitor;
let variantAnalysis: any;
let variantAnalysis: VariantAnalysis;
beforeEach(async () => {
sandbox = sinon.createSandbox();
sandbox.stub(logger, 'log');
sandbox.stub(config, 'isVariantAnalysisLiveResultsEnabled').returns(false);
cancellationToken = {
isCancellationRequested: false
} as unknown as CancellationToken;
variantAnalysis = {
id: 123,
controllerRepoId: 1,
cancellationTokenSource = {
token: {
isCancellationRequested: false,
onCancellationRequested: sandbox.stub()
},
cancel: sandbox.stub(),
dispose: sandbox.stub()
};
variantAnalysis = createMockVariantAnalysis();
try {
const extension = await extensions.getExtension<CodeQLExtensionInterface | Record<string, never>>('GitHub.vscode-codeql')!.activate();
variantAnalysisMonitor = new VariantAnalysisMonitor(extension.ctx, logger);
@@ -58,7 +61,7 @@ describe('Variant Analysis Monitor', async function() {
it('should return early if credentials are wrong', async () => {
try {
await variantAnalysisMonitor.monitorVariantAnalysis(variantAnalysis, cancellationToken);
await variantAnalysisMonitor.monitorVariantAnalysis(variantAnalysis, cancellationTokenSource.token);
} catch (error: any) {
expect(error.message).to.equal('Error authenticating with GitHub');
}
@@ -76,9 +79,9 @@ describe('Variant Analysis Monitor', async function() {
});
it('should return early if variant analysis is cancelled', async () => {
cancellationToken.isCancellationRequested = true;
cancellationTokenSource.token.isCancellationRequested = true;
const result = await variantAnalysisMonitor.monitorVariantAnalysis(variantAnalysis, cancellationToken);
const result = await variantAnalysisMonitor.monitorVariantAnalysis(variantAnalysis, cancellationTokenSource.token);
expect(result).to.eql({ status: 'Cancelled', error: 'Variant Analysis was canceled.' });
});
@@ -92,14 +95,13 @@ describe('Variant Analysis Monitor', async function() {
});
it('should mark as failed locally and stop monitoring', async () => {
const result = await variantAnalysisMonitor.monitorVariantAnalysis(variantAnalysis, cancellationToken);
variantAnalysis = result.variantAnalysis;
const result = await variantAnalysisMonitor.monitorVariantAnalysis(variantAnalysis, cancellationTokenSource.token);
expect(mockGetVariantAnalysis.calledOnce).to.be.true;
expect(result.status).to.eql('Failed');
expect(result.error).to.eql(`Variant Analysis has failed: ${mockFailedApiResponse.failure_reason}`);
expect(variantAnalysis.status).to.equal(VariantAnalysisStatus.Failed);
expect(variantAnalysis.failureReason).to.equal(processFailureReason(mockFailedApiResponse.failure_reason as VariantAnalysisFailureReason));
expect(result.variantAnalysis?.status).to.equal(VariantAnalysisStatus.Failed);
expect(result.variantAnalysis?.failureReason).to.equal(processFailureReason(mockFailedApiResponse.failure_reason as VariantAnalysisFailureReason));
});
});
@@ -115,7 +117,7 @@ describe('Variant Analysis Monitor', async function() {
});
it('should succeed and return a list of scanned repo ids', async () => {
const result = await variantAnalysisMonitor.monitorVariantAnalysis(variantAnalysis, cancellationToken);
const result = await variantAnalysisMonitor.monitorVariantAnalysis(variantAnalysis, cancellationTokenSource.token);
const scannedRepoIds = scannedRepos.filter(r => r.analysis_status == 'succeeded').map(r => r.repository.id);
expect(result.status).to.equal('CompletedSuccessfully');
@@ -133,7 +135,7 @@ describe('Variant Analysis Monitor', async function() {
});
it('should succeed and return an empty list of scanned repo ids', async () => {
const result = await variantAnalysisMonitor.monitorVariantAnalysis(variantAnalysis, cancellationToken);
const result = await variantAnalysisMonitor.monitorVariantAnalysis(variantAnalysis, cancellationTokenSource.token);
expect(result.status).to.equal('CompletedSuccessfully');
expect(result.scannedReposDownloaded).to.eql([]);
@@ -148,7 +150,7 @@ describe('Variant Analysis Monitor', async function() {
});
it('should succeed and return an empty list of scanned repo ids', async () => {
const result = await variantAnalysisMonitor.monitorVariantAnalysis(variantAnalysis, cancellationToken);
const result = await variantAnalysisMonitor.monitorVariantAnalysis(variantAnalysis, cancellationTokenSource.token);
expect(result.status).to.equal('CompletedSuccessfully');
expect(result.scannedReposDownloaded).to.eql([]);

View File

@@ -25,8 +25,8 @@ describe('Variant Analysis processor', function() {
const { access_mismatch_repos, no_codeql_db_repos, not_found_repo_nwos, over_limit_repos } = skippedRepos;
expect(result).to.eql({
'id': 123,
'controllerRepoId': 456,
'id': mockApiResponse.id,
'controllerRepoId': mockApiResponse.controller_repo.id,
'query': {
'filePath': 'query-file-path',
'language': VariantAnalysisQueryLanguage.Javascript,
@@ -36,7 +36,7 @@ describe('Variant Analysis processor', function() {
'repositories': ['1', '2', '3'],
},
'status': 'succeeded',
'actionsWorkflowRunId': 456,
'actionsWorkflowRunId': mockApiResponse.actions_workflow_run_id,
'scannedRepos': [
transformScannedRepo(VariantAnalysisRepoStatus.Succeeded, scannedRepos[0]),
transformScannedRepo(VariantAnalysisRepoStatus.Pending, scannedRepos[1]),

View File

@@ -1,3 +1,4 @@
import { faker } from '@faker-js/faker';
import {
VariantAnalysis as VariantAnalysisApiResponse,
VariantAnalysisScannedRepository,
@@ -15,19 +16,20 @@ export function createMockApiResponse(
scannedRepos: VariantAnalysisScannedRepository[] = createMockScannedRepos(),
skippedRepos: VariantAnalysisSkippedRepositories = createMockSkippedRepos()
): VariantAnalysisApiResponse {
const variantAnalysis: VariantAnalysisApiResponse = {
id: 123,
id: faker.datatype.number(),
controller_repo: {
id: 456,
id: faker.datatype.number(),
name: 'pickles',
full_name: 'github/pickles',
private: false,
},
actor_id: 123,
actor_id: faker.datatype.number(),
query_language: VariantAnalysisQueryLanguage.Javascript,
query_pack_url: 'https://example.com/foo',
status: status,
actions_workflow_run_id: 456,
actions_workflow_run_id: faker.datatype.number(),
scanned_repositories: scannedRepos,
skipped_repositories: skippedRepos
};

View File

@@ -0,0 +1,19 @@
import { faker } from '@faker-js/faker';
import { VariantAnalysisRepoTask } from '../../../../remote-queries/gh-api/variant-analysis';
import { VariantAnalysisRepoStatus } from '../../../../remote-queries/shared/variant-analysis';
export function createMockVariantAnalysisRepoTask(): VariantAnalysisRepoTask {
return {
repository: {
id: faker.datatype.number(),
name: faker.random.word(),
full_name: 'github/' + faker.random.word(),
private: false,
},
analysis_status: VariantAnalysisRepoStatus.Succeeded,
result_count: faker.datatype.number(),
artifact_size_in_bytes: faker.datatype.number(),
artifact_url: 'https://www.pickles.com'
};
}

View File

@@ -0,0 +1,33 @@
import { faker } from '@faker-js/faker';
import {
VariantAnalysisRepoStatus,
VariantAnalysisScannedRepository
} from '../../../../remote-queries/shared/variant-analysis';
export function createMockScannedRepo(
name: string,
isPrivate: boolean,
analysisStatus: VariantAnalysisRepoStatus,
): VariantAnalysisScannedRepository {
return {
repository: {
id: faker.datatype.number(),
fullName: 'github/' + name,
private: isPrivate,
},
analysisStatus: analysisStatus,
resultCount: faker.datatype.number(),
artifactSizeInBytes: faker.datatype.number()
};
}
export function createMockScannedRepos(
statuses: VariantAnalysisRepoStatus[] = [
VariantAnalysisRepoStatus.Succeeded,
VariantAnalysisRepoStatus.Pending,
VariantAnalysisRepoStatus.InProgress,
]
): VariantAnalysisScannedRepository[] {
return statuses.map(status => createMockScannedRepo(`mona-${status}`, false, status));
}

View File

@@ -0,0 +1,44 @@
import { faker } from '@faker-js/faker';
import {
VariantAnalysisSkippedRepositories,
VariantAnalysisSkippedRepositoryGroup
} from '../../../../remote-queries/shared/variant-analysis';
export function createMockSkippedRepos(): VariantAnalysisSkippedRepositories {
return {
accessMismatchRepos: createMockSkippedRepoGroup(),
noCodeqlDbRepos: createMockSkippedRepoGroup(),
notFoundRepos: createMockNotFoundRepoGroup(),
overLimitRepos: createMockSkippedRepoGroup()
};
}
export function createMockSkippedRepoGroup(): VariantAnalysisSkippedRepositoryGroup {
return {
repositoryCount: 2,
repositories: [
{
id: faker.datatype.number(),
fullName: 'github/' + faker.random.word(),
},
{
id: faker.datatype.number(),
fullName: 'github/' + faker.random.word(),
}
]
};
}
export function createMockNotFoundRepoGroup(): VariantAnalysisSkippedRepositoryGroup {
return {
repositoryCount: 2,
repositories: [
{
fullName: 'github/' + faker.random.word(),
},
{
fullName: 'github/' + faker.random.word(),
}
]
};
}

View File

@@ -1,9 +1,10 @@
import { faker } from '@faker-js/faker';
import { VariantAnalysisQueryLanguage, VariantAnalysisSubmission } from '../../../../remote-queries/shared/variant-analysis';
export function createMockSubmission(): VariantAnalysisSubmission {
return {
startTime: 1234,
controllerRepoId: 5678,
startTime: faker.datatype.number(),
controllerRepoId: faker.datatype.number(),
actionRepoRef: 'repo-ref',
query: {
name: 'query-name',

View File

@@ -0,0 +1,35 @@
import { faker } from '@faker-js/faker';
import {
VariantAnalysis,
VariantAnalysisQueryLanguage,
VariantAnalysisScannedRepository,
VariantAnalysisSkippedRepositories,
VariantAnalysisStatus,
} from '../../../../remote-queries/shared/variant-analysis';
import { createMockScannedRepos } from './scanned-repositories';
import { createMockSkippedRepos } from './skipped-repositories';
export function createMockVariantAnalysis(
status: VariantAnalysisStatus = VariantAnalysisStatus.InProgress,
scannedRepos: VariantAnalysisScannedRepository[] = createMockScannedRepos(),
skippedRepos: VariantAnalysisSkippedRepositories = createMockSkippedRepos()
): VariantAnalysis {
const variantAnalysis: VariantAnalysis = {
id: faker.datatype.number(),
controllerRepoId: faker.datatype.number(),
query: {
name: 'a-query-name',
filePath: 'a-query-file-path',
language: VariantAnalysisQueryLanguage.Javascript
},
databases: {
repositories: ['1', '2', '3'],
},
status: status,
actionsWorkflowRunId: faker.datatype.number(),
scannedRepos: scannedRepos,
skippedRepos: skippedRepos
};
return variantAnalysis;
}