Allow exporting of results for non-alert queries
This commit is contained in:
committed by
Edoardo Pirovano
parent
089b23f0aa
commit
2561db1721
@@ -3,6 +3,7 @@
|
||||
## [UNRELEASED]
|
||||
|
||||
- Add support for filename pattern in history view. [#930](https://github.com/github/vscode-codeql/pull/930)
|
||||
- Add an option _Export Results (CSV)_ to export the results of a non-alert query. The existing options for alert queries have been renamed to _View Alerts_ to avoid confusion. [#929](https://github.com/github/vscode-codeql/pull/929)
|
||||
|
||||
## 1.5.3 - 18 August 2021
|
||||
|
||||
|
||||
@@ -461,13 +461,17 @@
|
||||
"command": "codeQLQueryHistory.showQueryText",
|
||||
"title": "Show Query Text"
|
||||
},
|
||||
{
|
||||
"command": "codeQLQueryHistory.exportCsvResults",
|
||||
"title": "Export Results (CSV)"
|
||||
},
|
||||
{
|
||||
"command": "codeQLQueryHistory.viewCsvResults",
|
||||
"title": "View Results (CSV)"
|
||||
"title": "View Alerts (CSV)"
|
||||
},
|
||||
{
|
||||
"command": "codeQLQueryHistory.viewSarifResults",
|
||||
"title": "View Results (SARIF)"
|
||||
"title": "View Alerts (SARIF)"
|
||||
},
|
||||
{
|
||||
"command": "codeQLQueryHistory.viewDil",
|
||||
@@ -643,6 +647,11 @@
|
||||
"group": "9_qlCommands",
|
||||
"when": "view == codeQLQueryHistory"
|
||||
},
|
||||
{
|
||||
"command": "codeQLQueryHistory.exportCsvResults",
|
||||
"group": "9_qlCommands",
|
||||
"when": "view == codeQLQueryHistory && viewItem != interpretedResultsItem"
|
||||
},
|
||||
{
|
||||
"command": "codeQLQueryHistory.viewCsvResults",
|
||||
"group": "9_qlCommands",
|
||||
@@ -800,6 +809,10 @@
|
||||
"command": "codeQLQueryHistory.showQueryText",
|
||||
"when": "false"
|
||||
},
|
||||
{
|
||||
"command": "codeQLQueryHistory.exportCsvResults",
|
||||
"when": "false"
|
||||
},
|
||||
{
|
||||
"command": "codeQLQueryHistory.viewCsvResults",
|
||||
"when": "false"
|
||||
|
||||
@@ -12,7 +12,7 @@ import { ProgressCallback } from '../commandRunner';
|
||||
import { KeyType } from './keyType';
|
||||
import { qlpackOfDatabase, resolveQueries } from './queryResolver';
|
||||
|
||||
const SELECT_QUERY_NAME = '#select';
|
||||
export const SELECT_QUERY_NAME = '#select';
|
||||
export const TEMPLATE_NAME = 'selectedSourceFile';
|
||||
|
||||
export interface FullLocationLink extends vscode.LocationLink {
|
||||
|
||||
@@ -304,6 +304,12 @@ export class QueryHistoryManager extends DisposableObject {
|
||||
this.handleShowQueryText.bind(this)
|
||||
)
|
||||
);
|
||||
this.push(
|
||||
commandRunner(
|
||||
'codeQLQueryHistory.exportCsvResults',
|
||||
this.handleExportCsvResults.bind(this)
|
||||
)
|
||||
);
|
||||
this.push(
|
||||
commandRunner(
|
||||
'codeQLQueryHistory.viewCsvResults',
|
||||
@@ -571,6 +577,32 @@ export class QueryHistoryManager extends DisposableObject {
|
||||
}
|
||||
}
|
||||
|
||||
async handleExportCsvResults(
|
||||
singleItem: CompletedQuery,
|
||||
multiSelect: CompletedQuery[]
|
||||
) {
|
||||
if (!this.assertSingleQuery(multiSelect)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const saveLocation = await vscode.window.showSaveDialog({
|
||||
title: 'CSV Results',
|
||||
saveLabel: 'Export',
|
||||
filters: {
|
||||
'Comma-separated values': ['csv'],
|
||||
}
|
||||
});
|
||||
if (!saveLocation) {
|
||||
void showAndLogErrorMessage('No save location selected for CSV export!');
|
||||
return;
|
||||
}
|
||||
await singleItem.query.exportCsvResults(this.qs, saveLocation.fsPath, () => {
|
||||
void this.tryOpenExternalFile(
|
||||
saveLocation.fsPath
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
async handleViewCsvResults(
|
||||
singleItem: CompletedQuery,
|
||||
multiSelect: CompletedQuery[]
|
||||
|
||||
@@ -25,6 +25,8 @@ import * as qsClient from './queryserver-client';
|
||||
import { isQuickQueryPath } from './quick-query';
|
||||
import { compileDatabaseUpgradeSequence, hasNondestructiveUpgradeCapabilities, upgradeDatabaseExplicit } from './upgrades';
|
||||
import { ensureMetadataIsComplete } from './query-results';
|
||||
import { SELECT_QUERY_NAME } from './contextual/locationFinder';
|
||||
import { DecodedBqrsChunk } from './pure/bqrs-cli-types';
|
||||
|
||||
/**
|
||||
* run-queries.ts
|
||||
@@ -216,6 +218,29 @@ export class QueryInfo {
|
||||
return this.dilPath;
|
||||
}
|
||||
|
||||
async exportCsvResults(qs: qsClient.QueryServerClient, csvPath: string, onFinish: () => void): Promise<void> {
|
||||
let stopDecoding = false;
|
||||
const out = fs.createWriteStream(csvPath);
|
||||
out.on('finish', onFinish);
|
||||
out.on('error', () => {
|
||||
if (!stopDecoding) {
|
||||
stopDecoding = true;
|
||||
void showAndLogErrorMessage(`Failed to write CSV results to ${csvPath}`);
|
||||
}
|
||||
});
|
||||
let nextOffset: number | undefined = 0;
|
||||
while (nextOffset !== undefined && !stopDecoding) {
|
||||
const chunk: DecodedBqrsChunk = await qs.cliServer.bqrsDecode(this.resultsPaths.resultsPath, SELECT_QUERY_NAME, {
|
||||
pageSize: 100,
|
||||
offset: nextOffset,
|
||||
});
|
||||
for (const tuple of chunk.tuples)
|
||||
out.write(tuple.join(',') + '\n');
|
||||
nextOffset = chunk.next;
|
||||
}
|
||||
out.end();
|
||||
}
|
||||
|
||||
async ensureCsvProduced(qs: qsClient.QueryServerClient): Promise<string> {
|
||||
if (await this.hasCsv()) {
|
||||
return this.csvPath;
|
||||
|
||||
Reference in New Issue
Block a user