Skip to content

Commit 0aa3114

Browse files
authored
Merge branch 'main' into snippets
2 parents db33630 + dbaed3a commit 0aa3114

6 files changed

Lines changed: 93 additions & 12 deletions

File tree

extensions/ql-vscode/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
- Implement sorting of the query history view by name, date, and results count. [#777](https://github.com/github/vscode-codeql/pull/777)
1010
- Add a configuration option to pass additional arguments to the CLI when running tests. [#785](https://github.com/github/vscode-codeql/pull/785)
1111
- Add some snippets for commonly used QL statements. [#782](https://github.com/github/vscode-codeql/pull/782)
12+
- Introduce option to view query results as CSV. [#784](https://github.com/github/vscode-codeql/pull/784)
1213

1314
## 1.4.3 - 22 February 2021
1415

extensions/ql-vscode/package.json

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -402,8 +402,12 @@
402402
"title": "Show Query Text"
403403
},
404404
{
405-
"command": "codeQLQueryHistory.viewSarif",
406-
"title": "View SARIF"
405+
"command": "codeQLQueryHistory.viewCsvResults",
406+
"title": "View Results (CSV)"
407+
},
408+
{
409+
"command": "codeQLQueryHistory.viewSarifResults",
410+
"title": "View Results (SARIF)"
407411
},
408412
{
409413
"command": "codeQLQueryHistory.viewDil",
@@ -575,7 +579,12 @@
575579
"when": "view == codeQLQueryHistory"
576580
},
577581
{
578-
"command": "codeQLQueryHistory.viewSarif",
582+
"command": "codeQLQueryHistory.viewCsvResults",
583+
"group": "9_qlCommands",
584+
"when": "view == codeQLQueryHistory && viewItem == interpretedResultsItem"
585+
},
586+
{
587+
"command": "codeQLQueryHistory.viewSarifResults",
579588
"group": "9_qlCommands",
580589
"when": "view == codeQLQueryHistory && viewItem == interpretedResultsItem"
581590
},
@@ -702,7 +711,11 @@
702711
"when": "false"
703712
},
704713
{
705-
"command": "codeQLQueryHistory.viewSarif",
714+
"command": "codeQLQueryHistory.viewCsvResults",
715+
"when": "false"
716+
},
717+
{
718+
"command": "codeQLQueryHistory.viewSarifResults",
706719
"when": "false"
707720
},
708721
{

extensions/ql-vscode/src/cli.ts

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ import { CompilationMessage } from './pure/messages';
2525
*/
2626
const SARIF_FORMAT = 'sarifv2.1.0';
2727

28+
/**
29+
* The string used to specify CSV format.
30+
*/
31+
const CSV_FORMAT = 'csv';
32+
2833
/**
2934
* Flags to pass to all cli commands.
3035
*/
@@ -582,18 +587,20 @@ export class CodeQLCliServer implements Disposable {
582587
return await this.runJsonCodeQlCliCommand<DecodedBqrsChunk>(['bqrs', 'decode'], subcommandArgs, 'Reading bqrs data');
583588
}
584589

585-
async interpretBqrs(metadata: { kind: string; id: string; scored?: string }, resultsPath: string, interpretedResultsPath: string, sourceInfo?: SourceInfo): Promise<sarif.Log> {
590+
async runInterpretCommand(format: string, metadata: QueryMetadata, resultsPath: string, interpretedResultsPath: string, sourceInfo?: SourceInfo) {
586591
const args = [
587592
`-t=kind=${metadata.kind}`,
588593
`-t=id=${metadata.id}`,
589594
'--output', interpretedResultsPath,
590-
'--format', SARIF_FORMAT,
595+
'--format', format,
596+
];
597+
if (format == SARIF_FORMAT) {
591598
// TODO: This flag means that we don't group interpreted results
592599
// by primary location. We may want to revisit whether we call
593600
// interpretation with and without this flag, or do some
594601
// grouping client-side.
595-
'--no-group-results',
596-
];
602+
args.push('--no-group-results');
603+
}
597604
if (config.isCanary() && metadata.scored !== undefined) {
598605
args.push(`-t=scored=${metadata.scored}`);
599606
}
@@ -611,6 +618,10 @@ export class CodeQLCliServer implements Disposable {
611618

612619
args.push(resultsPath);
613620
await this.runCodeQlCliCommand(['bqrs', 'interpret'], args, 'Interpreting query results');
621+
}
622+
623+
async interpretBqrs(metadata: QueryMetadata, resultsPath: string, interpretedResultsPath: string, sourceInfo?: SourceInfo): Promise<sarif.Log> {
624+
await this.runInterpretCommand(SARIF_FORMAT, metadata, resultsPath, interpretedResultsPath, sourceInfo);
614625

615626
let output: string;
616627
try {
@@ -629,6 +640,9 @@ export class CodeQLCliServer implements Disposable {
629640
}
630641
}
631642

643+
async generateResultsCsv(metadata: QueryMetadata, resultsPath: string, csvPath: string, sourceInfo?: SourceInfo): Promise<void> {
644+
await this.runInterpretCommand(CSV_FORMAT, metadata, resultsPath, csvPath, sourceInfo);
645+
}
632646

633647
async sortBqrs(resultsPath: string, sortedResultsPath: string, resultSet: string, sortKeys: number[], sortDirections: SortDirection[]): Promise<void> {
634648
const sortDirectionStrings = sortDirections.map(direction => {

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

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -306,8 +306,14 @@ export class QueryHistoryManager extends DisposableObject {
306306
);
307307
this.push(
308308
commandRunner(
309-
'codeQLQueryHistory.viewSarif',
310-
this.handleViewSarif.bind(this)
309+
'codeQLQueryHistory.viewCsvResults',
310+
this.handleViewCsvResults.bind(this)
311+
)
312+
);
313+
this.push(
314+
commandRunner(
315+
'codeQLQueryHistory.viewSarifResults',
316+
this.handleViewSarifResults.bind(this)
311317
)
312318
);
313319
this.push(
@@ -544,7 +550,7 @@ export class QueryHistoryManager extends DisposableObject {
544550
await vscode.window.showTextDocument(doc, { preview: false });
545551
}
546552

547-
async handleViewSarif(
553+
async handleViewSarifResults(
548554
singleItem: CompletedQuery,
549555
multiSelect: CompletedQuery[]
550556
) {
@@ -565,6 +571,19 @@ export class QueryHistoryManager extends DisposableObject {
565571
}
566572
}
567573

574+
async handleViewCsvResults(
575+
singleItem: CompletedQuery,
576+
multiSelect: CompletedQuery[]
577+
) {
578+
if (!this.assertSingleQuery(multiSelect)) {
579+
return;
580+
}
581+
582+
await this.tryOpenExternalFile(
583+
await singleItem.query.ensureCsvProduced(this.qs)
584+
);
585+
}
586+
568587
async handleViewDil(
569588
singleItem: CompletedQuery,
570589
multiSelect: CompletedQuery[],
@@ -778,3 +797,4 @@ the file in the file explorer and dragging it into the workspace.`
778797
this.treeDataProvider.refresh(completedQuery);
779798
}
780799
}
800+

extensions/ql-vscode/src/query-results.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,10 @@ export async function interpretResults(
179179
if (await fs.pathExists(interpretedResultsPath)) {
180180
return JSON.parse(await fs.readFile(interpretedResultsPath, 'utf8'));
181181
}
182+
return await server.interpretBqrs(ensureMetadataIsComplete(metadata), resultsPath, interpretedResultsPath, sourceInfo);
183+
}
184+
185+
export function ensureMetadataIsComplete(metadata: QueryMetadata | undefined) {
182186
if (metadata === undefined) {
183187
throw new Error('Can\'t interpret results without query metadata');
184188
}
@@ -191,5 +195,5 @@ export async function interpretResults(
191195
// SARIF format does, so in the absence of one, we use a dummy id.
192196
id = 'dummy-id';
193197
}
194-
return await server.interpretBqrs({ kind, id, scored }, resultsPath, interpretedResultsPath, sourceInfo);
198+
return { kind, id, scored };
195199
}

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

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import { QueryHistoryItemOptions } from './query-history';
2424
import * as qsClient from './queryserver-client';
2525
import { isQuickQueryPath } from './quick-query';
2626
import { compileDatabaseUpgradeSequence, hasNondestructiveUpgradeCapabilities, upgradeDatabaseExplicit } from './upgrades';
27+
import { ensureMetadataIsComplete } from './query-results';
2728

2829
/**
2930
* run-queries.ts
@@ -53,6 +54,7 @@ export class QueryInfo {
5354

5455
readonly compiledQueryPath: string;
5556
readonly dilPath: string;
57+
readonly csvPath: string;
5658
readonly resultsPaths: ResultsPaths;
5759
readonly dataset: Uri; // guarantee the existence of a well-defined dataset dir at this point
5860
readonly queryID: number;
@@ -68,6 +70,7 @@ export class QueryInfo {
6870
this.queryID = QueryInfo.nextQueryId++;
6971
this.compiledQueryPath = path.join(tmpDir.name, `compiledQuery${this.queryID}.qlo`);
7072
this.dilPath = path.join(tmpDir.name, `results${this.queryID}.dil`);
73+
this.csvPath = path.join(tmpDir.name, `results${this.queryID}.csv`);
7174
this.resultsPaths = {
7275
resultsPath: path.join(tmpDir.name, `results${this.queryID}.bqrs`),
7376
interpretedResultsPath: path.join(tmpDir.name, `interpretedResults${this.queryID}.sarif`)
@@ -183,6 +186,13 @@ export class QueryInfo {
183186
return fs.pathExists(this.dilPath);
184187
}
185188

189+
/**
190+
* Holds if this query already has CSV results produced
191+
*/
192+
async hasCsv(): Promise<boolean> {
193+
return fs.pathExists(this.csvPath);
194+
}
195+
186196
async ensureDilPath(qs: qsClient.QueryServerClient): Promise<string> {
187197
if (await this.hasDil()) {
188198
return this.dilPath;
@@ -198,8 +208,27 @@ export class QueryInfo {
198208
return this.dilPath;
199209
}
200210

211+
async ensureCsvProduced(qs: qsClient.QueryServerClient): Promise<string> {
212+
if (await this.hasCsv()) {
213+
return this.csvPath;
214+
}
215+
216+
let sourceInfo;
217+
if (this.dbItem.sourceArchive !== undefined) {
218+
sourceInfo = {
219+
sourceArchive: this.dbItem.sourceArchive.fsPath,
220+
sourceLocationPrefix: await this.dbItem.getSourceLocationPrefix(
221+
qs.cliServer
222+
),
223+
};
224+
}
225+
226+
await qs.cliServer.generateResultsCsv(ensureMetadataIsComplete(this.metadata), this.resultsPaths.resultsPath, this.csvPath, sourceInfo);
227+
return this.csvPath;
228+
}
201229
}
202230

231+
203232
export interface QueryWithResults {
204233
readonly query: QueryInfo;
205234
readonly result: messages.EvaluationResult;

0 commit comments

Comments
 (0)