Skip to content

Commit 84048cc

Browse files
author
Dave Bartolomeo
committed
Merge remote-tracking branch 'origin/main' into dbartol/goto-ql
2 parents 49a1576 + 2cf5b39 commit 84048cc

35 files changed

Lines changed: 1095 additions & 141 deletions

extensions/ql-vscode/package-lock.json

Lines changed: 40 additions & 0 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: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@
231231
},
232232
"codeQL.queryHistory.format": {
233233
"type": "string",
234-
"default": "%q on %d - %s, %r [%t]",
234+
"default": "%q on %d - %s %r [%t]",
235235
"markdownDescription": "Default string for how to label query history items.\n* %t is the time of the query\n* %q is the human-readable query name\n* %f is the query file name\n* %d is the database name\n* %r is the number of results\n* %s is a status string"
236236
},
237237
"codeQL.queryHistory.ttl": {
@@ -1160,8 +1160,10 @@
11601160
},
11611161
"dependencies": {
11621162
"@octokit/rest": "^18.5.6",
1163+
"@octokit/plugin-retry": "^3.0.9",
11631164
"@primer/octicons-react": "^16.3.0",
11641165
"@primer/react": "^35.0.0",
1166+
"@vscode/codicons": "^0.0.31",
11651167
"@vscode/webview-ui-toolkit": "^1.0.0",
11661168
"child-process-promise": "^2.2.1",
11671169
"classnames": "~2.2.6",
@@ -1177,8 +1179,8 @@
11771179
"react": "^17.0.2",
11781180
"react-dom": "^17.0.2",
11791181
"semver": "~7.3.2",
1180-
"source-map-support": "^0.5.21",
11811182
"source-map": "^0.7.4",
1183+
"source-map-support": "^0.5.21",
11821184
"stream": "^0.0.2",
11831185
"stream-chain": "~2.2.4",
11841186
"stream-json": "~1.7.3",

extensions/ql-vscode/src/authentication.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import * as vscode from 'vscode';
22
import * as Octokit from '@octokit/rest';
3+
import { retry } from '@octokit/plugin-retry';
34

45
const GITHUB_AUTH_PROVIDER_ID = 'github';
56

@@ -51,14 +52,15 @@ export class Credentials {
5152

5253
private async createOctokit(createIfNone: boolean, overrideToken?: string): Promise<Octokit.Octokit | undefined> {
5354
if (overrideToken) {
54-
return new Octokit.Octokit({ auth: overrideToken });
55+
return new Octokit.Octokit({ auth: overrideToken, retry });
5556
}
5657

5758
const session = await vscode.authentication.getSession(GITHUB_AUTH_PROVIDER_ID, SCOPES, { createIfNone });
5859

5960
if (session) {
6061
return new Octokit.Octokit({
61-
auth: session.accessToken
62+
auth: session.accessToken,
63+
retry
6264
});
6365
} else {
6466
return undefined;

extensions/ql-vscode/src/cli.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -690,6 +690,23 @@ export class CodeQLCliServer implements Disposable {
690690
return await this.runCodeQlCliCommand(['generate', 'log-summary'], subcommandArgs, 'Generating log summary');
691691
}
692692

693+
/**
694+
* Generate a JSON summary of an evaluation log.
695+
* @param inputPath The path of an evaluation event log.
696+
* @param outputPath The path to write a JSON summary of it to.
697+
*/
698+
async generateJsonLogSummary(
699+
inputPath: string,
700+
outputPath: string,
701+
): Promise<string> {
702+
const subcommandArgs = [
703+
'--format=predicates',
704+
inputPath,
705+
outputPath
706+
];
707+
return await this.runCodeQlCliCommand(['generate', 'log-summary'], subcommandArgs, 'Generating JSON log summary');
708+
}
709+
693710
/**
694711
* Gets the results from a bqrs.
695712
* @param bqrsPath The path to the bqrs.

extensions/ql-vscode/src/config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ const PERSONAL_ACCESS_TOKEN_SETTING = new Setting('personalAccessToken', DISTRIB
5959
// Query History configuration
6060
const QUERY_HISTORY_SETTING = new Setting('queryHistory', ROOT_SETTING);
6161
const QUERY_HISTORY_FORMAT_SETTING = new Setting('format', QUERY_HISTORY_SETTING);
62-
const QUERY_HISTORY_TTL = new Setting('format', QUERY_HISTORY_SETTING);
62+
const QUERY_HISTORY_TTL = new Setting('ttl', QUERY_HISTORY_SETTING);
6363

6464
/** When these settings change, the distribution should be updated. */
6565
const DISTRIBUTION_CHANGE_SETTINGS = [CUSTOM_CODEQL_PATH_SETTING, INCLUDE_PRERELEASE_SETTING, PERSONAL_ACCESS_TOKEN_SETTING];

extensions/ql-vscode/src/helpers.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -581,3 +581,11 @@ export async function* walkDirectory(dir: string): AsyncIterableIterator<string>
581581
}
582582
}
583583
}
584+
585+
/**
586+
* Pluralizes a word.
587+
* Example: Returns "N repository" if N is one, "N repositories" otherwise.
588+
*/
589+
export function pluralize(numItems: number | undefined, singular: string, plural: string): string {
590+
return numItems ? `${numItems} ${numItems === 1 ? singular : plural}` : '';
591+
}

extensions/ql-vscode/src/history-item-label-provider.ts

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import * as path from 'path';
33
import { QueryHistoryConfig } from './config';
44
import { LocalQueryInfo, QueryHistoryInfo } from './query-results';
55
import { RemoteQueryHistoryItem } from './remote-queries/remote-query-history-item';
6+
import { pluralize } from './helpers';
67

78
interface InterpolateReplacements {
89
t: string; // Start time
@@ -57,23 +58,30 @@ export class HistoryItemLabelProvider {
5758
t: item.startTime,
5859
q: item.getQueryName(),
5960
d: item.initialInfo.databaseInfo.name,
60-
r: `${resultCount} results`,
61+
r: `(${resultCount} results)`,
6162
s: statusString,
6263
f: item.getQueryFileName(),
6364
'%': '%',
6465
};
6566
}
6667

68+
// Return the number of repositories queried if available. Otherwise, use the controller repository name.
69+
private buildRepoLabel(item: RemoteQueryHistoryItem): string {
70+
const repositoryCount = item.remoteQuery.repositoryCount;
71+
72+
if (repositoryCount) {
73+
return pluralize(repositoryCount, 'repository', 'repositories');
74+
}
75+
76+
return `${item.remoteQuery.controllerRepository.owner}/${item.remoteQuery.controllerRepository.name}`;
77+
}
78+
6779
private getRemoteInterpolateReplacements(item: RemoteQueryHistoryItem): InterpolateReplacements {
6880
return {
6981
t: new Date(item.remoteQuery.executionStartTime).toLocaleString(env.language),
70-
q: item.remoteQuery.queryName,
71-
72-
// There is no database name for remote queries. Instead use the controller repository name.
73-
d: `${item.remoteQuery.controllerRepository.owner}/${item.remoteQuery.controllerRepository.name}`,
74-
75-
// There is no synchronous way to get the results count.
76-
r: '',
82+
q: `${item.remoteQuery.queryName} (${item.remoteQuery.language})`,
83+
d: this.buildRepoLabel(item),
84+
r: `(${pluralize(item.resultCount, 'result', 'results')})`,
7785
s: item.status,
7886
f: path.basename(item.remoteQuery.queryFilePath),
7987
'%': '%'

extensions/ql-vscode/src/interface-utils.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,8 @@ export function getHtmlForWebview(
137137
? `${webview.cspSource} vscode-file: 'unsafe-inline'`
138138
: `'nonce-${nonce}'`;
139139

140+
const fontSrc = webview.cspSource;
141+
140142
/*
141143
* Content security policy:
142144
* default-src: allow nothing by default.
@@ -149,7 +151,7 @@ export function getHtmlForWebview(
149151
<html>
150152
<head>
151153
<meta http-equiv="Content-Security-Policy"
152-
content="default-src 'none'; script-src 'nonce-${nonce}'; style-src ${styleSrc}; connect-src ${webview.cspSource};">
154+
content="default-src 'none'; script-src 'nonce-${nonce}'; font-src ${fontSrc}; style-src ${styleSrc}; connect-src ${webview.cspSource};">
153155
${stylesheetsHtmlLines.join(` ${os.EOL}`)}
154156
</head>
155157
<body>
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import * as os from 'os';
2+
3+
// TODO(angelapwen): Only load in necessary information and
4+
// location in bytes for this log to save memory.
5+
export interface EvaluatorLogData {
6+
queryCausingWork: string;
7+
predicateName: string;
8+
millis: number;
9+
resultSize: number;
10+
ra: Pipelines;
11+
}
12+
13+
interface Pipelines {
14+
// Key: pipeline identifier; Value: array of pipeline steps
15+
pipelineNamesToSteps: Map<string, string[]>;
16+
}
17+
18+
/**
19+
* A pure method that parses a string of evaluator log summaries into
20+
* an array of EvaluatorLogData objects.
21+
*
22+
*/
23+
export function parseVisualizerData(logSummary: string): EvaluatorLogData[] {
24+
// Remove newline delimiters because summary is in .jsonl format.
25+
const jsonSummaryObjects: string[] = logSummary.split(os.EOL + os.EOL);
26+
const visualizerData: EvaluatorLogData[] = [];
27+
28+
for (const obj of jsonSummaryObjects) {
29+
const jsonObj = JSON.parse(obj);
30+
31+
// Only convert log items that have an RA and millis field
32+
if (jsonObj.ra !== undefined && jsonObj.millis !== undefined) {
33+
const newLogData: EvaluatorLogData = {
34+
queryCausingWork: jsonObj.queryCausingWork,
35+
predicateName: jsonObj.predicateName,
36+
millis: jsonObj.millis,
37+
resultSize: jsonObj.resultSize,
38+
ra: jsonObj.ra
39+
};
40+
visualizerData.push(newLogData);
41+
}
42+
}
43+
return visualizerData;
44+
}

extensions/ql-vscode/src/query-history-scrubber.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import * as os from 'os';
33
import * as path from 'path';
44
import { Disposable, ExtensionContext } from 'vscode';
55
import { logger } from './logging';
6+
import { QueryHistoryManager } from './query-history';
67

78
const LAST_SCRUB_TIME_KEY = 'lastScrubTime';
89

@@ -30,12 +31,13 @@ export function registerQueryHistoryScubber(
3031
throttleTime: number,
3132
maxQueryTime: number,
3233
queryDirectory: string,
34+
qhm: QueryHistoryManager,
3335
ctx: ExtensionContext,
3436

3537
// optional counter to keep track of how many times the scrubber has run
3638
counter?: Counter
3739
): Disposable {
38-
const deregister = setInterval(scrubQueries, wakeInterval, throttleTime, maxQueryTime, queryDirectory, ctx, counter);
40+
const deregister = setInterval(scrubQueries, wakeInterval, throttleTime, maxQueryTime, queryDirectory, qhm, ctx, counter);
3941

4042
return {
4143
dispose: () => {
@@ -48,6 +50,7 @@ async function scrubQueries(
4850
throttleTime: number,
4951
maxQueryTime: number,
5052
queryDirectory: string,
53+
qhm: QueryHistoryManager,
5154
ctx: ExtensionContext,
5255
counter?: Counter
5356
) {
@@ -89,6 +92,7 @@ async function scrubQueries(
8992
} finally {
9093
void logger.log(`Scrubbed ${scrubCount} old queries.`);
9194
}
95+
await qhm.removeDeletedQueries();
9296
}
9397
}
9498

0 commit comments

Comments
 (0)