Skip to content

Commit 72253a1

Browse files
Merge branch 'main' into robertbrignull/skipped-repos
2 parents 529ceb1 + 2065c7d commit 72253a1

33 files changed

+2059
-233
lines changed

.github/workflows/main.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ jobs:
139139
strategy:
140140
matrix:
141141
os: [ubuntu-latest, windows-latest]
142-
version: ['v2.6.3', 'v2.7.6', 'v2.8.5', 'v2.9.4', 'v2.10.5', 'nightly']
142+
version: ['v2.6.3', 'v2.7.6', 'v2.8.5', 'v2.9.4', 'v2.10.5', 'v2.11.0', 'nightly']
143143
env:
144144
CLI_VERSION: ${{ matrix.version }}
145145
NIGHTLY_URL: ${{ needs.find-nightly.outputs.url }}

extensions/ql-vscode/package-lock.json

Lines changed: 368 additions & 104 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

extensions/ql-vscode/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1206,7 +1206,7 @@
12061206
},
12071207
"dependencies": {
12081208
"@octokit/plugin-retry": "^3.0.9",
1209-
"@octokit/rest": "^18.5.6",
1209+
"@octokit/rest": "^19.0.4",
12101210
"@primer/octicons-react": "^16.3.0",
12111211
"@primer/react": "^35.0.0",
12121212
"@vscode/codicons": "^0.0.31",
@@ -1246,6 +1246,7 @@
12461246
"devDependencies": {
12471247
"@babel/core": "^7.18.13",
12481248
"@babel/plugin-transform-modules-commonjs": "^7.18.6",
1249+
"@faker-js/faker": "^7.5.0",
12491250
"@storybook/addon-actions": "^6.5.10",
12501251
"@storybook/addon-essentials": "^6.5.10",
12511252
"@storybook/addon-interactions": "^6.5.10",

extensions/ql-vscode/src/extension.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,8 @@ import { createInitialQueryInfo } from './run-queries-shared';
105105
import { LegacyQueryRunner } from './legacy-query-server/legacyRunner';
106106
import { QueryRunner } from './queryRunner';
107107
import { VariantAnalysisView } from './remote-queries/variant-analysis-view';
108+
import { VariantAnalysisMonitor } from './remote-queries/variant-analysis-monitor';
109+
import { VariantAnalysis } from './remote-queries/shared/variant-analysis';
108110

109111
/**
110112
* extension.ts
@@ -894,6 +896,16 @@ async function activateWithInstalledDistribution(
894896
})
895897
);
896898

899+
const variantAnalysisMonitor = new VariantAnalysisMonitor(ctx, logger);
900+
ctx.subscriptions.push(
901+
commandRunner('codeQL.monitorVariantAnalysis', async (
902+
variantAnalysis: VariantAnalysis,
903+
token: CancellationToken
904+
) => {
905+
await variantAnalysisMonitor.monitorVariantAnalysis(variantAnalysis, token);
906+
})
907+
);
908+
897909
ctx.subscriptions.push(
898910
commandRunner('codeQL.autoDownloadRemoteQueryResults', async (
899911
queryResult: RemoteQueryResult,

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ export interface VariantAnalysisSkippedRepositoryGroup {
6262

6363
export interface VariantAnalysisNotFoundRepositoryGroup {
6464
repository_count: number,
65-
repository_nwos: string[]
65+
repository_full_names: string[]
6666
}
6767
export interface VariantAnalysisRepoTask {
6868
repository: Repository,

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

Lines changed: 9 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { CancellationToken, Uri, window } from 'vscode';
1+
import { CancellationToken, commands, Uri, window } from 'vscode';
22
import * as path from 'path';
33
import * as yaml from 'js-yaml';
44
import * as fs from 'fs-extra';
@@ -26,8 +26,9 @@ import { QueryMetadata } from '../pure/interface-types';
2626
import { getErrorMessage, REPO_REGEX } from '../pure/helpers-pure';
2727
import * as ghApiClient from './gh-api/gh-api-client';
2828
import { getRepositorySelection, isValidSelection, RepositorySelection } from './repository-selection';
29-
import { parseVariantAnalysisQueryLanguage, VariantAnalysis, VariantAnalysisStatus, VariantAnalysisSubmission } from './shared/variant-analysis';
29+
import { parseVariantAnalysisQueryLanguage, VariantAnalysisSubmission } from './shared/variant-analysis';
3030
import { Repository } from './shared/repository';
31+
import { processVariantAnalysis } from './variant-analysis-processor';
3132

3233
export interface QlPack {
3334
name: string;
@@ -270,28 +271,15 @@ export async function runRemoteQuery(
270271
variantAnalysisSubmission
271272
);
272273

273-
const variantAnalysis: VariantAnalysis = {
274-
id: variantAnalysisResponse.id,
275-
controllerRepoId: variantAnalysisResponse.controller_repo.id,
276-
query: {
277-
name: variantAnalysisSubmission.query.name,
278-
filePath: variantAnalysisSubmission.query.filePath,
279-
language: variantAnalysisSubmission.query.language,
280-
},
281-
databases: {
282-
repositories: variantAnalysisSubmission.databases.repositories,
283-
repositoryLists: variantAnalysisSubmission.databases.repositoryLists,
284-
repositoryOwners: variantAnalysisSubmission.databases.repositoryOwners,
285-
},
286-
status: VariantAnalysisStatus.InProgress,
287-
};
274+
const processedVariantAnalysis = processVariantAnalysis(variantAnalysisSubmission, variantAnalysisResponse);
288275

289276
// TODO: Remove once we have a proper notification
290277
void showAndLogInformationMessage('Variant analysis submitted for processing');
291-
void logger.log(`Variant analysis:\n${JSON.stringify(variantAnalysis, null, 2)}`);
278+
void logger.log(`Variant analysis:\n${JSON.stringify(processedVariantAnalysis, null, 2)}`);
292279

293-
return { variantAnalysis };
280+
void commands.executeCommand('codeQL.monitorVariantAnalysis', processedVariantAnalysis);
294281

282+
return { variantAnalysis: processedVariantAnalysis };
295283
} else {
296284
const apiResponse = await runRemoteQueriesApiRequest(credentials, actionBranch, language, repoSelection, controllerRepo, base64Pack, dryRun);
297285

@@ -361,9 +349,9 @@ async function runRemoteQueriesApiRequest(
361349
try {
362350
const octokit = await credentials.getOctokit();
363351
const response: OctokitResponse<QueriesResponse, number> = await octokit.request(
364-
'POST /repos/:controllerRepo/code-scanning/codeql/queries',
352+
'POST /repositories/:controllerRepoId/code-scanning/codeql/queries',
365353
{
366-
controllerRepo: controllerRepo.fullName,
354+
controllerRepoId: controllerRepo.id,
367355
data
368356
}
369357
);
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { VariantAnalysis } from './variant-analysis';
2+
3+
export type VariantAnalysisMonitorStatus =
4+
| 'InProgress'
5+
| 'CompletedSuccessfully'
6+
| 'CompletedUnsuccessfully'
7+
| 'Failed'
8+
| 'Cancelled'
9+
| 'TimedOut';
10+
11+
export interface VariantAnalysisMonitorResult {
12+
status: VariantAnalysisMonitorStatus;
13+
error?: string;
14+
scannedReposDownloaded?: number[],
15+
variantAnalysis?: VariantAnalysis
16+
}

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

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Repository } from './repository';
2+
import { AnalysisAlert, AnalysisRawResults } from './analysis-result';
23

34
export interface VariantAnalysis {
45
id: number,
@@ -81,6 +82,12 @@ export interface VariantAnalysisSkippedRepository {
8182
private?: boolean,
8283
}
8384

85+
export interface VariantAnalysisScannedRepositoryResult {
86+
repositoryId: number;
87+
interpretedResults?: AnalysisAlert[];
88+
rawResults?: AnalysisRawResults;
89+
}
90+
8491
/**
8592
* Captures information needed to submit a variant
8693
* analysis for processing.
@@ -105,16 +112,24 @@ export interface VariantAnalysisSubmission {
105112
}
106113

107114
/**
108-
* @param repo
109-
* @returns whether the repo scan is in a completed state, i.e. it cannot normally change state anymore
115+
* @param status
116+
* @returns whether the status is in a completed state, i.e. it cannot normally change state anymore
110117
*/
111-
export function hasRepoScanCompleted(repo: VariantAnalysisScannedRepository): boolean {
118+
export function isCompletedAnalysisRepoStatus(status: VariantAnalysisRepoStatus): boolean {
112119
return [
113120
// All states that indicates the repository has been scanned and cannot
114121
// change status anymore.
115122
VariantAnalysisRepoStatus.Succeeded, VariantAnalysisRepoStatus.Failed,
116123
VariantAnalysisRepoStatus.Canceled, VariantAnalysisRepoStatus.TimedOut,
117-
].includes(repo.analysisStatus);
124+
].includes(status);
125+
}
126+
127+
/**
128+
* @param repo
129+
* @returns whether the repo scan is in a completed state, i.e. it cannot normally change state anymore
130+
*/
131+
export function hasRepoScanCompleted(repo: VariantAnalysisScannedRepository): boolean {
132+
return isCompletedAnalysisRepoStatus(repo.analysisStatus);
118133
}
119134

120135
/**
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import * as vscode from 'vscode';
2+
import { Credentials } from '../authentication';
3+
import { Logger } from '../logging';
4+
import * as ghApiClient from './gh-api/gh-api-client';
5+
6+
import { VariantAnalysis, VariantAnalysisStatus } from './shared/variant-analysis';
7+
import {
8+
VariantAnalysis as VariantAnalysisApiResponse
9+
} from './gh-api/variant-analysis';
10+
import { VariantAnalysisMonitorResult } from './shared/variant-analysis-monitor-result';
11+
import { processFailureReason } from './variant-analysis-processor';
12+
13+
export class VariantAnalysisMonitor {
14+
// With a sleep of 5 seconds, the maximum number of attempts takes
15+
// us to just over 2 days worth of monitoring.
16+
public static maxAttemptCount = 17280;
17+
public static sleepTime = 5000;
18+
19+
constructor(
20+
private readonly extensionContext: vscode.ExtensionContext,
21+
private readonly logger: Logger
22+
) {
23+
}
24+
25+
public async monitorVariantAnalysis(
26+
variantAnalysis: VariantAnalysis,
27+
cancellationToken: vscode.CancellationToken
28+
): Promise<VariantAnalysisMonitorResult> {
29+
30+
const credentials = await Credentials.initialize(this.extensionContext);
31+
if (!credentials) {
32+
throw Error('Error authenticating with GitHub');
33+
}
34+
35+
let variantAnalysisSummary: VariantAnalysisApiResponse;
36+
let attemptCount = 0;
37+
const scannedReposDownloaded: number[] = [];
38+
39+
while (attemptCount <= VariantAnalysisMonitor.maxAttemptCount) {
40+
await this.sleep(VariantAnalysisMonitor.sleepTime);
41+
42+
if (cancellationToken && cancellationToken.isCancellationRequested) {
43+
return { status: 'Cancelled', error: 'Variant Analysis was canceled.' };
44+
}
45+
46+
variantAnalysisSummary = await ghApiClient.getVariantAnalysis(
47+
credentials,
48+
variantAnalysis.controllerRepoId,
49+
variantAnalysis.id
50+
);
51+
52+
if (variantAnalysisSummary.failure_reason) {
53+
variantAnalysis.status = VariantAnalysisStatus.Failed;
54+
variantAnalysis.failureReason = processFailureReason(variantAnalysisSummary.failure_reason);
55+
return {
56+
status: 'Failed',
57+
error: `Variant Analysis has failed: ${variantAnalysisSummary.failure_reason}`,
58+
variantAnalysis: variantAnalysis
59+
};
60+
}
61+
62+
void this.logger.log('****** Retrieved variant analysis' + JSON.stringify(variantAnalysisSummary));
63+
64+
if (variantAnalysisSummary.scanned_repositories) {
65+
variantAnalysisSummary.scanned_repositories.forEach(scannedRepo => {
66+
if (!scannedReposDownloaded.includes(scannedRepo.repository.id) && scannedRepo.analysis_status === 'succeeded') {
67+
scannedReposDownloaded.push(scannedRepo.repository.id);
68+
}
69+
});
70+
}
71+
72+
if (variantAnalysisSummary.status === 'completed') {
73+
break;
74+
}
75+
76+
attemptCount++;
77+
}
78+
79+
return { status: 'CompletedSuccessfully', scannedReposDownloaded: scannedReposDownloaded };
80+
}
81+
82+
private async sleep(ms: number) {
83+
return new Promise(resolve => setTimeout(resolve, ms));
84+
}
85+
}

0 commit comments

Comments
 (0)