Add ability to create repo list from MRVA results (#1403)

This commit is contained in:
Charis Kyriakou
2022-06-24 09:26:12 +01:00
committed by GitHub
parent fd4b6022a9
commit 9c29c5c9c6
9 changed files with 107 additions and 6 deletions

View File

@@ -573,6 +573,10 @@
"command": "codeQLQueryHistory.openOnGithub",
"title": "Open Variant Analysis on GitHub"
},
{
"command": "codeQLQueryHistory.copyRepoList",
"title": "Copy Repository List"
},
{
"command": "codeQLQueryResults.nextPathStep",
"title": "CodeQL: Show Next Step on Path"
@@ -790,6 +794,11 @@
"group": "9_qlCommands",
"when": "viewItem == remoteResultsItem || viewItem == inProgressRemoteResultsItem || viewItem == cancelledResultsItem"
},
{
"command": "codeQLQueryHistory.copyRepoList",
"group": "9_qlCommands",
"when": "viewItem == remoteResultsItem"
},
{
"command": "codeQLTests.showOutputDifferences",
"group": "qltest@1",
@@ -978,6 +987,10 @@
"command": "codeQLQueryHistory.openOnGithub",
"when": "false"
},
{
"command": "codeQLQueryHistory.copyRepoList",
"when": "false"
},
{
"command": "codeQLQueryHistory.showQueryText",
"when": "false"

View File

@@ -886,6 +886,12 @@ async function activateWithInstalledDistribution(
await rqm.monitorRemoteQuery(queryId, query, token);
}));
ctx.subscriptions.push(
commandRunner('codeQL.copyRepoList', async (queryId: string) => {
await rqm.copyRemoteQueryRepoListToClipboard(queryId);
})
);
ctx.subscriptions.push(
commandRunner('codeQL.autoDownloadRemoteQueryResults', async (
queryResult: RemoteQueryResult,

View File

@@ -395,7 +395,8 @@ export type FromRemoteQueriesMessage =
| OpenVirtualFileMsg
| RemoteQueryDownloadAnalysisResultsMessage
| RemoteQueryDownloadAllAnalysesResultsMessage
| RemoteQueryExportResultsMessage;
| RemoteQueryExportResultsMessage
| CopyRepoListMessage;
export type ToRemoteQueriesMessage =
| SetRemoteQueryResultMessage
@@ -433,3 +434,8 @@ export interface RemoteQueryDownloadAllAnalysesResultsMessage {
export interface RemoteQueryExportResultsMessage {
t: 'remoteQueryExportResults';
}
export interface CopyRepoListMessage {
t: 'copyRepoList';
queryId: string;
}

View File

@@ -491,6 +491,12 @@ export class QueryHistoryManager extends DisposableObject {
}
)
);
this.push(
commandRunner(
'codeQLQueryHistory.copyRepoList',
this.handleCopyRepoList.bind(this)
)
);
// There are two configuration items that affect the query history:
// 1. The ttl for query history items.
@@ -1050,6 +1056,20 @@ export class QueryHistoryManager extends DisposableObject {
);
}
async handleCopyRepoList(
singleItem: QueryHistoryInfo,
multiSelect: QueryHistoryInfo[],
) {
const { finalSingleItem, finalMultiSelect } = this.determineSelection(singleItem, multiSelect);
// Remote queries only
if (!this.assertSingleQuery(finalMultiSelect) || !finalSingleItem || finalSingleItem.t !== 'remote') {
return;
}
await commands.executeCommand('codeQL.copyRepoList', finalSingleItem.queryId);
}
async getQueryText(item: QueryHistoryInfo): Promise<string> {
return item.t === 'local'
? item.initialInfo.queryText

View File

@@ -80,6 +80,7 @@ export class RemoteQueriesInterfaceManager {
const affectedRepositories = queryResult.analysisSummaries.filter(r => r.resultCount > 0);
return {
queryId: queryResult.queryId,
queryTitle: query.queryName,
queryFileName: queryFileName,
queryFilePath: query.queryFilePath,
@@ -206,6 +207,9 @@ export class RemoteQueriesInterfaceManager {
case 'openVirtualFile':
await this.openVirtualFile(msg.queryText);
break;
case 'copyRepoList':
await commands.executeCommand('codeQL.copyRepoList', msg.queryId);
break;
case 'remoteQueryDownloadAnalysisResults':
await this.downloadAnalysisResults(msg);
break;

View File

@@ -1,7 +1,8 @@
import { CancellationToken, commands, EventEmitter, ExtensionContext, Uri, window } from 'vscode';
import { CancellationToken, commands, EventEmitter, ExtensionContext, Uri, env, window } from 'vscode';
import { nanoid } from 'nanoid';
import * as path from 'path';
import * as fs from 'fs-extra';
import * as os from 'os';
import { Credentials } from '../authentication';
import { CodeQLCliServer } from '../cli';
@@ -190,6 +191,22 @@ export class RemoteQueriesManager extends DisposableObject {
results => this.interfaceManager.setAnalysisResults(results, queryResult.queryId));
}
public async copyRemoteQueryRepoListToClipboard(queryId: string) {
const queryResult = await this.getRemoteQueryResult(queryId);
const repos = queryResult.analysisSummaries.map(a => a.nwo);
if (repos.length > 0) {
const text = [
'"new-repo-list": [',
...repos.slice(0, -1).map(repo => ` "${repo}",`),
` "${repos[repos.length - 1]}"`,
']'
];
await env.clipboard.writeText(text.join(os.EOL));
}
}
private mapQueryResult(
executionEndTime: number,
resultIndex: RemoteQueryResultIndex,
@@ -259,6 +276,10 @@ export class RemoteQueriesManager extends DisposableObject {
await createTimestampFile(path.join(this.storagePath, queryId));
}
private async getRemoteQueryResult(queryId: string): Promise<RemoteQueryResult> {
return await this.retrieveJsonFile<RemoteQueryResult>(queryId, 'query-result.json');
}
private async storeJsonFile<T>(queryId: string, fileName: string, obj: T): Promise<void> {
const filePath = path.join(this.storagePath, queryId, fileName);
await fs.writeFile(filePath, JSON.stringify(obj, null, 2), 'utf8');

View File

@@ -2,6 +2,7 @@ import { DownloadLink } from '../download-link';
import { AnalysisFailure } from './analysis-failure';
export interface RemoteQueryResult {
queryId: string,
queryTitle: string,
queryFileName: string,
queryFilePath: string,

View File

@@ -22,10 +22,12 @@ import RepositoriesSearch from './RepositoriesSearch';
import StarCount from './StarCount';
import SortRepoFilter, { Sort, sorter } from './SortRepoFilter';
import LastUpdated from './LastUpdated';
import RepoListCopyButton from './RepoListCopyButton';
const numOfReposInContractedMode = 10;
const emptyQueryResult: RemoteQueryResult = {
queryId: '',
queryTitle: '',
queryFileName: '',
queryFilePath: '',
@@ -149,10 +151,14 @@ const SummaryTitleWithResults = ({
text="Download all"
onClick={() => downloadAllAnalysesResults(queryResult)} />
}
<SortRepoFilter
sort={sort}
setSort={setSort}
/>
<div style={{ flexGrow: 2, textAlign: 'right' }}>
<RepoListCopyButton queryResult={queryResult} />
<HorizontalSpace size={1} />
<SortRepoFilter
sort={sort}
setSort={setSort}
/>
</div>
</div>
);
};

View File

@@ -0,0 +1,24 @@
import * as React from 'react';
import { vscode } from '../../view/vscode-api';
import { RemoteQueryResult } from '../shared/remote-query-result';
import { CopyIcon } from '@primer/octicons-react';
import { IconButton } from '@primer/react';
const copyRepositoryList = (queryResult: RemoteQueryResult) => {
vscode.postMessage({
t: 'copyRepoList',
queryId: queryResult.queryId
});
};
const RepoListCopyButton = ({ queryResult }: { queryResult: RemoteQueryResult }) => (
<IconButton
aria-label="Copy repository list"
icon={CopyIcon}
variant="invisible"
size="small"
sx={{ 'text-align': 'right' }}
onClick={() => copyRepositoryList(queryResult)} />
);
export default RepoListCopyButton;