Merge remote-tracking branch 'origin/main' into koesie10/add-metadata-to-repo-row
This commit is contained in:
@@ -1,6 +1,4 @@
|
||||
{
|
||||
"exit": true,
|
||||
"require": [
|
||||
"test/mocha.setup.js"
|
||||
]
|
||||
"require": ["test/mocha.setup.js"]
|
||||
}
|
||||
|
||||
@@ -1256,9 +1256,11 @@
|
||||
"test": "npm-run-all -p test:*",
|
||||
"test:unit": "mocha --config .mocharc.json test/pure-tests/**/*.ts",
|
||||
"test:view": "jest",
|
||||
"preintegration": "rm -rf ./out/vscode-tests && gulp",
|
||||
"integration": "node ./out/vscode-tests/run-integration-tests.js no-workspace,minimal-workspace",
|
||||
"cli-integration": "npm run preintegration && node ./out/vscode-tests/run-integration-tests.js cli-integration",
|
||||
"integration-setup": "rm -rf ./out/vscode-tests && gulp",
|
||||
"integration": "npm run integration-setup && node ./out/vscode-tests/run-integration-tests.js no-workspace,minimal-workspace",
|
||||
"integration:no-workspace": "npm run integration-setup && node ./out/vscode-tests/run-integration-tests.js no-workspace",
|
||||
"integration:minimal-workspace": "npm run integration-setup && node ./out/vscode-tests/run-integration-tests.js minimal-workspace",
|
||||
"cli-integration": "npm run integration-setup && node ./out/vscode-tests/run-integration-tests.js cli-integration",
|
||||
"update-vscode": "node ./node_modules/vscode/bin/install",
|
||||
"format": "tsfmt -r && eslint . --ext .ts,.tsx --fix",
|
||||
"lint": "eslint . --ext .ts,.tsx --max-warnings=0",
|
||||
|
||||
@@ -525,9 +525,6 @@ async function activateWithInstalledDistribution(
|
||||
ctx.subscriptions.push(logScannerService);
|
||||
ctx.subscriptions.push(logScannerService.scanners.registerLogScannerProvider(new JoinOrderScannerProvider(() => joinOrderWarningThreshold())));
|
||||
|
||||
void logger.log('Reading query history');
|
||||
await qhm.readQueryHistory();
|
||||
|
||||
void logger.log('Initializing compare view.');
|
||||
const compareView = new CompareView(
|
||||
ctx,
|
||||
@@ -1229,6 +1226,9 @@ async function activateWithInstalledDistribution(
|
||||
|
||||
await commands.executeCommand('codeQLDatabases.removeOrphanedDatabases');
|
||||
|
||||
void logger.log('Reading query history');
|
||||
await qhm.readQueryHistory();
|
||||
|
||||
void logger.log('Successfully finished extension initialization.');
|
||||
|
||||
return {
|
||||
|
||||
@@ -7,6 +7,7 @@ import { RemoteQueryHistoryItem } from './remote-queries/remote-query-history-it
|
||||
import { VariantAnalysisHistoryItem } from './remote-queries/variant-analysis-history-item';
|
||||
import { assertNever } from './pure/helpers-pure';
|
||||
import { pluralize } from './pure/word';
|
||||
import { humanizeQueryStatus } from './query-status';
|
||||
|
||||
interface InterpolateReplacements {
|
||||
t: string; // Start time
|
||||
@@ -86,7 +87,7 @@ export class HistoryItemLabelProvider {
|
||||
q: `${item.remoteQuery.queryName} (${item.remoteQuery.language})`,
|
||||
d: buildRepoLabel(item),
|
||||
r: resultCount,
|
||||
s: item.status,
|
||||
s: humanizeQueryStatus(item.status),
|
||||
f: path.basename(item.remoteQuery.queryFilePath),
|
||||
'%': '%'
|
||||
};
|
||||
@@ -99,7 +100,7 @@ export class HistoryItemLabelProvider {
|
||||
q: `${item.variantAnalysis.query.name} (${item.variantAnalysis.query.language})`,
|
||||
d: buildRepoLabel(item),
|
||||
r: resultCount,
|
||||
s: item.status,
|
||||
s: humanizeQueryStatus(item.status),
|
||||
f: path.basename(item.variantAnalysis.query.filePath),
|
||||
'%': '%',
|
||||
};
|
||||
|
||||
@@ -966,7 +966,7 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"not_found_repo_nwos": {
|
||||
"not_found_repos": {
|
||||
"repository_count": 110,
|
||||
"repository_full_names": [
|
||||
"evanw/node-source-map-support",
|
||||
|
||||
@@ -966,7 +966,7 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"not_found_repo_nwos": {
|
||||
"not_found_repos": {
|
||||
"repository_count": 110,
|
||||
"repository_full_names": [
|
||||
"evanw/node-source-map-support",
|
||||
|
||||
@@ -966,7 +966,7 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"not_found_repo_nwos": {
|
||||
"not_found_repos": {
|
||||
"repository_count": 110,
|
||||
"repository_full_names": [
|
||||
"evanw/node-source-map-support",
|
||||
|
||||
@@ -966,7 +966,7 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"not_found_repo_nwos": {
|
||||
"not_found_repos": {
|
||||
"repository_count": 110,
|
||||
"repository_full_names": [
|
||||
"evanw/node-source-map-support",
|
||||
|
||||
@@ -966,7 +966,7 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"not_found_repo_nwos": {
|
||||
"not_found_repos": {
|
||||
"repository_count": 110,
|
||||
"repository_full_names": [
|
||||
"evanw/node-source-map-support",
|
||||
|
||||
@@ -970,7 +970,7 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"not_found_repo_nwos": {
|
||||
"not_found_repos": {
|
||||
"repository_count": 110,
|
||||
"repository_full_names": [
|
||||
"evanw/node-source-map-support",
|
||||
|
||||
@@ -970,7 +970,7 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"not_found_repo_nwos": {
|
||||
"not_found_repos": {
|
||||
"repository_count": 110,
|
||||
"repository_full_names": [
|
||||
"evanw/node-source-map-support",
|
||||
|
||||
@@ -962,7 +962,7 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"not_found_repo_nwos": {
|
||||
"not_found_repos": {
|
||||
"repository_count": 110,
|
||||
"repository_full_names": [
|
||||
"evanw/node-source-map-support",
|
||||
|
||||
@@ -970,7 +970,7 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"not_found_repo_nwos": {
|
||||
"not_found_repos": {
|
||||
"repository_count": 110,
|
||||
"repository_full_names": [
|
||||
"evanw/node-source-map-support",
|
||||
|
||||
@@ -970,7 +970,7 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"not_found_repo_nwos": {
|
||||
"not_found_repos": {
|
||||
"repository_count": 110,
|
||||
"repository_full_names": [
|
||||
"evanw/node-source-map-support",
|
||||
|
||||
@@ -970,7 +970,7 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"not_found_repo_nwos": {
|
||||
"not_found_repos": {
|
||||
"repository_count": 110,
|
||||
"repository_full_names": [
|
||||
"evanw/node-source-map-support",
|
||||
|
||||
@@ -970,7 +970,7 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"not_found_repo_nwos": {
|
||||
"not_found_repos": {
|
||||
"repository_count": 110,
|
||||
"repository_full_names": [
|
||||
"evanw/node-source-map-support",
|
||||
|
||||
@@ -970,7 +970,7 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"not_found_repo_nwos": {
|
||||
"not_found_repos": {
|
||||
"repository_count": 110,
|
||||
"repository_full_names": [
|
||||
"evanw/node-source-map-support",
|
||||
|
||||
@@ -970,7 +970,7 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"not_found_repo_nwos": {
|
||||
"not_found_repos": {
|
||||
"repository_count": 110,
|
||||
"repository_full_names": [
|
||||
"evanw/node-source-map-support",
|
||||
|
||||
@@ -970,7 +970,7 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"not_found_repo_nwos": {
|
||||
"not_found_repos": {
|
||||
"repository_count": 110,
|
||||
"repository_full_names": [
|
||||
"evanw/node-source-map-support",
|
||||
|
||||
@@ -970,7 +970,7 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"not_found_repo_nwos": {
|
||||
"not_found_repos": {
|
||||
"repository_count": 110,
|
||||
"repository_full_names": [
|
||||
"evanw/node-source-map-support",
|
||||
|
||||
@@ -962,7 +962,7 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"not_found_repo_nwos": {
|
||||
"not_found_repos": {
|
||||
"repository_count": 110,
|
||||
"repository_full_names": [
|
||||
"evanw/node-source-map-support",
|
||||
|
||||
@@ -970,7 +970,7 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"not_found_repo_nwos": {
|
||||
"not_found_repos": {
|
||||
"repository_count": 110,
|
||||
"repository_full_names": [
|
||||
"evanw/node-source-map-support",
|
||||
|
||||
@@ -970,7 +970,7 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"not_found_repo_nwos": {
|
||||
"not_found_repos": {
|
||||
"repository_count": 110,
|
||||
"repository_full_names": [
|
||||
"evanw/node-source-map-support",
|
||||
|
||||
@@ -970,7 +970,7 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"not_found_repo_nwos": {
|
||||
"not_found_repos": {
|
||||
"repository_count": 110,
|
||||
"repository_full_names": [
|
||||
"evanw/node-source-map-support",
|
||||
|
||||
@@ -970,7 +970,7 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"not_found_repo_nwos": {
|
||||
"not_found_repos": {
|
||||
"repository_count": 110,
|
||||
"repository_full_names": [
|
||||
"evanw/node-source-map-support",
|
||||
|
||||
@@ -970,7 +970,7 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"not_found_repo_nwos": {
|
||||
"not_found_repos": {
|
||||
"repository_count": 110,
|
||||
"repository_full_names": [
|
||||
"evanw/node-source-map-support",
|
||||
|
||||
@@ -970,7 +970,7 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"not_found_repo_nwos": {
|
||||
"not_found_repos": {
|
||||
"repository_count": 110,
|
||||
"repository_full_names": [
|
||||
"evanw/node-source-map-support",
|
||||
|
||||
@@ -970,7 +970,7 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"not_found_repo_nwos": {
|
||||
"not_found_repos": {
|
||||
"repository_count": 110,
|
||||
"repository_full_names": [
|
||||
"evanw/node-source-map-support",
|
||||
|
||||
@@ -970,7 +970,7 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"not_found_repo_nwos": {
|
||||
"not_found_repos": {
|
||||
"repository_count": 110,
|
||||
"repository_full_names": [
|
||||
"evanw/node-source-map-support",
|
||||
|
||||
@@ -962,7 +962,7 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"not_found_repo_nwos": {
|
||||
"not_found_repos": {
|
||||
"repository_count": 110,
|
||||
"repository_full_names": [
|
||||
"evanw/node-source-map-support",
|
||||
|
||||
@@ -970,7 +970,7 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"not_found_repo_nwos": {
|
||||
"not_found_repos": {
|
||||
"repository_count": 110,
|
||||
"repository_full_names": [
|
||||
"evanw/node-source-map-support",
|
||||
|
||||
@@ -970,7 +970,7 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"not_found_repo_nwos": {
|
||||
"not_found_repos": {
|
||||
"repository_count": 110,
|
||||
"repository_full_names": [
|
||||
"evanw/node-source-map-support",
|
||||
|
||||
@@ -970,7 +970,7 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"not_found_repo_nwos": {
|
||||
"not_found_repos": {
|
||||
"repository_count": 110,
|
||||
"repository_full_names": [
|
||||
"evanw/node-source-map-support",
|
||||
|
||||
@@ -970,7 +970,7 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"not_found_repo_nwos": {
|
||||
"not_found_repos": {
|
||||
"repository_count": 110,
|
||||
"repository_full_names": [
|
||||
"evanw/node-source-map-support",
|
||||
|
||||
@@ -972,7 +972,7 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"not_found_repo_nwos": {
|
||||
"not_found_repos": {
|
||||
"repository_count": 110,
|
||||
"repository_full_names": [
|
||||
"evanw/node-source-map-support",
|
||||
|
||||
@@ -972,7 +972,7 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"not_found_repo_nwos": {
|
||||
"not_found_repos": {
|
||||
"repository_count": 110,
|
||||
"repository_full_names": [
|
||||
"evanw/node-source-map-support",
|
||||
|
||||
@@ -972,7 +972,7 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"not_found_repo_nwos": {
|
||||
"not_found_repos": {
|
||||
"repository_count": 110,
|
||||
"repository_full_names": [
|
||||
"evanw/node-source-map-support",
|
||||
|
||||
@@ -972,7 +972,7 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"not_found_repo_nwos": {
|
||||
"not_found_repos": {
|
||||
"repository_count": 110,
|
||||
"repository_full_names": [
|
||||
"evanw/node-source-map-support",
|
||||
|
||||
@@ -962,7 +962,7 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"not_found_repo_nwos": {
|
||||
"not_found_repos": {
|
||||
"repository_count": 110,
|
||||
"repository_full_names": [
|
||||
"evanw/node-source-map-support",
|
||||
|
||||
@@ -972,7 +972,7 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"not_found_repo_nwos": {
|
||||
"not_found_repos": {
|
||||
"repository_count": 110,
|
||||
"repository_full_names": [
|
||||
"evanw/node-source-map-support",
|
||||
|
||||
@@ -973,7 +973,7 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"not_found_repo_nwos": {
|
||||
"not_found_repos": {
|
||||
"repository_count": 110,
|
||||
"repository_full_names": [
|
||||
"evanw/node-source-map-support",
|
||||
|
||||
@@ -962,7 +962,7 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"not_found_repo_nwos": {
|
||||
"not_found_repos": {
|
||||
"repository_count": 110,
|
||||
"repository_full_names": [
|
||||
"evanw/node-source-map-support",
|
||||
|
||||
@@ -962,7 +962,7 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"not_found_repo_nwos": {
|
||||
"not_found_repos": {
|
||||
"repository_count": 110,
|
||||
"repository_full_names": [
|
||||
"evanw/node-source-map-support",
|
||||
|
||||
@@ -966,7 +966,7 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"not_found_repo_nwos": {
|
||||
"not_found_repos": {
|
||||
"repository_count": 110,
|
||||
"repository_full_names": [
|
||||
"evanw/node-source-map-support",
|
||||
|
||||
@@ -90,3 +90,7 @@ function createFormatter(unit: string) {
|
||||
unitDisplay: 'long'
|
||||
});
|
||||
}
|
||||
|
||||
export async function sleep(ms: number) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
@@ -694,7 +694,7 @@ export class QueryHistoryManager extends DisposableObject {
|
||||
await this.remoteQueriesManager.rehydrateRemoteQuery(item.queryId, item.remoteQuery, item.status);
|
||||
}
|
||||
if (item.t === 'variant-analysis') {
|
||||
await this.variantAnalysisManager.rehydrateVariantAnalysis(item.variantAnalysis, item.status);
|
||||
await this.variantAnalysisManager.rehydrateVariantAnalysis(item.variantAnalysis);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -21,3 +21,16 @@ export function variantAnalysisStatusToQueryStatus(status: VariantAnalysisStatus
|
||||
assertNever(status);
|
||||
}
|
||||
}
|
||||
|
||||
export function humanizeQueryStatus(status: QueryStatus): string {
|
||||
switch (status) {
|
||||
case QueryStatus.InProgress:
|
||||
return 'in progress';
|
||||
case QueryStatus.Completed:
|
||||
return 'completed';
|
||||
case QueryStatus.Failed:
|
||||
return 'failed';
|
||||
default:
|
||||
return 'unknown';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ export interface VariantAnalysisRepoTask {
|
||||
|
||||
export interface VariantAnalysisSkippedRepositories {
|
||||
access_mismatch_repos?: VariantAnalysisSkippedRepositoryGroup,
|
||||
not_found_repo_nwos?: VariantAnalysisNotFoundRepositoryGroup,
|
||||
not_found_repos?: VariantAnalysisNotFoundRepositoryGroup,
|
||||
no_codeql_db_repos?: VariantAnalysisSkippedRepositoryGroup,
|
||||
over_limit_repos?: VariantAnalysisSkippedRepositoryGroup
|
||||
}
|
||||
|
||||
@@ -205,6 +205,7 @@ function generateMarkdownForPathResults(
|
||||
const stepCount = codeFlow.threadFlows.length;
|
||||
const title = `Path with ${stepCount} steps`;
|
||||
for (let i = 0; i < stepCount; i++) {
|
||||
const listNumber = i + 1;
|
||||
const threadFlow = codeFlow.threadFlows[i];
|
||||
const link = createMarkdownRemoteFileRef(
|
||||
threadFlow.fileLink,
|
||||
@@ -217,8 +218,9 @@ function generateMarkdownForPathResults(
|
||||
threadFlow.highlightedRegion
|
||||
);
|
||||
// Indent the snippet to fit with the numbered list.
|
||||
const codeSnippetIndented = codeSnippet.map((line) => ` ${line}`);
|
||||
pathLines.push(`${i + 1}. ${link}`, ...codeSnippetIndented);
|
||||
// The indentation is "n + 2" where the list number is an n-digit number.
|
||||
const codeSnippetIndented = codeSnippet.map(line => ' '.repeat(listNumber.toString().length + 2) + line);
|
||||
pathLines.push(`${listNumber}. ${link}`, ...codeSnippetIndented);
|
||||
}
|
||||
lines.push(
|
||||
...buildExpandableMarkdownSection(title, pathLines)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import * as vscode from 'vscode';
|
||||
import { Credentials } from '../authentication';
|
||||
import { Logger } from '../logging';
|
||||
import { sleep } from '../pure/time';
|
||||
import { getWorkflowStatus, isArtifactAvailable, RESULT_INDEX_ARTIFACT_NAME } from './gh-api/gh-actions-api-client';
|
||||
import { RemoteQuery } from './remote-query';
|
||||
import { RemoteQueryWorkflowResult } from './remote-query-workflow-result';
|
||||
@@ -30,7 +31,7 @@ export class RemoteQueriesMonitor {
|
||||
let attemptCount = 0;
|
||||
|
||||
while (attemptCount <= RemoteQueriesMonitor.maxAttemptCount) {
|
||||
await this.sleep(RemoteQueriesMonitor.sleepTime);
|
||||
await sleep(RemoteQueriesMonitor.sleepTime);
|
||||
|
||||
if (cancellationToken && cancellationToken.isCancellationRequested) {
|
||||
return { status: 'Cancelled' };
|
||||
@@ -70,10 +71,6 @@ export class RemoteQueriesMonitor {
|
||||
void this.logger.log('Variant analysis monitoring timed out after 2 days');
|
||||
return { status: 'Cancelled' };
|
||||
}
|
||||
|
||||
private async sleep(ms: number) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,16 +1,11 @@
|
||||
import { VariantAnalysis } from './variant-analysis';
|
||||
|
||||
export type VariantAnalysisMonitorStatus =
|
||||
| 'InProgress'
|
||||
| 'CompletedSuccessfully'
|
||||
| 'CompletedUnsuccessfully'
|
||||
| 'Failed'
|
||||
| 'Cancelled'
|
||||
| 'TimedOut';
|
||||
| 'Completed'
|
||||
| 'Canceled';
|
||||
|
||||
export interface VariantAnalysisMonitorResult {
|
||||
status: VariantAnalysisMonitorStatus;
|
||||
error?: string;
|
||||
scannedReposDownloaded?: number[],
|
||||
variantAnalysis?: VariantAnalysis
|
||||
}
|
||||
|
||||
@@ -47,6 +47,13 @@ export enum VariantAnalysisStatus {
|
||||
Canceled = 'canceled',
|
||||
}
|
||||
|
||||
export function isFinalVariantAnalysisStatus(status: VariantAnalysisStatus): boolean {
|
||||
return [
|
||||
// All states that indicates the analysis has completed and cannot change status anymore.
|
||||
VariantAnalysisStatus.Succeeded, VariantAnalysisStatus.Failed, VariantAnalysisStatus.Canceled,
|
||||
].includes(status);
|
||||
}
|
||||
|
||||
export enum VariantAnalysisFailureReason {
|
||||
NoReposQueried = 'noReposQueried',
|
||||
InternalError = 'internalError',
|
||||
@@ -132,6 +139,26 @@ export interface VariantAnalysisSubmission {
|
||||
}
|
||||
}
|
||||
|
||||
export async function isVariantAnalysisComplete(
|
||||
variantAnalysis: VariantAnalysis,
|
||||
artifactDownloaded: (repo: VariantAnalysisScannedRepository) => Promise<boolean>
|
||||
): Promise<boolean> {
|
||||
// It's only acceptable to have no scanned repos if the variant analysis is not in a final state.
|
||||
// Otherwise it means the analysis hit some kind of internal error or there were no repos to scan.
|
||||
if (variantAnalysis.scannedRepos === undefined || variantAnalysis.scannedRepos.length === 0) {
|
||||
return variantAnalysis.status !== VariantAnalysisStatus.InProgress;
|
||||
}
|
||||
|
||||
return (await Promise.all(variantAnalysis.scannedRepos.map(repo => isVariantAnalysisRepoComplete(repo, artifactDownloaded)))).every(x => x);
|
||||
}
|
||||
|
||||
async function isVariantAnalysisRepoComplete(
|
||||
repo: VariantAnalysisScannedRepository,
|
||||
artifactDownloaded: (repo: VariantAnalysisScannedRepository) => Promise<boolean>
|
||||
): Promise<boolean> {
|
||||
return hasRepoScanCompleted(repo) && (!repoHasDownloadableArtifact(repo) || await artifactDownloaded(repo));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param status
|
||||
* @returns whether the status is in a completed state, i.e. it cannot normally change state anymore
|
||||
@@ -153,6 +180,14 @@ export function hasRepoScanCompleted(repo: VariantAnalysisScannedRepository): bo
|
||||
return isCompletedAnalysisRepoStatus(repo.analysisStatus);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param repo
|
||||
* @returns whether the repo scan has an artifact that can be downloaded
|
||||
*/
|
||||
export function repoHasDownloadableArtifact(repo: VariantAnalysisScannedRepository): boolean {
|
||||
return repo.analysisStatus === VariantAnalysisRepoStatus.Succeeded;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param repos
|
||||
* @returns the total number of results. Will be `undefined` when there are no repos with results.
|
||||
|
||||
@@ -11,7 +11,9 @@ import {
|
||||
VariantAnalysisScannedRepository as ApiVariantAnalysisScannedRepository
|
||||
} from './gh-api/variant-analysis';
|
||||
import {
|
||||
isVariantAnalysisComplete,
|
||||
VariantAnalysis, VariantAnalysisQueryLanguage,
|
||||
VariantAnalysisScannedRepository,
|
||||
VariantAnalysisScannedRepositoryDownloadStatus,
|
||||
VariantAnalysisScannedRepositoryResult,
|
||||
VariantAnalysisScannedRepositoryState
|
||||
@@ -24,7 +26,6 @@ import { getControllerRepo } from './run-remote-query';
|
||||
import { processUpdatedVariantAnalysis } from './variant-analysis-processor';
|
||||
import PQueue from 'p-queue';
|
||||
import { createTimestampFile, showAndLogErrorMessage } from '../helpers';
|
||||
import { QueryStatus } from '../query-status';
|
||||
import * as fs from 'fs-extra';
|
||||
|
||||
export class VariantAnalysisManager extends DisposableObject implements VariantAnalysisViewManager<VariantAnalysisView> {
|
||||
@@ -55,21 +56,24 @@ export class VariantAnalysisManager extends DisposableObject implements VariantA
|
||||
this.variantAnalysisResultsManager.onResultLoaded(this.onRepoResultLoaded.bind(this));
|
||||
}
|
||||
|
||||
public async rehydrateVariantAnalysis(variantAnalysis: VariantAnalysis, status: QueryStatus) {
|
||||
public async rehydrateVariantAnalysis(variantAnalysis: VariantAnalysis) {
|
||||
if (!(await this.variantAnalysisRecordExists(variantAnalysis.id))) {
|
||||
// In this case, the variant analysis was deleted from disk, most likely because
|
||||
// it was purged by another workspace.
|
||||
this._onVariantAnalysisRemoved.fire(variantAnalysis);
|
||||
} else {
|
||||
await this.setVariantAnalysis(variantAnalysis);
|
||||
if (status === QueryStatus.InProgress) {
|
||||
// In this case, last time we checked, the query was still in progress.
|
||||
// We need to setup the monitor to check for completion.
|
||||
await commands.executeCommand('codeQL.monitorVariantAnalysis', variantAnalysis);
|
||||
if (!await isVariantAnalysisComplete(variantAnalysis, this.makeResultDownloadChecker(variantAnalysis))) {
|
||||
void commands.executeCommand('codeQL.monitorVariantAnalysis', variantAnalysis);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private makeResultDownloadChecker(variantAnalysis: VariantAnalysis): (repo: VariantAnalysisScannedRepository) => Promise<boolean> {
|
||||
const storageLocation = this.getVariantAnalysisStorageLocation(variantAnalysis.id);
|
||||
return (repo) => this.variantAnalysisResultsManager.isVariantAnalysisRepoDownloaded(storageLocation, repo.repository.fullName);
|
||||
}
|
||||
|
||||
public async removeVariantAnalysis(variantAnalysis: VariantAnalysis) {
|
||||
this.variantAnalysisResultsManager.removeAnalysisResults(variantAnalysis);
|
||||
await this.removeStorageDirectory(variantAnalysis.id);
|
||||
|
||||
@@ -2,14 +2,15 @@ import { ExtensionContext, CancellationToken, commands, EventEmitter } from 'vsc
|
||||
import { Credentials } from '../authentication';
|
||||
import * as ghApiClient from './gh-api/gh-api-client';
|
||||
|
||||
import { VariantAnalysis, VariantAnalysisStatus } from './shared/variant-analysis';
|
||||
import { isFinalVariantAnalysisStatus, VariantAnalysis } from './shared/variant-analysis';
|
||||
import {
|
||||
VariantAnalysis as VariantAnalysisApiResponse,
|
||||
VariantAnalysisScannedRepository
|
||||
} from './gh-api/variant-analysis';
|
||||
import { VariantAnalysisMonitorResult } from './shared/variant-analysis-monitor-result';
|
||||
import { processFailureReason, processUpdatedVariantAnalysis } from './variant-analysis-processor';
|
||||
import { processUpdatedVariantAnalysis } from './variant-analysis-processor';
|
||||
import { DisposableObject } from '../pure/disposable-object';
|
||||
import { sleep } from '../pure/time';
|
||||
|
||||
export class VariantAnalysisMonitor extends DisposableObject {
|
||||
// With a sleep of 5 seconds, the maximum number of attempts takes
|
||||
@@ -36,38 +37,22 @@ export class VariantAnalysisMonitor extends DisposableObject {
|
||||
throw Error('Error authenticating with GitHub');
|
||||
}
|
||||
|
||||
let variantAnalysisSummary: VariantAnalysisApiResponse;
|
||||
let attemptCount = 0;
|
||||
const scannedReposDownloaded: number[] = [];
|
||||
|
||||
this._onVariantAnalysisChange.fire(variantAnalysis);
|
||||
|
||||
while (attemptCount <= VariantAnalysisMonitor.maxAttemptCount) {
|
||||
await this.sleep(VariantAnalysisMonitor.sleepTime);
|
||||
await sleep(VariantAnalysisMonitor.sleepTime);
|
||||
|
||||
if (cancellationToken && cancellationToken.isCancellationRequested) {
|
||||
return { status: 'Cancelled', error: 'Variant Analysis was canceled.' };
|
||||
return { status: 'Canceled' };
|
||||
}
|
||||
|
||||
variantAnalysisSummary = await ghApiClient.getVariantAnalysis(
|
||||
const variantAnalysisSummary = await ghApiClient.getVariantAnalysis(
|
||||
credentials,
|
||||
variantAnalysis.controllerRepo.id,
|
||||
variantAnalysis.id
|
||||
);
|
||||
|
||||
if (variantAnalysisSummary.failure_reason) {
|
||||
variantAnalysis.status = VariantAnalysisStatus.Failed;
|
||||
variantAnalysis.failureReason = processFailureReason(variantAnalysisSummary.failure_reason);
|
||||
|
||||
this._onVariantAnalysisChange.fire(variantAnalysis);
|
||||
|
||||
return {
|
||||
status: 'Failed',
|
||||
error: `Variant Analysis has failed: ${variantAnalysisSummary.failure_reason}`,
|
||||
variantAnalysis: variantAnalysis
|
||||
};
|
||||
}
|
||||
|
||||
variantAnalysis = processUpdatedVariantAnalysis(variantAnalysis, variantAnalysisSummary);
|
||||
|
||||
this._onVariantAnalysisChange.fire(variantAnalysis);
|
||||
@@ -75,14 +60,14 @@ export class VariantAnalysisMonitor extends DisposableObject {
|
||||
const downloadedRepos = this.downloadVariantAnalysisResults(variantAnalysisSummary, scannedReposDownloaded);
|
||||
scannedReposDownloaded.push(...downloadedRepos);
|
||||
|
||||
if (variantAnalysisSummary.status === 'completed') {
|
||||
if (isFinalVariantAnalysisStatus(variantAnalysis.status) || variantAnalysis.failureReason) {
|
||||
break;
|
||||
}
|
||||
|
||||
attemptCount++;
|
||||
}
|
||||
|
||||
return { status: 'CompletedSuccessfully', scannedReposDownloaded: scannedReposDownloaded };
|
||||
return { status: 'Completed', scannedReposDownloaded, variantAnalysis };
|
||||
}
|
||||
|
||||
private scheduleForDownload(
|
||||
@@ -124,8 +109,4 @@ export class VariantAnalysisMonitor extends DisposableObject {
|
||||
|
||||
return downloadedRepos;
|
||||
}
|
||||
|
||||
private async sleep(ms: number) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ export function processUpdatedVariantAnalysis(
|
||||
executionStartTime: previousVariantAnalysis.executionStartTime,
|
||||
createdAt: response.created_at,
|
||||
updatedAt: response.updated_at,
|
||||
status: processApiStatus(response.status),
|
||||
status: processApiStatus(response.status, response.failure_reason),
|
||||
completedAt: response.completed_at,
|
||||
actionsWorkflowRunId: response.actions_workflow_run_id,
|
||||
scannedRepos: scannedRepos,
|
||||
@@ -102,7 +102,7 @@ function processSkippedRepositories(
|
||||
|
||||
return {
|
||||
accessMismatchRepos: processRepoGroup(skippedRepos.access_mismatch_repos),
|
||||
notFoundRepos: processNotFoundRepoGroup(skippedRepos.not_found_repo_nwos),
|
||||
notFoundRepos: processNotFoundRepoGroup(skippedRepos.not_found_repos),
|
||||
noCodeqlDbRepos: processRepoGroup(skippedRepos.no_codeql_db_repos),
|
||||
overLimitRepos: processRepoGroup(skippedRepos.over_limit_repos)
|
||||
};
|
||||
@@ -163,12 +163,13 @@ function processApiRepoStatus(analysisStatus: ApiVariantAnalysisRepoStatus): Var
|
||||
}
|
||||
}
|
||||
|
||||
function processApiStatus(status: ApiVariantAnalysisStatus): VariantAnalysisStatus {
|
||||
switch (status) {
|
||||
case 'in_progress':
|
||||
return VariantAnalysisStatus.InProgress;
|
||||
case 'completed':
|
||||
return VariantAnalysisStatus.Succeeded;
|
||||
function processApiStatus(status: ApiVariantAnalysisStatus, failureReason: string | undefined): VariantAnalysisStatus {
|
||||
if (status === 'in_progress') {
|
||||
return VariantAnalysisStatus.InProgress;
|
||||
} else if (failureReason !== undefined) {
|
||||
return VariantAnalysisStatus.Failed;
|
||||
} else {
|
||||
return VariantAnalysisStatus.Succeeded;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -146,7 +146,7 @@ export class VariantAnalysisResultsManager extends DisposableObject {
|
||||
throw new Error('Missing results file');
|
||||
}
|
||||
|
||||
private async isVariantAnalysisRepoDownloaded(
|
||||
public async isVariantAnalysisRepoDownloaded(
|
||||
variantAnalysisStoragePath: string,
|
||||
repositoryFullName: string,
|
||||
): Promise<boolean> {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import * as sinon from 'sinon';
|
||||
import { expect } from 'chai';
|
||||
import { CancellationTokenSource, extensions } from 'vscode';
|
||||
import { CancellationTokenSource, commands, extensions } from 'vscode';
|
||||
import { CodeQLExtensionInterface } from '../../../extension';
|
||||
import { logger } from '../../../logging';
|
||||
import * as config from '../../../config';
|
||||
@@ -21,15 +21,17 @@ import { createMockVariantAnalysisRepoTask } from '../../factories/remote-querie
|
||||
import { CodeQLCliServer } from '../../../cli';
|
||||
import { storagePath } from '../global.helper';
|
||||
import { VariantAnalysisResultsManager } from '../../../remote-queries/variant-analysis-results-manager';
|
||||
import { VariantAnalysis } from '../../../remote-queries/shared/variant-analysis';
|
||||
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 { createTimestampFile } from '../../../helpers';
|
||||
|
||||
describe('Variant Analysis Manager', async function() {
|
||||
let sandbox: sinon.SinonSandbox;
|
||||
let cli: CodeQLCliServer;
|
||||
let cancellationTokenSource: CancellationTokenSource;
|
||||
let variantAnalysisManager: VariantAnalysisManager;
|
||||
let variantAnalysis: VariantAnalysisApiResponse;
|
||||
let variantAnalysisApiResponse: VariantAnalysisApiResponse;
|
||||
let scannedRepos: ApiVariantAnalysisScannedRepository[];
|
||||
let getVariantAnalysisRepoStub: sinon.SinonStub;
|
||||
let getVariantAnalysisRepoResultStub: sinon.SinonStub;
|
||||
@@ -45,7 +47,7 @@ describe('Variant Analysis Manager', async function() {
|
||||
cancellationTokenSource = new CancellationTokenSource();
|
||||
|
||||
scannedRepos = createMockScannedRepos();
|
||||
variantAnalysis = createMockApiResponse('in_progress', scannedRepos);
|
||||
variantAnalysisApiResponse = createMockApiResponse('in_progress', scannedRepos);
|
||||
|
||||
try {
|
||||
const extension = await extensions.getExtension<CodeQLExtensionInterface | Record<string, never>>('GitHub.vscode-codeql')!.activate();
|
||||
@@ -68,7 +70,7 @@ describe('Variant Analysis Manager', async function() {
|
||||
try {
|
||||
await variantAnalysisManager.autoDownloadVariantAnalysisResult(
|
||||
scannedRepos[0],
|
||||
variantAnalysis,
|
||||
variantAnalysisApiResponse,
|
||||
cancellationTokenSource.token
|
||||
);
|
||||
} catch (error: any) {
|
||||
@@ -105,7 +107,7 @@ describe('Variant Analysis Manager', async function() {
|
||||
it('should not try to download the result', async () => {
|
||||
await variantAnalysisManager.autoDownloadVariantAnalysisResult(
|
||||
scannedRepos[0],
|
||||
variantAnalysis,
|
||||
variantAnalysisApiResponse,
|
||||
cancellationTokenSource.token
|
||||
);
|
||||
|
||||
@@ -129,7 +131,7 @@ describe('Variant Analysis Manager', async function() {
|
||||
|
||||
await variantAnalysisManager.autoDownloadVariantAnalysisResult(
|
||||
scannedRepos[0],
|
||||
variantAnalysis,
|
||||
variantAnalysisApiResponse,
|
||||
cancellationTokenSource.token
|
||||
);
|
||||
|
||||
@@ -139,7 +141,7 @@ describe('Variant Analysis Manager', async function() {
|
||||
it('should fetch a repo task', async () => {
|
||||
await variantAnalysisManager.autoDownloadVariantAnalysisResult(
|
||||
scannedRepos[0],
|
||||
variantAnalysis,
|
||||
variantAnalysisApiResponse,
|
||||
cancellationTokenSource.token
|
||||
);
|
||||
|
||||
@@ -149,7 +151,7 @@ describe('Variant Analysis Manager', async function() {
|
||||
it('should fetch a repo result', async () => {
|
||||
await variantAnalysisManager.autoDownloadVariantAnalysisResult(
|
||||
scannedRepos[0],
|
||||
variantAnalysis,
|
||||
variantAnalysisApiResponse,
|
||||
cancellationTokenSource.token
|
||||
);
|
||||
|
||||
@@ -161,9 +163,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], variantAnalysis, cancellationTokenSource.token);
|
||||
await variantAnalysisManager.enqueueDownload(scannedRepos[1], variantAnalysis, cancellationTokenSource.token);
|
||||
await variantAnalysisManager.enqueueDownload(scannedRepos[2], variantAnalysis, cancellationTokenSource.token);
|
||||
await variantAnalysisManager.enqueueDownload(scannedRepos[0], variantAnalysisApiResponse, cancellationTokenSource.token);
|
||||
await variantAnalysisManager.enqueueDownload(scannedRepos[1], variantAnalysisApiResponse, cancellationTokenSource.token);
|
||||
await variantAnalysisManager.enqueueDownload(scannedRepos[2], variantAnalysisApiResponse, cancellationTokenSource.token);
|
||||
|
||||
expect(variantAnalysisManager.downloadsQueueSize()).to.equal(0);
|
||||
expect(getResultsSpy).to.have.been.calledThrice;
|
||||
@@ -194,4 +196,77 @@ describe('Variant Analysis Manager', async function() {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when rehydrating a query', async () => {
|
||||
let variantAnalysis: VariantAnalysis;
|
||||
let variantAnalysisRemovedSpy: sinon.SinonSpy;
|
||||
let monitorVariantAnalysisCommandSpy: sinon.SinonSpy;
|
||||
|
||||
beforeEach(() => {
|
||||
variantAnalysis = createMockVariantAnalysis();
|
||||
|
||||
variantAnalysisRemovedSpy = sinon.spy();
|
||||
variantAnalysisManager.onVariantAnalysisRemoved(variantAnalysisRemovedSpy);
|
||||
|
||||
monitorVariantAnalysisCommandSpy = sinon.spy();
|
||||
sandbox.stub(commands, 'executeCommand').callsFake(monitorVariantAnalysisCommandSpy);
|
||||
});
|
||||
|
||||
describe('when variant analysis record doesn\'t exist', async () => {
|
||||
it('should remove the variant analysis', async () => {
|
||||
await variantAnalysisManager.rehydrateVariantAnalysis(variantAnalysis);
|
||||
sinon.assert.calledOnce(variantAnalysisRemovedSpy);
|
||||
});
|
||||
|
||||
it('should not trigger a monitoring command', async () => {
|
||||
await variantAnalysisManager.rehydrateVariantAnalysis(variantAnalysis);
|
||||
sinon.assert.notCalled(monitorVariantAnalysisCommandSpy);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when variant analysis record does exist', async () => {
|
||||
let variantAnalysisStorageLocation: string;
|
||||
|
||||
beforeEach(async () => {
|
||||
variantAnalysisStorageLocation = variantAnalysisManager.getVariantAnalysisStorageLocation(variantAnalysis.id);
|
||||
await createTimestampFile(variantAnalysisStorageLocation);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
fs.rmSync(variantAnalysisStorageLocation, { recursive: true });
|
||||
});
|
||||
|
||||
describe('when the variant analysis is not complete', async () => {
|
||||
beforeEach(() => {
|
||||
sandbox.stub(VariantAnalysisModule, 'isVariantAnalysisComplete').resolves(false);
|
||||
});
|
||||
|
||||
it('should not remove the variant analysis', async () => {
|
||||
await variantAnalysisManager.rehydrateVariantAnalysis(variantAnalysis);
|
||||
sinon.assert.notCalled(variantAnalysisRemovedSpy);
|
||||
});
|
||||
|
||||
it('should trigger a monitoring command', async () => {
|
||||
await variantAnalysisManager.rehydrateVariantAnalysis(variantAnalysis);
|
||||
sinon.assert.calledWith(monitorVariantAnalysisCommandSpy, 'codeQL.monitorVariantAnalysis');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when the variant analysis is complete', async () => {
|
||||
beforeEach(() => {
|
||||
sandbox.stub(VariantAnalysisModule, 'isVariantAnalysisComplete').resolves(true);
|
||||
});
|
||||
|
||||
it('should not remove the variant analysis', async () => {
|
||||
await variantAnalysisManager.rehydrateVariantAnalysis(variantAnalysis);
|
||||
sinon.assert.notCalled(variantAnalysisRemovedSpy);
|
||||
});
|
||||
|
||||
it('should not trigger a monitoring command', async () => {
|
||||
await variantAnalysisManager.rehydrateVariantAnalysis(variantAnalysis);
|
||||
sinon.assert.notCalled(monitorVariantAnalysisCommandSpy);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -83,14 +83,14 @@ describe('Variant Analysis Monitor', async function() {
|
||||
|
||||
const result = await variantAnalysisMonitor.monitorVariantAnalysis(variantAnalysis, cancellationTokenSource.token);
|
||||
|
||||
expect(result).to.eql({ status: 'Cancelled', error: 'Variant Analysis was canceled.' });
|
||||
expect(result).to.eql({ status: 'Canceled' });
|
||||
});
|
||||
|
||||
describe('when the variant analysis fails', async () => {
|
||||
let mockFailedApiResponse: VariantAnalysisApiResponse;
|
||||
|
||||
beforeEach(async function() {
|
||||
mockFailedApiResponse = createFailedMockApiResponse('in_progress');
|
||||
mockFailedApiResponse = createFailedMockApiResponse();
|
||||
mockGetVariantAnalysis = sandbox.stub(ghApiClient, 'getVariantAnalysis').resolves(mockFailedApiResponse);
|
||||
});
|
||||
|
||||
@@ -98,8 +98,7 @@ describe('Variant Analysis Monitor', async function() {
|
||||
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(result.status).to.eql('Completed');
|
||||
expect(result.variantAnalysis?.status).to.equal(VariantAnalysisStatus.Failed);
|
||||
expect(result.variantAnalysis?.failureReason).to.equal(processFailureReason(mockFailedApiResponse.failure_reason as VariantAnalysisFailureReason));
|
||||
});
|
||||
@@ -130,7 +129,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, cancellationTokenSource.token);
|
||||
|
||||
expect(result.status).to.equal('CompletedSuccessfully');
|
||||
expect(result.status).to.equal('Completed');
|
||||
expect(result.scannedReposDownloaded).to.eql(succeededRepos.map(r => r.repository.id));
|
||||
});
|
||||
|
||||
@@ -173,7 +172,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, cancellationTokenSource.token);
|
||||
|
||||
expect(result.status).to.equal('CompletedSuccessfully');
|
||||
expect(result.status).to.equal('Completed');
|
||||
expect(result.scannedReposDownloaded).to.eql([]);
|
||||
});
|
||||
|
||||
@@ -194,7 +193,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, cancellationTokenSource.token);
|
||||
|
||||
expect(result.status).to.equal('CompletedSuccessfully');
|
||||
expect(result.status).to.equal('Completed');
|
||||
expect(result.scannedReposDownloaded).to.eql([]);
|
||||
});
|
||||
|
||||
|
||||
@@ -13,7 +13,6 @@ 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 { VariantAnalysisRepoTask } from '../../../remote-queries/gh-api/variant-analysis';
|
||||
|
||||
describe(VariantAnalysisResultsManager.name, function() {
|
||||
this.timeout(10000);
|
||||
@@ -47,15 +46,32 @@ describe(VariantAnalysisResultsManager.name, function() {
|
||||
|
||||
describe('download', () => {
|
||||
let getOctokitStub: sinon.SinonStub;
|
||||
let variantAnalysisStoragePath: string;
|
||||
const mockCredentials = {
|
||||
getOctokit: () => Promise.resolve({
|
||||
request: getOctokitStub
|
||||
})
|
||||
} as unknown as Credentials;
|
||||
let dummyRepoTask = createMockVariantAnalysisRepoTask();
|
||||
let variantAnalysisStoragePath: string;
|
||||
let repoTaskStorageDirectory: string;
|
||||
|
||||
beforeEach(async () => {
|
||||
dummyRepoTask = createMockVariantAnalysisRepoTask();
|
||||
|
||||
variantAnalysisStoragePath = path.join(storagePath, variantAnalysisId.toString());
|
||||
repoTaskStorageDirectory = variantAnalysisResultsManager.getRepoStorageDirectory(variantAnalysisStoragePath, dummyRepoTask.repository.full_name);
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
if (fs.existsSync(variantAnalysisStoragePath)) {
|
||||
fs.rmSync(variantAnalysisStoragePath, { recursive: true });
|
||||
}
|
||||
});
|
||||
|
||||
describe('isVariantAnalysisRepoDownloaded', () => {
|
||||
it('should return false when no results are downloaded', async () => {
|
||||
expect(await variantAnalysisResultsManager.isVariantAnalysisRepoDownloaded(variantAnalysisStoragePath, dummyRepoTask.repository.full_name)).to.equal(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when the artifact_url is missing', async () => {
|
||||
@@ -79,14 +95,9 @@ describe(VariantAnalysisResultsManager.name, function() {
|
||||
});
|
||||
|
||||
describe('when the artifact_url is present', async () => {
|
||||
let dummyRepoTask: VariantAnalysisRepoTask;
|
||||
let storageDirectory: string;
|
||||
let arrayBuffer: ArrayBuffer;
|
||||
|
||||
beforeEach(async () => {
|
||||
dummyRepoTask = createMockVariantAnalysisRepoTask();
|
||||
|
||||
storageDirectory = variantAnalysisResultsManager.getRepoStorageDirectory(variantAnalysisStoragePath, dummyRepoTask.repository.full_name);
|
||||
const sourceFilePath = path.join(__dirname, '../../../../src/vscode-tests/cli-integration/data/variant-analysis-results.zip');
|
||||
arrayBuffer = fs.readFileSync(sourceFilePath).buffer;
|
||||
|
||||
@@ -96,11 +107,6 @@ describe(VariantAnalysisResultsManager.name, function() {
|
||||
.resolves(arrayBuffer);
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
fs.removeSync(`${storageDirectory}/results.zip`);
|
||||
fs.removeSync(`${storageDirectory}/results`);
|
||||
});
|
||||
|
||||
it('should call the API to download the results', async () => {
|
||||
await variantAnalysisResultsManager.download(
|
||||
mockCredentials,
|
||||
@@ -120,7 +126,7 @@ describe(VariantAnalysisResultsManager.name, function() {
|
||||
variantAnalysisStoragePath
|
||||
);
|
||||
|
||||
expect(fs.existsSync(`${storageDirectory}/results.zip`)).to.be.true;
|
||||
expect(fs.existsSync(`${repoTaskStorageDirectory}/results.zip`)).to.be.true;
|
||||
});
|
||||
|
||||
it('should unzip the results in a `results/` folder', async () => {
|
||||
@@ -131,7 +137,20 @@ describe(VariantAnalysisResultsManager.name, function() {
|
||||
variantAnalysisStoragePath
|
||||
);
|
||||
|
||||
expect(fs.existsSync(`${storageDirectory}/results/results.sarif`)).to.be.true;
|
||||
expect(fs.existsSync(`${repoTaskStorageDirectory}/results/results.sarif`)).to.be.true;
|
||||
});
|
||||
|
||||
describe('isVariantAnalysisRepoDownloaded', () => {
|
||||
it('should return true once results are downloaded', async () => {
|
||||
await variantAnalysisResultsManager.download(
|
||||
mockCredentials,
|
||||
variantAnalysisId,
|
||||
dummyRepoTask,
|
||||
variantAnalysisStoragePath
|
||||
);
|
||||
|
||||
expect(await variantAnalysisResultsManager.isVariantAnalysisRepoDownloaded(variantAnalysisStoragePath, dummyRepoTask.repository.full_name)).to.equal(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -4,6 +4,9 @@ import {
|
||||
CompletedLocalQueryInfo,
|
||||
LocalQueryInfo,
|
||||
} from '../../../query-results';
|
||||
import { QueryEvaluationInfo, QueryWithResults } from '../../../run-queries-shared';
|
||||
import { CancellationTokenSource } from 'vscode';
|
||||
import { QueryResultType } from '../../../pure/legacy-messages';
|
||||
|
||||
export function createMockLocalQueryInfo(
|
||||
startTime: string,
|
||||
@@ -31,3 +34,56 @@ export function createMockLocalQueryInfo(
|
||||
} as unknown) as CompletedQueryInfo,
|
||||
} as unknown) as CompletedLocalQueryInfo;
|
||||
}
|
||||
|
||||
export function createMockLocalQuery(
|
||||
dbName = 'a',
|
||||
queryWithResults?: QueryWithResults,
|
||||
isFail = false
|
||||
): LocalQueryInfo {
|
||||
const initialQueryInfo = {
|
||||
databaseInfo: { name: dbName },
|
||||
start: new Date(),
|
||||
queryPath: 'hucairz'
|
||||
} as InitialQueryInfo;
|
||||
|
||||
const cancellationToken = {
|
||||
dispose: () => { /**/ },
|
||||
} as CancellationTokenSource;
|
||||
|
||||
const fqi = new LocalQueryInfo(
|
||||
initialQueryInfo,
|
||||
cancellationToken,
|
||||
);
|
||||
|
||||
if (queryWithResults) {
|
||||
fqi.completeThisQuery(queryWithResults);
|
||||
}
|
||||
|
||||
if (isFail) {
|
||||
fqi.failureReason = 'failure reason';
|
||||
}
|
||||
|
||||
return fqi;
|
||||
}
|
||||
|
||||
export function createMockQueryWithResults(
|
||||
sandbox: sinon.SinonSandbox,
|
||||
didRunSuccessfully = true,
|
||||
hasInterpretedResults = true
|
||||
): QueryWithResults {
|
||||
return {
|
||||
query: {
|
||||
hasInterpretedResults: () => Promise.resolve(hasInterpretedResults),
|
||||
deleteQuery: sandbox.stub(),
|
||||
} as unknown as QueryEvaluationInfo,
|
||||
successful: didRunSuccessfully,
|
||||
message: 'foo',
|
||||
dispose: sandbox.spy(),
|
||||
result: {
|
||||
evaluationTime: 1,
|
||||
queryId: 0,
|
||||
runId: 0,
|
||||
resultType: QueryResultType.SUCCESS,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ export function createMockSkippedRepos(): VariantAnalysisSkippedRepositories {
|
||||
return {
|
||||
access_mismatch_repos: createMockSkippedRepoGroup(),
|
||||
no_codeql_db_repos: createMockSkippedRepoGroup(),
|
||||
not_found_repo_nwos: createMockNotFoundSkippedRepoGroup(),
|
||||
not_found_repos: createMockNotFoundSkippedRepoGroup(),
|
||||
over_limit_repos: createMockSkippedRepoGroup()
|
||||
};
|
||||
}
|
||||
|
||||
@@ -40,13 +40,10 @@ export function createMockApiResponse(
|
||||
}
|
||||
|
||||
export function createFailedMockApiResponse(
|
||||
status: VariantAnalysisStatus = 'in_progress',
|
||||
scannedRepos: VariantAnalysisScannedRepository[] = createMockScannedRepos(),
|
||||
skippedRepos: VariantAnalysisSkippedRepositories = createMockSkippedRepos(),
|
||||
): VariantAnalysisApiResponse {
|
||||
const variantAnalysis = createMockApiResponse(status, scannedRepos, skippedRepos);
|
||||
variantAnalysis.status = status;
|
||||
const variantAnalysis = createMockApiResponse('completed', scannedRepos, skippedRepos);
|
||||
variantAnalysis.failure_reason = 'internal_error';
|
||||
|
||||
return variantAnalysis;
|
||||
}
|
||||
|
||||
@@ -1,31 +1,41 @@
|
||||
import { RemoteQueryHistoryItem } from '../../../remote-queries/remote-query-history-item';
|
||||
import { QueryStatus } from '../../../query-status';
|
||||
|
||||
export function createMockRemoteQueryHistoryItem({
|
||||
date = new Date('2022-01-01T00:00:00.000Z'),
|
||||
status = QueryStatus.InProgress,
|
||||
failureReason = undefined,
|
||||
resultCount = 16,
|
||||
userSpecifiedLabel = undefined,
|
||||
repositoryCount = 0,
|
||||
userSpecifiedLabel = undefined,
|
||||
}: {
|
||||
date?: Date;
|
||||
status?: QueryStatus;
|
||||
failureReason?: string;
|
||||
resultCount?: number;
|
||||
userSpecifiedLabel?: string;
|
||||
repositoryCount?: number;
|
||||
userSpecifiedLabel?: string;
|
||||
}): RemoteQueryHistoryItem {
|
||||
return ({
|
||||
t: 'remote',
|
||||
userSpecifiedLabel,
|
||||
failureReason,
|
||||
resultCount,
|
||||
status,
|
||||
completed: false,
|
||||
queryId: 'queryId',
|
||||
remoteQuery: {
|
||||
executionStartTime: date.getTime(),
|
||||
queryName: 'query-name',
|
||||
queryFilePath: 'query-file.ql',
|
||||
queryText: 'select 1',
|
||||
language: 'javascript',
|
||||
controllerRepository: {
|
||||
owner: 'github',
|
||||
name: 'vscode-codeql-integration-tests',
|
||||
},
|
||||
language: 'javascript',
|
||||
executionStartTime: date.getTime(),
|
||||
actionsWorkflowRunId: 1,
|
||||
repositoryCount,
|
||||
},
|
||||
status: 'in progress',
|
||||
resultCount,
|
||||
} as unknown) as RemoteQueryHistoryItem;
|
||||
userSpecifiedLabel,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
import { VariantAnalysisHistoryItem } from '../../../remote-queries/variant-analysis-history-item';
|
||||
import { QueryStatus } from '../../../query-status';
|
||||
import { VariantAnalysisStatus } from '../../../remote-queries/shared/variant-analysis';
|
||||
import { createMockVariantAnalysis } from './shared/variant-analysis';
|
||||
|
||||
export function createMockVariantAnalysisHistoryItem(
|
||||
historyItemStatus: QueryStatus = QueryStatus.InProgress,
|
||||
variantAnalysisStatus: VariantAnalysisStatus = VariantAnalysisStatus.Succeeded,
|
||||
failureReason?: string,
|
||||
resultCount?: number,
|
||||
userSpecifiedLabel?: string
|
||||
): VariantAnalysisHistoryItem {
|
||||
return ({
|
||||
t: 'variant-analysis',
|
||||
failureReason,
|
||||
resultCount,
|
||||
status: historyItemStatus,
|
||||
completed: false,
|
||||
variantAnalysis: createMockVariantAnalysis(variantAnalysisStatus),
|
||||
userSpecifiedLabel,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -5,9 +5,7 @@ import { HistoryItemLabelProvider } from '../../history-item-label-provider';
|
||||
import { createMockLocalQueryInfo } from '../factories/local-queries/local-query-history-item';
|
||||
import { createMockRemoteQueryHistoryItem } from '../factories/remote-queries/remote-query-history-item';
|
||||
|
||||
|
||||
describe('HistoryItemLabelProvider', () => {
|
||||
|
||||
let labelProvider: HistoryItemLabelProvider;
|
||||
let config: QueryHistoryConfig;
|
||||
const date = new Date('2022-01-01T00:00:00.000Z');
|
||||
|
||||
@@ -1,19 +1,18 @@
|
||||
import { expect } from 'chai';
|
||||
|
||||
import { QueryStatus } from '../../src/query-status';
|
||||
import { QueryStatus } from '../../query-status';
|
||||
import {
|
||||
buildRepoLabel,
|
||||
getActionsWorkflowRunUrl,
|
||||
getQueryId,
|
||||
getQueryText,
|
||||
getRawQueryName
|
||||
} from '../../src/query-history-info';
|
||||
import { VariantAnalysisHistoryItem } from '../../src/remote-queries/variant-analysis-history-item';
|
||||
import { createMockVariantAnalysis } from '../../src/vscode-tests/factories/remote-queries/shared/variant-analysis';
|
||||
import { createMockScannedRepos } from '../../src/vscode-tests/factories/remote-queries/shared/scanned-repositories';
|
||||
import { createMockLocalQueryInfo } from '../../src/vscode-tests/factories/local-queries/local-query-history-item';
|
||||
import { createMockRemoteQueryHistoryItem } from '../../src/vscode-tests/factories/remote-queries/remote-query-history-item';
|
||||
import { VariantAnalysisRepoStatus, VariantAnalysisStatus } from '../../src/remote-queries/shared/variant-analysis';
|
||||
} from '../../query-history-info';
|
||||
import { VariantAnalysisHistoryItem } from '../../remote-queries/variant-analysis-history-item';
|
||||
import { createMockVariantAnalysis } from '../factories/remote-queries/shared/variant-analysis';
|
||||
import { createMockScannedRepos } from '../factories/remote-queries/shared/scanned-repositories';
|
||||
import { createMockLocalQueryInfo } from '../factories/local-queries/local-query-history-item';
|
||||
import { createMockRemoteQueryHistoryItem } from '../factories/remote-queries/remote-query-history-item';
|
||||
import { VariantAnalysisRepoStatus, VariantAnalysisStatus } from '../../remote-queries/shared/variant-analysis';
|
||||
|
||||
describe('Query history info', () => {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -13,6 +13,7 @@ import { slurpQueryHistory, splatQueryHistory } from '../../query-serialization'
|
||||
import { formatLegacyMessage, QueryInProgress } from '../../legacy-query-server/run-queries';
|
||||
import { EvaluationResult, QueryResultType } from '../../pure/legacy-messages';
|
||||
import Sinon = require('sinon');
|
||||
import { sleep } from '../../pure/time';
|
||||
|
||||
describe('query-results', () => {
|
||||
let disposeSpy: sinon.SinonSpy;
|
||||
@@ -455,10 +456,6 @@ describe('query-results', () => {
|
||||
}
|
||||
}
|
||||
|
||||
async function sleep(ms: number) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
function createMockQueryWithResults(
|
||||
queryPath: string,
|
||||
didRunSuccessfully = true,
|
||||
|
||||
@@ -121,9 +121,7 @@ describe('Variant Analyses and QueryHistoryManager', function() {
|
||||
|
||||
expect(rehydrateVariantAnalysisStub).to.have.callCount(2);
|
||||
expect(rehydrateVariantAnalysisStub.getCall(0).args[0]).to.deep.eq(rawQueryHistory[0].variantAnalysis);
|
||||
expect(rehydrateVariantAnalysisStub.getCall(0).args[1]).to.deep.eq(rawQueryHistory[0].status);
|
||||
expect(rehydrateVariantAnalysisStub.getCall(1).args[0]).to.deep.eq(rawQueryHistory[1].variantAnalysis);
|
||||
expect(rehydrateVariantAnalysisStub.getCall(1).args[1]).to.deep.eq(rawQueryHistory[1].status);
|
||||
|
||||
expect(qhm.treeDataProvider.allHistory[0]).to.deep.eq(rawQueryHistory[0]);
|
||||
expect(qhm.treeDataProvider.allHistory[1]).to.deep.eq(rawQueryHistory[1]);
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
import { QueryHistoryInfo } from '../../query-history-info';
|
||||
|
||||
export function shuffleHistoryItems(history: QueryHistoryInfo[]) {
|
||||
return history.sort(() => Math.random() - 0.5);
|
||||
}
|
||||
@@ -600,6 +600,74 @@
|
||||
"endColumn": 52
|
||||
}
|
||||
},
|
||||
{
|
||||
"fileLink": {
|
||||
"fileLinkPrefix": "https://github.com/meteor/meteor/blob/73b538fe201cbfe89dd0c709689023f9b3eab1ec",
|
||||
"filePath": "npm-packages/meteor-installer/install.js"
|
||||
},
|
||||
"codeSnippet": {
|
||||
"startLine": 257,
|
||||
"endLine": 261,
|
||||
"text": " if (isWindows()) {\n //set for the current session and beyond\n child_process.execSync(`setx path \"${meteorPath}/;%path%`);\n return;\n }\n"
|
||||
},
|
||||
"highlightedRegion": {
|
||||
"startLine": 259,
|
||||
"startColumn": 42,
|
||||
"endLine": 259,
|
||||
"endColumn": 52
|
||||
}
|
||||
},
|
||||
{
|
||||
"fileLink": {
|
||||
"fileLinkPrefix": "https://github.com/meteor/meteor/blob/73b538fe201cbfe89dd0c709689023f9b3eab1ec",
|
||||
"filePath": "npm-packages/meteor-installer/install.js"
|
||||
},
|
||||
"codeSnippet": {
|
||||
"startLine": 257,
|
||||
"endLine": 261,
|
||||
"text": " if (isWindows()) {\n //set for the current session and beyond\n child_process.execSync(`setx path \"${meteorPath}/;%path%`);\n return;\n }\n"
|
||||
},
|
||||
"highlightedRegion": {
|
||||
"startLine": 259,
|
||||
"startColumn": 42,
|
||||
"endLine": 259,
|
||||
"endColumn": 52
|
||||
}
|
||||
},
|
||||
{
|
||||
"fileLink": {
|
||||
"fileLinkPrefix": "https://github.com/meteor/meteor/blob/73b538fe201cbfe89dd0c709689023f9b3eab1ec",
|
||||
"filePath": "npm-packages/meteor-installer/install.js"
|
||||
},
|
||||
"codeSnippet": {
|
||||
"startLine": 257,
|
||||
"endLine": 261,
|
||||
"text": " if (isWindows()) {\n //set for the current session and beyond\n child_process.execSync(`setx path \"${meteorPath}/;%path%`);\n return;\n }\n"
|
||||
},
|
||||
"highlightedRegion": {
|
||||
"startLine": 259,
|
||||
"startColumn": 42,
|
||||
"endLine": 259,
|
||||
"endColumn": 52
|
||||
}
|
||||
},
|
||||
{
|
||||
"fileLink": {
|
||||
"fileLinkPrefix": "https://github.com/meteor/meteor/blob/73b538fe201cbfe89dd0c709689023f9b3eab1ec",
|
||||
"filePath": "npm-packages/meteor-installer/install.js"
|
||||
},
|
||||
"codeSnippet": {
|
||||
"startLine": 257,
|
||||
"endLine": 261,
|
||||
"text": " if (isWindows()) {\n //set for the current session and beyond\n child_process.execSync(`setx path \"${meteorPath}/;%path%`);\n return;\n }\n"
|
||||
},
|
||||
"highlightedRegion": {
|
||||
"startLine": 259,
|
||||
"startColumn": 42,
|
||||
"endLine": 259,
|
||||
"endColumn": 52
|
||||
}
|
||||
},
|
||||
{
|
||||
"fileLink": {
|
||||
"fileLinkPrefix": "https://github.com/meteor/meteor/blob/73b538fe201cbfe89dd0c709689023f9b3eab1ec",
|
||||
|
||||
@@ -16,44 +16,44 @@
|
||||
<summary>Path with 5 steps</summary>
|
||||
|
||||
1. [javascript/ql/src/Security/CWE-078/examples/shell-command-injection-from-environment.js](https://github.com/github/codeql/blob/48015e5a2e6202131f2d1062cc066dc33ed69a9b/javascript/ql/src/Security/CWE-078/examples/shell-command-injection-from-environment.js#L4-L4)
|
||||
<pre><code class="javascript"> path = require("path");
|
||||
function cleanupTemp() {
|
||||
let cmd = "rm -rf " + path.join(<strong>__dirname</strong>, "temp");
|
||||
cp.execSync(cmd); // BAD
|
||||
}
|
||||
</code></pre>
|
||||
|
||||
<pre><code class="javascript"> path = require("path");
|
||||
function cleanupTemp() {
|
||||
let cmd = "rm -rf " + path.join(<strong>__dirname</strong>, "temp");
|
||||
cp.execSync(cmd); // BAD
|
||||
}
|
||||
</code></pre>
|
||||
|
||||
2. [javascript/ql/src/Security/CWE-078/examples/shell-command-injection-from-environment.js](https://github.com/github/codeql/blob/48015e5a2e6202131f2d1062cc066dc33ed69a9b/javascript/ql/src/Security/CWE-078/examples/shell-command-injection-from-environment.js#L4-L4)
|
||||
<pre><code class="javascript"> path = require("path");
|
||||
function cleanupTemp() {
|
||||
let cmd = "rm -rf " + <strong>path.join(__dirname, "temp")</strong>;
|
||||
cp.execSync(cmd); // BAD
|
||||
}
|
||||
</code></pre>
|
||||
|
||||
<pre><code class="javascript"> path = require("path");
|
||||
function cleanupTemp() {
|
||||
let cmd = "rm -rf " + <strong>path.join(__dirname, "temp")</strong>;
|
||||
cp.execSync(cmd); // BAD
|
||||
}
|
||||
</code></pre>
|
||||
|
||||
3. [javascript/ql/src/Security/CWE-078/examples/shell-command-injection-from-environment.js](https://github.com/github/codeql/blob/48015e5a2e6202131f2d1062cc066dc33ed69a9b/javascript/ql/src/Security/CWE-078/examples/shell-command-injection-from-environment.js#L4-L4)
|
||||
<pre><code class="javascript"> path = require("path");
|
||||
function cleanupTemp() {
|
||||
let cmd = <strong>"rm -rf " + path.join(__dirname, "temp")</strong>;
|
||||
cp.execSync(cmd); // BAD
|
||||
}
|
||||
</code></pre>
|
||||
|
||||
<pre><code class="javascript"> path = require("path");
|
||||
function cleanupTemp() {
|
||||
let cmd = <strong>"rm -rf " + path.join(__dirname, "temp")</strong>;
|
||||
cp.execSync(cmd); // BAD
|
||||
}
|
||||
</code></pre>
|
||||
|
||||
4. [javascript/ql/src/Security/CWE-078/examples/shell-command-injection-from-environment.js](https://github.com/github/codeql/blob/48015e5a2e6202131f2d1062cc066dc33ed69a9b/javascript/ql/src/Security/CWE-078/examples/shell-command-injection-from-environment.js#L4-L4)
|
||||
<pre><code class="javascript"> path = require("path");
|
||||
function cleanupTemp() {
|
||||
let <strong>cmd = "rm -rf " + path.join(__dirname, "temp")</strong>;
|
||||
cp.execSync(cmd); // BAD
|
||||
}
|
||||
</code></pre>
|
||||
|
||||
<pre><code class="javascript"> path = require("path");
|
||||
function cleanupTemp() {
|
||||
let <strong>cmd = "rm -rf " + path.join(__dirname, "temp")</strong>;
|
||||
cp.execSync(cmd); // BAD
|
||||
}
|
||||
</code></pre>
|
||||
|
||||
5. [javascript/ql/src/Security/CWE-078/examples/shell-command-injection-from-environment.js](https://github.com/github/codeql/blob/48015e5a2e6202131f2d1062cc066dc33ed69a9b/javascript/ql/src/Security/CWE-078/examples/shell-command-injection-from-environment.js#L5-L5)
|
||||
<pre><code class="javascript">function cleanupTemp() {
|
||||
let cmd = "rm -rf " + path.join(__dirname, "temp");
|
||||
cp.execSync(<strong>cmd</strong>); // BAD
|
||||
}
|
||||
</code></pre>
|
||||
|
||||
<pre><code class="javascript">function cleanupTemp() {
|
||||
let cmd = "rm -rf " + path.join(__dirname, "temp");
|
||||
cp.execSync(<strong>cmd</strong>); // BAD
|
||||
}
|
||||
</code></pre>
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
@@ -76,29 +76,29 @@
|
||||
<summary>Path with 3 steps</summary>
|
||||
|
||||
1. [javascript/ql/test/query-tests/Security/CWE-078/tst_shell-command-injection-from-environment.js](https://github.com/github/codeql/blob/48015e5a2e6202131f2d1062cc066dc33ed69a9b/javascript/ql/test/query-tests/Security/CWE-078/tst_shell-command-injection-from-environment.js#L6-L6)
|
||||
<pre><code class="javascript">(function() {
|
||||
cp.execFileSync('rm', ['-rf', path.join(__dirname, "temp")]); // GOOD
|
||||
cp.execSync('rm -rf ' + path.join(<strong>__dirname</strong>, "temp")); // BAD
|
||||
|
||||
execa.shell('rm -rf ' + path.join(__dirname, "temp")); // NOT OK
|
||||
</code></pre>
|
||||
|
||||
<pre><code class="javascript">(function() {
|
||||
cp.execFileSync('rm', ['-rf', path.join(__dirname, "temp")]); // GOOD
|
||||
cp.execSync('rm -rf ' + path.join(<strong>__dirname</strong>, "temp")); // BAD
|
||||
|
||||
execa.shell('rm -rf ' + path.join(__dirname, "temp")); // NOT OK
|
||||
</code></pre>
|
||||
|
||||
2. [javascript/ql/test/query-tests/Security/CWE-078/tst_shell-command-injection-from-environment.js](https://github.com/github/codeql/blob/48015e5a2e6202131f2d1062cc066dc33ed69a9b/javascript/ql/test/query-tests/Security/CWE-078/tst_shell-command-injection-from-environment.js#L6-L6)
|
||||
<pre><code class="javascript">(function() {
|
||||
cp.execFileSync('rm', ['-rf', path.join(__dirname, "temp")]); // GOOD
|
||||
cp.execSync('rm -rf ' + <strong>path.join(__dirname, "temp")</strong>); // BAD
|
||||
|
||||
execa.shell('rm -rf ' + path.join(__dirname, "temp")); // NOT OK
|
||||
</code></pre>
|
||||
|
||||
<pre><code class="javascript">(function() {
|
||||
cp.execFileSync('rm', ['-rf', path.join(__dirname, "temp")]); // GOOD
|
||||
cp.execSync('rm -rf ' + <strong>path.join(__dirname, "temp")</strong>); // BAD
|
||||
|
||||
execa.shell('rm -rf ' + path.join(__dirname, "temp")); // NOT OK
|
||||
</code></pre>
|
||||
|
||||
3. [javascript/ql/test/query-tests/Security/CWE-078/tst_shell-command-injection-from-environment.js](https://github.com/github/codeql/blob/48015e5a2e6202131f2d1062cc066dc33ed69a9b/javascript/ql/test/query-tests/Security/CWE-078/tst_shell-command-injection-from-environment.js#L6-L6)
|
||||
<pre><code class="javascript">(function() {
|
||||
cp.execFileSync('rm', ['-rf', path.join(__dirname, "temp")]); // GOOD
|
||||
cp.execSync(<strong>'rm -rf ' + path.join(__dirname, "temp")</strong>); // BAD
|
||||
|
||||
execa.shell('rm -rf ' + path.join(__dirname, "temp")); // NOT OK
|
||||
</code></pre>
|
||||
|
||||
<pre><code class="javascript">(function() {
|
||||
cp.execFileSync('rm', ['-rf', path.join(__dirname, "temp")]); // GOOD
|
||||
cp.execSync(<strong>'rm -rf ' + path.join(__dirname, "temp")</strong>); // BAD
|
||||
|
||||
execa.shell('rm -rf ' + path.join(__dirname, "temp")); // NOT OK
|
||||
</code></pre>
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
@@ -121,29 +121,29 @@
|
||||
<summary>Path with 3 steps</summary>
|
||||
|
||||
1. [javascript/ql/test/query-tests/Security/CWE-078/tst_shell-command-injection-from-environment.js](https://github.com/github/codeql/blob/48015e5a2e6202131f2d1062cc066dc33ed69a9b/javascript/ql/test/query-tests/Security/CWE-078/tst_shell-command-injection-from-environment.js#L8-L8)
|
||||
<pre><code class="javascript"> cp.execSync('rm -rf ' + path.join(__dirname, "temp")); // BAD
|
||||
|
||||
execa.shell('rm -rf ' + path.join(<strong>__dirname</strong>, "temp")); // NOT OK
|
||||
execa.shellSync('rm -rf ' + path.join(__dirname, "temp")); // NOT OK
|
||||
|
||||
</code></pre>
|
||||
|
||||
<pre><code class="javascript"> cp.execSync('rm -rf ' + path.join(__dirname, "temp")); // BAD
|
||||
|
||||
execa.shell('rm -rf ' + path.join(<strong>__dirname</strong>, "temp")); // NOT OK
|
||||
execa.shellSync('rm -rf ' + path.join(__dirname, "temp")); // NOT OK
|
||||
|
||||
</code></pre>
|
||||
|
||||
2. [javascript/ql/test/query-tests/Security/CWE-078/tst_shell-command-injection-from-environment.js](https://github.com/github/codeql/blob/48015e5a2e6202131f2d1062cc066dc33ed69a9b/javascript/ql/test/query-tests/Security/CWE-078/tst_shell-command-injection-from-environment.js#L8-L8)
|
||||
<pre><code class="javascript"> cp.execSync('rm -rf ' + path.join(__dirname, "temp")); // BAD
|
||||
|
||||
execa.shell('rm -rf ' + <strong>path.join(__dirname, "temp")</strong>); // NOT OK
|
||||
execa.shellSync('rm -rf ' + path.join(__dirname, "temp")); // NOT OK
|
||||
|
||||
</code></pre>
|
||||
|
||||
<pre><code class="javascript"> cp.execSync('rm -rf ' + path.join(__dirname, "temp")); // BAD
|
||||
|
||||
execa.shell('rm -rf ' + <strong>path.join(__dirname, "temp")</strong>); // NOT OK
|
||||
execa.shellSync('rm -rf ' + path.join(__dirname, "temp")); // NOT OK
|
||||
|
||||
</code></pre>
|
||||
|
||||
3. [javascript/ql/test/query-tests/Security/CWE-078/tst_shell-command-injection-from-environment.js](https://github.com/github/codeql/blob/48015e5a2e6202131f2d1062cc066dc33ed69a9b/javascript/ql/test/query-tests/Security/CWE-078/tst_shell-command-injection-from-environment.js#L8-L8)
|
||||
<pre><code class="javascript"> cp.execSync('rm -rf ' + path.join(__dirname, "temp")); // BAD
|
||||
|
||||
execa.shell(<strong>'rm -rf ' + path.join(__dirname, "temp")</strong>); // NOT OK
|
||||
execa.shellSync('rm -rf ' + path.join(__dirname, "temp")); // NOT OK
|
||||
|
||||
</code></pre>
|
||||
|
||||
<pre><code class="javascript"> cp.execSync('rm -rf ' + path.join(__dirname, "temp")); // BAD
|
||||
|
||||
execa.shell(<strong>'rm -rf ' + path.join(__dirname, "temp")</strong>); // NOT OK
|
||||
execa.shellSync('rm -rf ' + path.join(__dirname, "temp")); // NOT OK
|
||||
|
||||
</code></pre>
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
@@ -166,29 +166,29 @@
|
||||
<summary>Path with 3 steps</summary>
|
||||
|
||||
1. [javascript/ql/test/query-tests/Security/CWE-078/tst_shell-command-injection-from-environment.js](https://github.com/github/codeql/blob/48015e5a2e6202131f2d1062cc066dc33ed69a9b/javascript/ql/test/query-tests/Security/CWE-078/tst_shell-command-injection-from-environment.js#L9-L9)
|
||||
<pre><code class="javascript">
|
||||
execa.shell('rm -rf ' + path.join(__dirname, "temp")); // NOT OK
|
||||
execa.shellSync('rm -rf ' + path.join(<strong>__dirname</strong>, "temp")); // NOT OK
|
||||
|
||||
const safe = "\"" + path.join(__dirname, "temp") + "\"";
|
||||
</code></pre>
|
||||
|
||||
<pre><code class="javascript">
|
||||
execa.shell('rm -rf ' + path.join(__dirname, "temp")); // NOT OK
|
||||
execa.shellSync('rm -rf ' + path.join(<strong>__dirname</strong>, "temp")); // NOT OK
|
||||
|
||||
const safe = "\"" + path.join(__dirname, "temp") + "\"";
|
||||
</code></pre>
|
||||
|
||||
2. [javascript/ql/test/query-tests/Security/CWE-078/tst_shell-command-injection-from-environment.js](https://github.com/github/codeql/blob/48015e5a2e6202131f2d1062cc066dc33ed69a9b/javascript/ql/test/query-tests/Security/CWE-078/tst_shell-command-injection-from-environment.js#L9-L9)
|
||||
<pre><code class="javascript">
|
||||
execa.shell('rm -rf ' + path.join(__dirname, "temp")); // NOT OK
|
||||
execa.shellSync('rm -rf ' + <strong>path.join(__dirname, "temp")</strong>); // NOT OK
|
||||
|
||||
const safe = "\"" + path.join(__dirname, "temp") + "\"";
|
||||
</code></pre>
|
||||
|
||||
<pre><code class="javascript">
|
||||
execa.shell('rm -rf ' + path.join(__dirname, "temp")); // NOT OK
|
||||
execa.shellSync('rm -rf ' + <strong>path.join(__dirname, "temp")</strong>); // NOT OK
|
||||
|
||||
const safe = "\"" + path.join(__dirname, "temp") + "\"";
|
||||
</code></pre>
|
||||
|
||||
3. [javascript/ql/test/query-tests/Security/CWE-078/tst_shell-command-injection-from-environment.js](https://github.com/github/codeql/blob/48015e5a2e6202131f2d1062cc066dc33ed69a9b/javascript/ql/test/query-tests/Security/CWE-078/tst_shell-command-injection-from-environment.js#L9-L9)
|
||||
<pre><code class="javascript">
|
||||
execa.shell('rm -rf ' + path.join(__dirname, "temp")); // NOT OK
|
||||
execa.shellSync(<strong>'rm -rf ' + path.join(__dirname, "temp")</strong>); // NOT OK
|
||||
|
||||
const safe = "\"" + path.join(__dirname, "temp") + "\"";
|
||||
</code></pre>
|
||||
|
||||
<pre><code class="javascript">
|
||||
execa.shell('rm -rf ' + path.join(__dirname, "temp")); // NOT OK
|
||||
execa.shellSync(<strong>'rm -rf ' + path.join(__dirname, "temp")</strong>); // NOT OK
|
||||
|
||||
const safe = "\"" + path.join(__dirname, "temp") + "\"";
|
||||
</code></pre>
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
@@ -14,61 +14,93 @@
|
||||
#### Paths
|
||||
|
||||
<details>
|
||||
<summary>Path with 7 steps</summary>
|
||||
<summary>Path with 11 steps</summary>
|
||||
|
||||
1. [npm-packages/meteor-installer/config.js](https://github.com/meteor/meteor/blob/73b538fe201cbfe89dd0c709689023f9b3eab1ec/npm-packages/meteor-installer/config.js#L39-L39)
|
||||
<pre><code class="javascript">
|
||||
const meteorLocalFolder = '.meteor';
|
||||
const meteorPath = <strong>path.resolve(rootPath, meteorLocalFolder)</strong>;
|
||||
|
||||
module.exports = {
|
||||
</code></pre>
|
||||
|
||||
<pre><code class="javascript">
|
||||
const meteorLocalFolder = '.meteor';
|
||||
const meteorPath = <strong>path.resolve(rootPath, meteorLocalFolder)</strong>;
|
||||
|
||||
module.exports = {
|
||||
</code></pre>
|
||||
|
||||
2. [npm-packages/meteor-installer/config.js](https://github.com/meteor/meteor/blob/73b538fe201cbfe89dd0c709689023f9b3eab1ec/npm-packages/meteor-installer/config.js#L39-L39)
|
||||
<pre><code class="javascript">
|
||||
const meteorLocalFolder = '.meteor';
|
||||
const <strong>meteorPath = path.resolve(rootPath, meteorLocalFolder)</strong>;
|
||||
|
||||
module.exports = {
|
||||
</code></pre>
|
||||
|
||||
<pre><code class="javascript">
|
||||
const meteorLocalFolder = '.meteor';
|
||||
const <strong>meteorPath = path.resolve(rootPath, meteorLocalFolder)</strong>;
|
||||
|
||||
module.exports = {
|
||||
</code></pre>
|
||||
|
||||
3. [npm-packages/meteor-installer/config.js](https://github.com/meteor/meteor/blob/73b538fe201cbfe89dd0c709689023f9b3eab1ec/npm-packages/meteor-installer/config.js#L44-L44)
|
||||
<pre><code class="javascript"> METEOR_LATEST_VERSION,
|
||||
extractPath: rootPath,
|
||||
<strong>meteorPath</strong>,
|
||||
release: process.env.INSTALL_METEOR_VERSION || METEOR_LATEST_VERSION,
|
||||
rootPath,
|
||||
</code></pre>
|
||||
|
||||
<pre><code class="javascript"> METEOR_LATEST_VERSION,
|
||||
extractPath: rootPath,
|
||||
<strong>meteorPath</strong>,
|
||||
release: process.env.INSTALL_METEOR_VERSION || METEOR_LATEST_VERSION,
|
||||
rootPath,
|
||||
</code></pre>
|
||||
|
||||
4. [npm-packages/meteor-installer/install.js](https://github.com/meteor/meteor/blob/73b538fe201cbfe89dd0c709689023f9b3eab1ec/npm-packages/meteor-installer/install.js#L12-L12)
|
||||
<pre><code class="javascript">const os = require('os');
|
||||
const {
|
||||
<strong>meteorPath</strong>,
|
||||
release,
|
||||
startedPath,
|
||||
</code></pre>
|
||||
|
||||
<pre><code class="javascript">const os = require('os');
|
||||
const {
|
||||
<strong>meteorPath</strong>,
|
||||
release,
|
||||
startedPath,
|
||||
</code></pre>
|
||||
|
||||
5. [npm-packages/meteor-installer/install.js](https://github.com/meteor/meteor/blob/73b538fe201cbfe89dd0c709689023f9b3eab1ec/npm-packages/meteor-installer/install.js#L11-L23)
|
||||
<pre><code class="javascript">const tmp = require('tmp');
|
||||
const os = require('os');
|
||||
const <strong>{</strong>
|
||||
<strong> meteorPath,</strong>
|
||||
<strong> release,</strong>
|
||||
<strong> startedPath,</strong>
|
||||
<strong> extractPath,</strong>
|
||||
<strong> isWindows,</strong>
|
||||
<strong> rootPath,</strong>
|
||||
<strong> sudoUser,</strong>
|
||||
<strong> isSudo,</strong>
|
||||
<strong> isMac,</strong>
|
||||
<strong> METEOR_LATEST_VERSION,</strong>
|
||||
<strong> shouldSetupExecPath,</strong>
|
||||
<strong>} = require('./config.js')</strong>;
|
||||
const { uninstall } = require('./uninstall');
|
||||
const {
|
||||
</code></pre>
|
||||
|
||||
<pre><code class="javascript">const tmp = require('tmp');
|
||||
const os = require('os');
|
||||
const <strong>{</strong>
|
||||
<strong> meteorPath,</strong>
|
||||
<strong> release,</strong>
|
||||
<strong> startedPath,</strong>
|
||||
<strong> extractPath,</strong>
|
||||
<strong> isWindows,</strong>
|
||||
<strong> rootPath,</strong>
|
||||
<strong> sudoUser,</strong>
|
||||
<strong> isSudo,</strong>
|
||||
<strong> isMac,</strong>
|
||||
<strong> METEOR_LATEST_VERSION,</strong>
|
||||
<strong> shouldSetupExecPath,</strong>
|
||||
<strong>} = require('./config.js')</strong>;
|
||||
const { uninstall } = require('./uninstall');
|
||||
const {
|
||||
</code></pre>
|
||||
|
||||
6. [npm-packages/meteor-installer/install.js](https://github.com/meteor/meteor/blob/73b538fe201cbfe89dd0c709689023f9b3eab1ec/npm-packages/meteor-installer/install.js#L259-L259)
|
||||
<pre><code class="javascript"> if (isWindows()) {
|
||||
//set for the current session and beyond
|
||||
child_process.execSync(`setx path "${<strong>meteorPath</strong>}/;%path%`);
|
||||
return;
|
||||
}
|
||||
</code></pre>
|
||||
|
||||
7. [npm-packages/meteor-installer/install.js](https://github.com/meteor/meteor/blob/73b538fe201cbfe89dd0c709689023f9b3eab1ec/npm-packages/meteor-installer/install.js#L259-L259)
|
||||
<pre><code class="javascript"> if (isWindows()) {
|
||||
//set for the current session and beyond
|
||||
child_process.execSync(`setx path "${<strong>meteorPath</strong>}/;%path%`);
|
||||
return;
|
||||
}
|
||||
</code></pre>
|
||||
|
||||
8. [npm-packages/meteor-installer/install.js](https://github.com/meteor/meteor/blob/73b538fe201cbfe89dd0c709689023f9b3eab1ec/npm-packages/meteor-installer/install.js#L259-L259)
|
||||
<pre><code class="javascript"> if (isWindows()) {
|
||||
//set for the current session and beyond
|
||||
child_process.execSync(`setx path "${<strong>meteorPath</strong>}/;%path%`);
|
||||
return;
|
||||
}
|
||||
</code></pre>
|
||||
|
||||
9. [npm-packages/meteor-installer/install.js](https://github.com/meteor/meteor/blob/73b538fe201cbfe89dd0c709689023f9b3eab1ec/npm-packages/meteor-installer/install.js#L259-L259)
|
||||
<pre><code class="javascript"> if (isWindows()) {
|
||||
//set for the current session and beyond
|
||||
child_process.execSync(`setx path "${<strong>meteorPath</strong>}/;%path%`);
|
||||
return;
|
||||
}
|
||||
</code></pre>
|
||||
|
||||
10. [npm-packages/meteor-installer/install.js](https://github.com/meteor/meteor/blob/73b538fe201cbfe89dd0c709689023f9b3eab1ec/npm-packages/meteor-installer/install.js#L259-L259)
|
||||
<pre><code class="javascript"> if (isWindows()) {
|
||||
//set for the current session and beyond
|
||||
child_process.execSync(`setx path "${<strong>meteorPath</strong>}/;%path%`);
|
||||
@@ -76,7 +108,7 @@
|
||||
}
|
||||
</code></pre>
|
||||
|
||||
7. [npm-packages/meteor-installer/install.js](https://github.com/meteor/meteor/blob/73b538fe201cbfe89dd0c709689023f9b3eab1ec/npm-packages/meteor-installer/install.js#L259-L259)
|
||||
11. [npm-packages/meteor-installer/install.js](https://github.com/meteor/meteor/blob/73b538fe201cbfe89dd0c709689023f9b3eab1ec/npm-packages/meteor-installer/install.js#L259-L259)
|
||||
<pre><code class="javascript"> if (isWindows()) {
|
||||
//set for the current session and beyond
|
||||
child_process.execSync(<strong>`setx path "${meteorPath}/;%path%`</strong>);
|
||||
@@ -91,21 +123,21 @@
|
||||
<summary>Path with 2 steps</summary>
|
||||
|
||||
1. [npm-packages/meteor-installer/config.js](https://github.com/meteor/meteor/blob/73b538fe201cbfe89dd0c709689023f9b3eab1ec/npm-packages/meteor-installer/config.js#L39-L39)
|
||||
<pre><code class="javascript">
|
||||
const meteorLocalFolder = '.meteor';
|
||||
const meteorPath = <strong>path.resolve(rootPath, meteorLocalFolder)</strong>;
|
||||
|
||||
module.exports = {
|
||||
</code></pre>
|
||||
|
||||
<pre><code class="javascript">
|
||||
const meteorLocalFolder = '.meteor';
|
||||
const meteorPath = <strong>path.resolve(rootPath, meteorLocalFolder)</strong>;
|
||||
|
||||
module.exports = {
|
||||
</code></pre>
|
||||
|
||||
2. [npm-packages/meteor-installer/install.js](https://github.com/meteor/meteor/blob/73b538fe201cbfe89dd0c709689023f9b3eab1ec/npm-packages/meteor-installer/install.js#L259-L259)
|
||||
<pre><code class="javascript"> if (isWindows()) {
|
||||
//set for the current session and beyond
|
||||
child_process.execSync(<strong>`setx path "${meteorPath}/;%path%`</strong>);
|
||||
return;
|
||||
}
|
||||
</code></pre>
|
||||
|
||||
<pre><code class="javascript"> if (isWindows()) {
|
||||
//set for the current session and beyond
|
||||
child_process.execSync(<strong>`setx path "${meteorPath}/;%path%`</strong>);
|
||||
return;
|
||||
}
|
||||
</code></pre>
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ describe('Variant Analysis processor', function() {
|
||||
it('should process an API response and return a variant analysis', () => {
|
||||
const result = processVariantAnalysis(mockSubmission, mockApiResponse);
|
||||
|
||||
const { access_mismatch_repos, no_codeql_db_repos, not_found_repo_nwos, over_limit_repos } = skippedRepos;
|
||||
const { access_mismatch_repos, no_codeql_db_repos, not_found_repos, over_limit_repos } = skippedRepos;
|
||||
|
||||
expect(result).to.eql({
|
||||
'id': mockApiResponse.id,
|
||||
@@ -97,13 +97,13 @@ describe('Variant Analysis processor', function() {
|
||||
'notFoundRepos': {
|
||||
'repositories': [
|
||||
{
|
||||
'fullName': not_found_repo_nwos?.repository_full_names[0]
|
||||
'fullName': not_found_repos?.repository_full_names[0]
|
||||
},
|
||||
{
|
||||
'fullName': not_found_repo_nwos?.repository_full_names[1]
|
||||
'fullName': not_found_repos?.repository_full_names[1]
|
||||
}
|
||||
],
|
||||
'repositoryCount': not_found_repo_nwos?.repository_count
|
||||
'repositoryCount': not_found_repos?.repository_count
|
||||
},
|
||||
'overLimitRepos': {
|
||||
'repositories': [
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
import { expect } from 'chai';
|
||||
import {
|
||||
getActionsWorkflowRunUrl,
|
||||
parseVariantAnalysisQueryLanguage,
|
||||
VariantAnalysisQueryLanguage
|
||||
} from '../../src/remote-queries/shared/variant-analysis';
|
||||
import { VariantAnalysis, parseVariantAnalysisQueryLanguage, VariantAnalysisQueryLanguage, VariantAnalysisStatus, isVariantAnalysisComplete, VariantAnalysisRepoStatus, getActionsWorkflowRunUrl } from '../../src/remote-queries/shared/variant-analysis';
|
||||
import { createMockScannedRepo } from '../../src/vscode-tests/factories/remote-queries/shared/scanned-repositories';
|
||||
import { createMockVariantAnalysis } from '../../src/vscode-tests/factories/remote-queries/shared/variant-analysis';
|
||||
|
||||
describe('parseVariantAnalysisQueryLanguage', () => {
|
||||
@@ -16,6 +13,95 @@ describe('parseVariantAnalysisQueryLanguage', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('isVariantAnalysisComplete', async () => {
|
||||
let variantAnalysis: VariantAnalysis;
|
||||
const uncallableArtifactDownloadChecker = () => { throw new Error('Should not be called'); };
|
||||
|
||||
beforeEach(() => {
|
||||
variantAnalysis = createMockVariantAnalysis();
|
||||
});
|
||||
|
||||
describe('when variant analysis status is InProgress', async () => {
|
||||
beforeEach(() => {
|
||||
variantAnalysis.status = VariantAnalysisStatus.InProgress;
|
||||
});
|
||||
|
||||
describe('when scanned repos is undefined', async () => {
|
||||
it('should say the variant analysis is not complete', async () => {
|
||||
variantAnalysis.scannedRepos = undefined;
|
||||
expect(await isVariantAnalysisComplete(variantAnalysis, uncallableArtifactDownloadChecker)).to.equal(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when scanned repos is non-empty', async () => {
|
||||
describe('when not all results are downloaded', async () => {
|
||||
it('should say the variant analysis is not complete', async () => {
|
||||
expect(await isVariantAnalysisComplete(variantAnalysis, async () => false)).to.equal(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when all results are downloaded', async () => {
|
||||
it('should say the variant analysis is complete', async () => {
|
||||
expect(await isVariantAnalysisComplete(variantAnalysis, async () => true)).to.equal(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
for (const variantAnalysisStatus of [
|
||||
VariantAnalysisStatus.Succeeded,
|
||||
VariantAnalysisStatus.Failed,
|
||||
VariantAnalysisStatus.Canceled
|
||||
]) {
|
||||
describe(`when variant analysis status is ${variantAnalysisStatus}`, async () => {
|
||||
beforeEach(() => {
|
||||
variantAnalysis.status = variantAnalysisStatus;
|
||||
});
|
||||
|
||||
describe('when scanned repos is undefined', async () => {
|
||||
it('should say the variant analysis is complete', async () => {
|
||||
variantAnalysis.scannedRepos = undefined;
|
||||
expect(await isVariantAnalysisComplete(variantAnalysis, uncallableArtifactDownloadChecker)).to.equal(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when scanned repos is empty', async () => {
|
||||
it('should say the variant analysis is complete', async () => {
|
||||
variantAnalysis.scannedRepos = [];
|
||||
expect(await isVariantAnalysisComplete(variantAnalysis, uncallableArtifactDownloadChecker)).to.equal(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when a repo scan is still in progress', async () => {
|
||||
it('should say the variant analysis is not complete', async () => {
|
||||
variantAnalysis.scannedRepos = [
|
||||
createMockScannedRepo('in-progress-repo', false, VariantAnalysisRepoStatus.InProgress),
|
||||
];
|
||||
expect(await isVariantAnalysisComplete(variantAnalysis, async () => false)).to.equal(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when not all results are downloaded', async () => {
|
||||
it('should say the variant analysis is not complete', async () => {
|
||||
variantAnalysis.scannedRepos = [
|
||||
createMockScannedRepo('in-progress-repo', false, VariantAnalysisRepoStatus.Succeeded),
|
||||
];
|
||||
expect(await isVariantAnalysisComplete(variantAnalysis, async () => false)).to.equal(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when all results are downloaded', async () => {
|
||||
it('should say the variant analysis is complete', async () => {
|
||||
variantAnalysis.scannedRepos = [
|
||||
createMockScannedRepo('in-progress-repo', false, VariantAnalysisRepoStatus.Succeeded),
|
||||
];
|
||||
expect(await isVariantAnalysisComplete(variantAnalysis, async () => true)).to.equal(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
describe('getActionsWorkflowRunUrl', () => {
|
||||
it('should get the run url', () => {
|
||||
const variantAnalysis = createMockVariantAnalysis();
|
||||
|
||||
Reference in New Issue
Block a user