Merge pull request #1716 from github/koesie10/use-shared-types-in-variant-analysis

Remove `gh-api` usage from variant analysis code
This commit is contained in:
Koen Vlaswinkel
2022-11-04 17:07:54 +01:00
committed by GitHub
11 changed files with 222 additions and 107 deletions

View File

@@ -109,11 +109,7 @@ import { NewQueryRunner } from './query-server/query-runner';
import { QueryRunner } from './queryRunner';
import { VariantAnalysisView } from './remote-queries/variant-analysis-view';
import { VariantAnalysisViewSerializer } from './remote-queries/variant-analysis-view-serializer';
import { VariantAnalysis } from './remote-queries/shared/variant-analysis';
import {
VariantAnalysis as VariantAnalysisApiResponse,
VariantAnalysisScannedRepository as ApiVariantAnalysisScannedRepository
} from './remote-queries/gh-api/variant-analysis';
import { VariantAnalysis, VariantAnalysisScannedRepository } from './remote-queries/shared/variant-analysis';
import { VariantAnalysisManager } from './remote-queries/variant-analysis-manager';
import { createVariantAnalysisContentProvider } from './remote-queries/variant-analysis-content-provider';
import { VSCodeMockGitHubApiServer } from './mocks/vscode-mock-gh-api-server';
@@ -949,8 +945,8 @@ async function activateWithInstalledDistribution(
ctx.subscriptions.push(
commandRunner('codeQL.autoDownloadVariantAnalysisResult', async (
scannedRepo: ApiVariantAnalysisScannedRepository,
variantAnalysisSummary: VariantAnalysisApiResponse,
scannedRepo: VariantAnalysisScannedRepository,
variantAnalysisSummary: VariantAnalysis,
token: CancellationToken
) => {
await variantAnalysisManager.enqueueDownload(scannedRepo, variantAnalysisSummary, token);

View File

@@ -76,6 +76,17 @@ export interface VariantAnalysisScannedRepository {
failureMessage?: string
}
export interface VariantAnalysisRepositoryTask {
repository: Repository,
analysisStatus: VariantAnalysisRepoStatus,
resultCount?: number,
artifactSizeInBytes?: number,
failureMessage?: string,
databaseCommitSha?: string,
sourceLocationPrefix?: string,
artifactUrl?: string,
}
export interface VariantAnalysisSkippedRepositories {
accessMismatchRepos?: VariantAnalysisSkippedRepositoryGroup,
notFoundRepos?: VariantAnalysisSkippedRepositoryGroup,

View File

@@ -5,14 +5,11 @@ import { CancellationToken, commands, EventEmitter, ExtensionContext, window } f
import { DisposableObject } from '../pure/disposable-object';
import { Credentials } from '../authentication';
import { VariantAnalysisMonitor } from './variant-analysis-monitor';
import {
VariantAnalysis as VariantAnalysisApiResponse,
VariantAnalysisRepoTask,
VariantAnalysisScannedRepository as ApiVariantAnalysisScannedRepository
} from './gh-api/variant-analysis';
import {
isVariantAnalysisComplete,
VariantAnalysis, VariantAnalysisQueryLanguage,
VariantAnalysis,
VariantAnalysisQueryLanguage,
VariantAnalysisRepositoryTask,
VariantAnalysisScannedRepository,
VariantAnalysisScannedRepositoryDownloadStatus,
VariantAnalysisScannedRepositoryResult,
@@ -23,7 +20,7 @@ import { VariantAnalysisView } from './variant-analysis-view';
import { VariantAnalysisViewManager } from './variant-analysis-view-manager';
import { VariantAnalysisResultsManager } from './variant-analysis-results-manager';
import { getControllerRepo } from './run-remote-query';
import { processUpdatedVariantAnalysis } from './variant-analysis-processor';
import { processUpdatedVariantAnalysis, processVariantAnalysisRepositoryTask } from './variant-analysis-processor';
import PQueue from 'p-queue';
import { createTimestampFile, showAndLogErrorMessage } from '../helpers';
import * as fs from 'fs-extra';
@@ -179,8 +176,8 @@ export class VariantAnalysisManager extends DisposableObject implements VariantA
}
public async autoDownloadVariantAnalysisResult(
scannedRepo: ApiVariantAnalysisScannedRepository,
variantAnalysisSummary: VariantAnalysisApiResponse,
scannedRepo: VariantAnalysisScannedRepository,
variantAnalysis: VariantAnalysis,
cancellationToken: CancellationToken
): Promise<void> {
const repoState = {
@@ -188,48 +185,50 @@ export class VariantAnalysisManager extends DisposableObject implements VariantA
downloadStatus: VariantAnalysisScannedRepositoryDownloadStatus.Pending,
};
await this.onRepoStateUpdated(variantAnalysisSummary.id, repoState);
await this.onRepoStateUpdated(variantAnalysis.id, repoState);
const credentials = await Credentials.initialize(this.ctx);
if (!credentials) { throw Error('Error authenticating with GitHub'); }
if (cancellationToken && cancellationToken.isCancellationRequested) {
repoState.downloadStatus = VariantAnalysisScannedRepositoryDownloadStatus.Failed;
await this.onRepoStateUpdated(variantAnalysisSummary.id, repoState);
await this.onRepoStateUpdated(variantAnalysis.id, repoState);
return;
}
let repoTask: VariantAnalysisRepoTask;
let repoTask: VariantAnalysisRepositoryTask;
try {
repoTask = await ghApiClient.getVariantAnalysisRepo(
const repoTaskResponse = await ghApiClient.getVariantAnalysisRepo(
credentials,
variantAnalysisSummary.controller_repo.id,
variantAnalysisSummary.id,
variantAnalysis.controllerRepo.id,
variantAnalysis.id,
scannedRepo.repository.id
);
repoTask = processVariantAnalysisRepositoryTask(repoTaskResponse);
} catch (e) {
repoState.downloadStatus = VariantAnalysisScannedRepositoryDownloadStatus.Failed;
await this.onRepoStateUpdated(variantAnalysisSummary.id, repoState);
throw new Error(`Could not download the results for variant analysis with id: ${variantAnalysisSummary.id}. Error: ${getErrorMessage(e)}`);
await this.onRepoStateUpdated(variantAnalysis.id, repoState);
throw new Error(`Could not download the results for variant analysis with id: ${variantAnalysis.id}. Error: ${getErrorMessage(e)}`);
}
if (repoTask.artifact_url) {
if (repoTask.artifactUrl) {
repoState.downloadStatus = VariantAnalysisScannedRepositoryDownloadStatus.InProgress;
await this.onRepoStateUpdated(variantAnalysisSummary.id, repoState);
await this.onRepoStateUpdated(variantAnalysis.id, repoState);
await this.variantAnalysisResultsManager.download(credentials, variantAnalysisSummary.id, repoTask, this.getVariantAnalysisStorageLocation(variantAnalysisSummary.id));
await this.variantAnalysisResultsManager.download(credentials, variantAnalysis.id, repoTask, this.getVariantAnalysisStorageLocation(variantAnalysis.id));
}
repoState.downloadStatus = VariantAnalysisScannedRepositoryDownloadStatus.Succeeded;
await this.onRepoStateUpdated(variantAnalysisSummary.id, repoState);
await this.onRepoStateUpdated(variantAnalysis.id, repoState);
}
public async enqueueDownload(
scannedRepo: ApiVariantAnalysisScannedRepository,
variantAnalysisSummary: VariantAnalysisApiResponse,
scannedRepo: VariantAnalysisScannedRepository,
variantAnalysis: VariantAnalysis,
token: CancellationToken
): Promise<void> {
await this.queue.add(() => this.autoDownloadVariantAnalysisResult(scannedRepo, variantAnalysisSummary, token));
await this.queue.add(() => this.autoDownloadVariantAnalysisResult(scannedRepo, variantAnalysis, token));
}
public downloadsQueueSize(): number {

View File

@@ -1,12 +1,13 @@
import { ExtensionContext, CancellationToken, commands, EventEmitter } from 'vscode';
import { CancellationToken, commands, EventEmitter, ExtensionContext } from 'vscode';
import { Credentials } from '../authentication';
import * as ghApiClient from './gh-api/gh-api-client';
import { isFinalVariantAnalysisStatus, VariantAnalysis } from './shared/variant-analysis';
import {
VariantAnalysis as VariantAnalysisApiResponse,
isFinalVariantAnalysisStatus,
VariantAnalysis,
VariantAnalysisRepoStatus,
VariantAnalysisScannedRepository
} from './gh-api/variant-analysis';
} from './shared/variant-analysis';
import { VariantAnalysisMonitorResult } from './shared/variant-analysis-monitor-result';
import { processUpdatedVariantAnalysis } from './variant-analysis-processor';
import { DisposableObject } from '../pure/disposable-object';
@@ -57,7 +58,7 @@ export class VariantAnalysisMonitor extends DisposableObject {
this._onVariantAnalysisChange.fire(variantAnalysis);
const downloadedRepos = this.downloadVariantAnalysisResults(variantAnalysisSummary, scannedReposDownloaded);
const downloadedRepos = this.downloadVariantAnalysisResults(variantAnalysis, scannedReposDownloaded);
scannedReposDownloaded.push(...downloadedRepos);
if (isFinalVariantAnalysisStatus(variantAnalysis.status) || variantAnalysis.failureReason) {
@@ -72,7 +73,7 @@ export class VariantAnalysisMonitor extends DisposableObject {
private scheduleForDownload(
scannedRepo: VariantAnalysisScannedRepository,
variantAnalysisSummary: VariantAnalysisApiResponse
variantAnalysisSummary: VariantAnalysis
) {
void commands.executeCommand('codeQL.autoDownloadVariantAnalysisResult', scannedRepo, variantAnalysisSummary);
}
@@ -81,22 +82,22 @@ export class VariantAnalysisMonitor extends DisposableObject {
scannedRepo: VariantAnalysisScannedRepository,
alreadyDownloaded: number[]
): boolean {
return !alreadyDownloaded.includes(scannedRepo.repository.id) && scannedRepo.analysis_status === 'succeeded';
return !alreadyDownloaded.includes(scannedRepo.repository.id) && scannedRepo.analysisStatus === VariantAnalysisRepoStatus.Succeeded;
}
private getReposToDownload(
variantAnalysisSummary: VariantAnalysisApiResponse,
variantAnalysisSummary: VariantAnalysis,
alreadyDownloaded: number[]
): VariantAnalysisScannedRepository[] {
if (variantAnalysisSummary.scanned_repositories) {
return variantAnalysisSummary.scanned_repositories.filter(scannedRepo => this.shouldDownload(scannedRepo, alreadyDownloaded));
if (variantAnalysisSummary.scannedRepos) {
return variantAnalysisSummary.scannedRepos.filter(scannedRepo => this.shouldDownload(scannedRepo, alreadyDownloaded));
} else {
return [];
}
}
private downloadVariantAnalysisResults(
variantAnalysisSummary: VariantAnalysisApiResponse,
variantAnalysisSummary: VariantAnalysis,
scannedReposDownloaded: number[]
): number[] {
const repoResultsToDownload = this.getReposToDownload(variantAnalysisSummary, scannedReposDownloaded);

View File

@@ -6,7 +6,8 @@ import {
VariantAnalysisFailureReason as ApiVariantAnalysisFailureReason,
VariantAnalysisStatus as ApiVariantAnalysisStatus,
VariantAnalysisSkippedRepositoryGroup as ApiVariantAnalysisSkippedRepositoryGroup,
VariantAnalysisNotFoundRepositoryGroup as ApiVariantAnalysisNotFoundRepositoryGroup
VariantAnalysisNotFoundRepositoryGroup as ApiVariantAnalysisNotFoundRepositoryGroup,
VariantAnalysisRepoTask as ApiVariantAnalysisRepoTask,
} from './gh-api/variant-analysis';
import {
VariantAnalysis,
@@ -16,7 +17,8 @@ import {
VariantAnalysisStatus,
VariantAnalysisRepoStatus,
VariantAnalysisSubmission,
VariantAnalysisSkippedRepositoryGroup
VariantAnalysisSkippedRepositoryGroup,
VariantAnalysisRepositoryTask
} from './shared/variant-analysis';
export function processVariantAnalysis(
@@ -76,24 +78,47 @@ export function processUpdatedVariantAnalysis(
return variantAnalysis;
}
export function processVariantAnalysisRepositoryTask(
response: ApiVariantAnalysisRepoTask
): VariantAnalysisRepositoryTask {
return {
repository: {
id: response.repository.id,
fullName: response.repository.full_name,
private: response.repository.private,
},
analysisStatus: processApiRepoStatus(response.analysis_status),
resultCount: response.result_count,
artifactSizeInBytes: response.artifact_size_in_bytes,
failureMessage: response.failure_message,
databaseCommitSha: response.database_commit_sha,
sourceLocationPrefix: response.source_location_prefix,
artifactUrl: response.artifact_url,
};
}
export function processScannedRepository(
scannedRepo: ApiVariantAnalysisScannedRepository
): VariantAnalysisScannedRepository {
return {
repository: {
id: scannedRepo.repository.id,
fullName: scannedRepo.repository.full_name,
private: scannedRepo.repository.private,
stargazersCount: scannedRepo.repository.stargazers_count,
updatedAt: scannedRepo.repository.updated_at,
},
analysisStatus: processApiRepoStatus(scannedRepo.analysis_status),
resultCount: scannedRepo.result_count,
artifactSizeInBytes: scannedRepo.artifact_size_in_bytes,
failureMessage: scannedRepo.failure_message
};
}
function processScannedRepositories(
scannedRepos: ApiVariantAnalysisScannedRepository[]
): VariantAnalysisScannedRepository[] {
return scannedRepos.map(scannedRepo => {
return {
repository: {
id: scannedRepo.repository.id,
fullName: scannedRepo.repository.full_name,
private: scannedRepo.repository.private,
stargazersCount: scannedRepo.repository.stargazers_count,
updatedAt: scannedRepo.repository.updated_at,
},
analysisStatus: processApiRepoStatus(scannedRepo.analysis_status),
resultCount: scannedRepo.result_count,
artifactSizeInBytes: scannedRepo.artifact_size_in_bytes,
failureMessage: scannedRepo.failure_message
};
});
return scannedRepos.map(scannedRepo => processScannedRepository(scannedRepo));
}
function processSkippedRepositories(

View File

@@ -9,9 +9,12 @@ import { sarifParser } from '../sarif-parser';
import { extractAnalysisAlerts } from './sarif-processing';
import { CodeQLCliServer } from '../cli';
import { extractRawResults } from './bqrs-processing';
import { VariantAnalysis, VariantAnalysisScannedRepositoryResult } from './shared/variant-analysis';
import {
VariantAnalysis,
VariantAnalysisRepositoryTask,
VariantAnalysisScannedRepositoryResult
} from './shared/variant-analysis';
import { DisposableObject, DisposeHandler } from '../pure/disposable-object';
import { VariantAnalysisRepoTask } from './gh-api/variant-analysis';
import * as ghApiClient from './gh-api/gh-api-client';
import { EventEmitter } from 'vscode';
import { unzipFile } from '../pure/zip';
@@ -22,7 +25,7 @@ const createCacheKey = (variantAnalysisId: number, repositoryFullName: string):
export type ResultDownloadedEvent = {
variantAnalysisId: number;
repoTask: VariantAnalysisRepoTask;
repoTask: VariantAnalysisRepositoryTask;
}
export class VariantAnalysisResultsManager extends DisposableObject {
@@ -48,18 +51,18 @@ export class VariantAnalysisResultsManager extends DisposableObject {
public async download(
credentials: Credentials,
variantAnalysisId: number,
repoTask: VariantAnalysisRepoTask,
repoTask: VariantAnalysisRepositoryTask,
variantAnalysisStoragePath: string,
): Promise<void> {
if (!repoTask.artifact_url) {
if (!repoTask.artifactUrl) {
throw new Error('Missing artifact URL');
}
const resultDirectory = this.getRepoStorageDirectory(variantAnalysisStoragePath, repoTask.repository.full_name);
const resultDirectory = this.getRepoStorageDirectory(variantAnalysisStoragePath, repoTask.repository.fullName);
const result = await ghApiClient.getVariantAnalysisRepoResult(
credentials,
repoTask.artifact_url
repoTask.artifactUrl
);
if (!(await fs.pathExists(resultDirectory))) {
@@ -112,13 +115,13 @@ export class VariantAnalysisResultsManager extends DisposableObject {
const storageDirectory = this.getRepoStorageDirectory(variantAnalysisStoragePath, repositoryFullName);
const repoTask: VariantAnalysisRepoTask = await fs.readJson(path.join(storageDirectory, VariantAnalysisResultsManager.REPO_TASK_FILENAME));
const repoTask: VariantAnalysisRepositoryTask = await fs.readJson(path.join(storageDirectory, VariantAnalysisResultsManager.REPO_TASK_FILENAME));
if (!repoTask.database_commit_sha || !repoTask.source_location_prefix) {
if (!repoTask.databaseCommitSha || !repoTask.sourceLocationPrefix) {
throw new Error('Missing database commit SHA');
}
const fileLinkPrefix = this.createGitHubDotcomFileLinkPrefix(repoTask.repository.full_name, repoTask.database_commit_sha);
const fileLinkPrefix = this.createGitHubDotcomFileLinkPrefix(repoTask.repository.fullName, repoTask.databaseCommitSha);
const resultsDirectory = path.join(storageDirectory, VariantAnalysisResultsManager.RESULTS_DIRECTORY);
const sarifPath = path.join(resultsDirectory, 'results.sarif');
@@ -134,7 +137,7 @@ export class VariantAnalysisResultsManager extends DisposableObject {
}
if (await fs.pathExists(bqrsPath)) {
const rawResults = await this.readBqrsResults(bqrsPath, fileLinkPrefix, repoTask.source_location_prefix);
const rawResults = await this.readBqrsResults(bqrsPath, fileLinkPrefix, repoTask.sourceLocationPrefix);
return {
variantAnalysisId,

View File

@@ -10,29 +10,28 @@ import * as fs from 'fs-extra';
import * as path from 'path';
import { VariantAnalysisManager } from '../../../remote-queries/variant-analysis-manager';
import {
VariantAnalysis as VariantAnalysisApiResponse,
VariantAnalysisRepoTask,
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';
import { CodeQLCliServer } from '../../../cli';
import { storagePath } from '../global.helper';
import { VariantAnalysisResultsManager } from '../../../remote-queries/variant-analysis-results-manager';
import { createMockVariantAnalysis } from '../../factories/remote-queries/shared/variant-analysis';
import { VariantAnalysis } from '../../../remote-queries/shared/variant-analysis';
import * as VariantAnalysisModule from '../../../remote-queries/shared/variant-analysis';
import { createMockScannedRepos } from '../../factories/remote-queries/shared/scanned-repositories';
import {
VariantAnalysis,
VariantAnalysisScannedRepository,
VariantAnalysisStatus,
} from '../../../remote-queries/shared/variant-analysis';
import { createTimestampFile } from '../../../helpers';
import { createMockVariantAnalysisRepoTask } from '../../factories/remote-queries/gh-api/variant-analysis-repo-task';
import { VariantAnalysisRepoTask } from '../../../remote-queries/gh-api/variant-analysis';
describe('Variant Analysis Manager', async function() {
let sandbox: sinon.SinonSandbox;
let cli: CodeQLCliServer;
let cancellationTokenSource: CancellationTokenSource;
let variantAnalysisManager: VariantAnalysisManager;
let variantAnalysisApiResponse: VariantAnalysisApiResponse;
let scannedRepos: ApiVariantAnalysisScannedRepository[];
let variantAnalysis: VariantAnalysis;
let scannedRepos: VariantAnalysisScannedRepository[];
let getVariantAnalysisRepoStub: sinon.SinonStub;
let getVariantAnalysisRepoResultStub: sinon.SinonStub;
let variantAnalysisResultsManager: VariantAnalysisResultsManager;
@@ -47,7 +46,10 @@ describe('Variant Analysis Manager', async function() {
cancellationTokenSource = new CancellationTokenSource();
scannedRepos = createMockScannedRepos();
variantAnalysisApiResponse = createMockApiResponse('in_progress', scannedRepos);
variantAnalysis = createMockVariantAnalysis({
status: VariantAnalysisStatus.InProgress,
scannedRepos,
});
try {
const extension = await extensions.getExtension<CodeQLExtensionInterface | Record<string, never>>('GitHub.vscode-codeql')!.activate();
@@ -70,7 +72,7 @@ describe('Variant Analysis Manager', async function() {
try {
await variantAnalysisManager.autoDownloadVariantAnalysisResult(
scannedRepos[0],
variantAnalysisApiResponse,
variantAnalysis,
cancellationTokenSource.token
);
} catch (error: any) {
@@ -107,7 +109,7 @@ describe('Variant Analysis Manager', async function() {
it('should not try to download the result', async () => {
await variantAnalysisManager.autoDownloadVariantAnalysisResult(
scannedRepos[0],
variantAnalysisApiResponse,
variantAnalysis,
cancellationTokenSource.token
);
@@ -131,7 +133,7 @@ describe('Variant Analysis Manager', async function() {
await variantAnalysisManager.autoDownloadVariantAnalysisResult(
scannedRepos[0],
variantAnalysisApiResponse,
variantAnalysis,
cancellationTokenSource.token
);
@@ -141,7 +143,7 @@ describe('Variant Analysis Manager', async function() {
it('should fetch a repo task', async () => {
await variantAnalysisManager.autoDownloadVariantAnalysisResult(
scannedRepos[0],
variantAnalysisApiResponse,
variantAnalysis,
cancellationTokenSource.token
);
@@ -151,7 +153,7 @@ describe('Variant Analysis Manager', async function() {
it('should fetch a repo result', async () => {
await variantAnalysisManager.autoDownloadVariantAnalysisResult(
scannedRepos[0],
variantAnalysisApiResponse,
variantAnalysis,
cancellationTokenSource.token
);
@@ -163,9 +165,9 @@ describe('Variant Analysis Manager', async function() {
it('should pop download tasks off the queue', async () => {
const getResultsSpy = sandbox.spy(variantAnalysisManager, 'autoDownloadVariantAnalysisResult');
await variantAnalysisManager.enqueueDownload(scannedRepos[0], variantAnalysisApiResponse, cancellationTokenSource.token);
await variantAnalysisManager.enqueueDownload(scannedRepos[1], variantAnalysisApiResponse, cancellationTokenSource.token);
await variantAnalysisManager.enqueueDownload(scannedRepos[2], variantAnalysisApiResponse, cancellationTokenSource.token);
await variantAnalysisManager.enqueueDownload(scannedRepos[0], variantAnalysis, cancellationTokenSource.token);
await variantAnalysisManager.enqueueDownload(scannedRepos[1], variantAnalysis, cancellationTokenSource.token);
await variantAnalysisManager.enqueueDownload(scannedRepos[2], variantAnalysis, cancellationTokenSource.token);
expect(variantAnalysisManager.downloadsQueueSize()).to.equal(0);
expect(getResultsSpy).to.have.been.calledThrice;

View File

@@ -14,7 +14,11 @@ import {
import { createFailedMockApiResponse, createMockApiResponse } from '../../factories/remote-queries/gh-api/variant-analysis-api-response';
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 {
processFailureReason,
processScannedRepository,
processUpdatedVariantAnalysis,
} from '../../../remote-queries/variant-analysis-processor';
import { Credentials } from '../../../authentication';
import { createMockVariantAnalysis } from '../../factories/remote-queries/shared/variant-analysis';
import { VariantAnalysisManager } from '../../../remote-queries/variant-analysis-manager';
@@ -143,8 +147,8 @@ describe('Variant Analysis Monitor', async function() {
succeededRepos.forEach((succeededRepo, index) => {
expect(commandSpy.getCall(index).args[0]).to.eq('codeQL.autoDownloadVariantAnalysisResult');
expect(commandSpy.getCall(index).args[1]).to.eq(succeededRepo);
expect(commandSpy.getCall(index).args[2]).to.eq(mockApiResponse);
expect(commandSpy.getCall(index).args[1]).to.deep.eq(processScannedRepository(succeededRepo));
expect(commandSpy.getCall(index).args[2]).to.deep.eq(processUpdatedVariantAnalysis(variantAnalysis, mockApiResponse));
});
});
@@ -154,8 +158,8 @@ describe('Variant Analysis Monitor', async function() {
expect(mockGetDownloadResult).to.have.callCount(succeededRepos.length);
succeededRepos.forEach((succeededRepo, index) => {
expect(mockGetDownloadResult.getCall(index).args[0]).to.eq(succeededRepo);
expect(mockGetDownloadResult.getCall(index).args[1]).to.eq(mockApiResponse);
expect(mockGetDownloadResult.getCall(index).args[0]).to.deep.eq(processScannedRepository(succeededRepo));
expect(mockGetDownloadResult.getCall(index).args[1]).to.deep.eq(processUpdatedVariantAnalysis(variantAnalysis, mockApiResponse));
});
});
});

View File

@@ -8,11 +8,14 @@ import * as fs from 'fs-extra';
import * as path from 'path';
import { VariantAnalysisResultsManager } from '../../../remote-queries/variant-analysis-results-manager';
import { createMockVariantAnalysisRepoTask } from '../../factories/remote-queries/gh-api/variant-analysis-repo-task';
import { CodeQLCliServer } from '../../../cli';
import { storagePath } from '../global.helper';
import { faker } from '@faker-js/faker';
import * as ghApiClient from '../../../remote-queries/gh-api/gh-api-client';
import {
createMockVariantAnalysisRepositoryTask
} from '../../factories/remote-queries/shared/variant-analysis-repo-tasks';
import { VariantAnalysisRepositoryTask } from '../../../remote-queries/shared/variant-analysis';
describe(VariantAnalysisResultsManager.name, function() {
this.timeout(10000);
@@ -51,15 +54,15 @@ describe(VariantAnalysisResultsManager.name, function() {
request: getOctokitStub
})
} as unknown as Credentials;
let dummyRepoTask = createMockVariantAnalysisRepoTask();
let dummyRepoTask: VariantAnalysisRepositoryTask;
let variantAnalysisStoragePath: string;
let repoTaskStorageDirectory: string;
beforeEach(async () => {
dummyRepoTask = createMockVariantAnalysisRepoTask();
dummyRepoTask = createMockVariantAnalysisRepositoryTask();
variantAnalysisStoragePath = path.join(storagePath, variantAnalysisId.toString());
repoTaskStorageDirectory = variantAnalysisResultsManager.getRepoStorageDirectory(variantAnalysisStoragePath, dummyRepoTask.repository.full_name);
repoTaskStorageDirectory = variantAnalysisResultsManager.getRepoStorageDirectory(variantAnalysisStoragePath, dummyRepoTask.repository.fullName);
});
afterEach(async () => {
@@ -70,14 +73,14 @@ describe(VariantAnalysisResultsManager.name, function() {
describe('isVariantAnalysisRepoDownloaded', () => {
it('should return false when no results are downloaded', async () => {
expect(await variantAnalysisResultsManager.isVariantAnalysisRepoDownloaded(variantAnalysisStoragePath, dummyRepoTask.repository.full_name)).to.equal(false);
expect(await variantAnalysisResultsManager.isVariantAnalysisRepoDownloaded(variantAnalysisStoragePath, dummyRepoTask.repository.fullName)).to.equal(false);
});
});
describe('when the artifact_url is missing', async () => {
it('should not try to download the result', async () => {
const dummyRepoTask = createMockVariantAnalysisRepoTask();
delete dummyRepoTask.artifact_url;
const dummyRepoTask = createMockVariantAnalysisRepositoryTask();
delete dummyRepoTask.artifactUrl;
try {
await variantAnalysisResultsManager.download(
@@ -103,7 +106,7 @@ describe(VariantAnalysisResultsManager.name, function() {
getVariantAnalysisRepoResultStub = sandbox
.stub(ghApiClient, 'getVariantAnalysisRepoResult')
.withArgs(mockCredentials, dummyRepoTask.artifact_url as string)
.withArgs(mockCredentials, dummyRepoTask.artifactUrl as string)
.resolves(arrayBuffer);
});
@@ -149,7 +152,7 @@ describe(VariantAnalysisResultsManager.name, function() {
variantAnalysisStoragePath
);
expect(await variantAnalysisResultsManager.isVariantAnalysisRepoDownloaded(variantAnalysisStoragePath, dummyRepoTask.repository.full_name)).to.equal(true);
expect(await variantAnalysisResultsManager.isVariantAnalysisRepoDownloaded(variantAnalysisStoragePath, dummyRepoTask.repository.fullName)).to.equal(true);
});
});
});

View File

@@ -0,0 +1,19 @@
import { faker } from '@faker-js/faker';
import {
VariantAnalysisRepositoryTask,
VariantAnalysisRepoStatus,
} from '../../../../remote-queries/shared/variant-analysis';
import { createMockRepositoryWithMetadata } from './repository';
export function createMockVariantAnalysisRepositoryTask(data?: Partial<VariantAnalysisRepositoryTask>): VariantAnalysisRepositoryTask {
return {
repository: createMockRepositoryWithMetadata(),
analysisStatus: VariantAnalysisRepoStatus.Pending,
resultCount: faker.datatype.number(),
artifactSizeInBytes: faker.datatype.number(),
databaseCommitSha: faker.git.commitSha(),
sourceLocationPrefix: faker.system.filePath(),
artifactUrl: faker.internet.url(),
...data,
};
}

View File

@@ -1,4 +1,5 @@
import { expect } from 'chai';
import { faker } from '@faker-js/faker';
import {
VariantAnalysisScannedRepository as ApiVariantAnalysisScannedRepository
} from '../../../src/remote-queries/gh-api/variant-analysis';
@@ -7,8 +8,15 @@ import {
VariantAnalysisScannedRepository,
VariantAnalysisRepoStatus
} from '../../../src/remote-queries/shared/variant-analysis';
import { processVariantAnalysis } from '../../../src/remote-queries/variant-analysis-processor';
import { createMockScannedRepos } from '../../../src/vscode-tests/factories/remote-queries/gh-api/scanned-repositories';
import {
processScannedRepository,
processVariantAnalysis,
processVariantAnalysisRepositoryTask
} from '../../../src/remote-queries/variant-analysis-processor';
import {
createMockScannedRepo,
createMockScannedRepos
} from '../../../src/vscode-tests/factories/remote-queries/gh-api/scanned-repositories';
import { createMockSkippedRepos } from '../../../src/vscode-tests/factories/remote-queries/gh-api/skipped-repositories';
import {
createMockApiResponse
@@ -16,8 +24,11 @@ import {
import {
createMockSubmission
} from '../../../src/vscode-tests/factories/remote-queries/shared/variant-analysis-submission';
import {
createMockVariantAnalysisRepoTask
} from '../../../src/vscode-tests/factories/remote-queries/gh-api/variant-analysis-repo-task';
describe('Variant Analysis processor', function() {
describe(processVariantAnalysis.name, function() {
const scannedRepos = createMockScannedRepos();
const skippedRepos = createMockSkippedRepos();
const mockApiResponse = createMockApiResponse('completed', scannedRepos, skippedRepos);
@@ -147,3 +158,44 @@ describe('Variant Analysis processor', function() {
};
}
});
describe(processVariantAnalysisRepositoryTask.name, () => {
const mockApiResponse = createMockVariantAnalysisRepoTask();
it('should return the correct result', () => {
expect(processVariantAnalysisRepositoryTask(mockApiResponse)).to.deep.eq({
repository: {
id: mockApiResponse.repository.id,
fullName: mockApiResponse.repository.full_name,
private: mockApiResponse.repository.private,
},
analysisStatus: 'succeeded',
resultCount: mockApiResponse.result_count,
artifactSizeInBytes: mockApiResponse.artifact_size_in_bytes,
failureMessage: mockApiResponse.failure_message,
databaseCommitSha: mockApiResponse.database_commit_sha,
sourceLocationPrefix: mockApiResponse.source_location_prefix,
artifactUrl: mockApiResponse.artifact_url,
});
});
});
describe(processScannedRepository.name, () => {
const mockApiResponse = createMockScannedRepo(faker.random.word(), faker.datatype.boolean(), VariantAnalysisRepoStatus.Pending);
it('should return the correct result', () => {
expect(processScannedRepository(mockApiResponse)).to.deep.eq({
repository: {
id: mockApiResponse.repository.id,
fullName: mockApiResponse.repository.full_name,
private: mockApiResponse.repository.private,
stargazersCount: mockApiResponse.repository.stargazers_count,
updatedAt: mockApiResponse.repository.updated_at,
},
analysisStatus: 'pending',
resultCount: mockApiResponse.result_count,
artifactSizeInBytes: mockApiResponse.artifact_size_in_bytes,
failureMessage: mockApiResponse.failure_message,
});
});
});