Merge pull request #1432 from github/charisk-elena/result-count-on-history-labels

Add result count to remote queries in Query History
This commit is contained in:
Elena Tanasoiu
2022-07-19 13:50:22 +01:00
committed by GitHub
14 changed files with 89 additions and 59 deletions

View File

@@ -224,7 +224,7 @@
}, },
"codeQL.queryHistory.format": { "codeQL.queryHistory.format": {
"type": "string", "type": "string",
"default": "%q on %d - %s, %r [%t]", "default": "%q on %d - %s %r [%t]",
"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" "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"
}, },
"codeQL.queryHistory.ttl": { "codeQL.queryHistory.ttl": {

View File

@@ -581,3 +581,11 @@ export async function* walkDirectory(dir: string): AsyncIterableIterator<string>
} }
} }
} }
/**
* Pluralizes a word.
* Example: Returns "N repository" if N is one, "N repositories" otherwise.
*/
export function pluralize(numItems: number | undefined, singular: string, plural: string): string {
return numItems ? `${numItems} ${numItems === 1 ? singular : plural}` : '';
}

View File

@@ -3,6 +3,7 @@ import * as path from 'path';
import { QueryHistoryConfig } from './config'; import { QueryHistoryConfig } from './config';
import { LocalQueryInfo, QueryHistoryInfo } from './query-results'; import { LocalQueryInfo, QueryHistoryInfo } from './query-results';
import { RemoteQueryHistoryItem } from './remote-queries/remote-query-history-item'; import { RemoteQueryHistoryItem } from './remote-queries/remote-query-history-item';
import { pluralize } from './helpers';
interface InterpolateReplacements { interface InterpolateReplacements {
t: string; // Start time t: string; // Start time
@@ -57,25 +58,30 @@ export class HistoryItemLabelProvider {
t: item.startTime, t: item.startTime,
q: item.getQueryName(), q: item.getQueryName(),
d: item.initialInfo.databaseInfo.name, d: item.initialInfo.databaseInfo.name,
r: `${resultCount} results`, r: `(${resultCount} results)`,
s: statusString, s: statusString,
f: item.getQueryFileName(), f: item.getQueryFileName(),
'%': '%', '%': '%',
}; };
} }
// Return the number of repositories queried if available. Otherwise, use the controller repository name.
private buildRepoLabel(item: RemoteQueryHistoryItem): string {
const repositoryCount = item.remoteQuery.repositoryCount;
if (repositoryCount) {
return pluralize(repositoryCount, 'repository', 'repositories');
}
return `${item.remoteQuery.controllerRepository.owner}/${item.remoteQuery.controllerRepository.name}`;
}
private getRemoteInterpolateReplacements(item: RemoteQueryHistoryItem): InterpolateReplacements { private getRemoteInterpolateReplacements(item: RemoteQueryHistoryItem): InterpolateReplacements {
const numRepositoriesQueried = item.remoteQuery.numRepositoriesQueried;
const numRepositoriesLabel = `${numRepositoriesQueried} ${numRepositoriesQueried === 1 ? 'repository' : 'repositories'}`;
return { return {
t: new Date(item.remoteQuery.executionStartTime).toLocaleString(env.language), t: new Date(item.remoteQuery.executionStartTime).toLocaleString(env.language),
q: `${item.remoteQuery.queryName} (${item.remoteQuery.language})`, q: `${item.remoteQuery.queryName} (${item.remoteQuery.language})`,
d: this.buildRepoLabel(item),
// Return the number of repositories queried if available. Otherwise, use the controller repository name. r: `(${pluralize(item.resultCount, 'result', 'results')})`,
d: numRepositoriesQueried ? numRepositoriesLabel : `${item.remoteQuery.controllerRepository.owner}/${item.remoteQuery.controllerRepository.name}`,
// There is no synchronous way to get the results count.
r: '',
s: item.status, s: item.status,
f: path.basename(item.remoteQuery.queryFilePath), f: path.basename(item.remoteQuery.queryFilePath),
'%': '%' '%': '%'

View File

@@ -205,13 +205,12 @@ export class HistoryTreeDataProvider extends DisposableObject {
? h2.initialInfo.start.getTime() ? h2.initialInfo.start.getTime()
: h2.remoteQuery?.executionStartTime; : h2.remoteQuery?.executionStartTime;
// result count for remote queries is not available here.
const resultCount1 = h1.t === 'local' const resultCount1 = h1.t === 'local'
? h1.completedQuery?.resultCount ?? -1 ? h1.completedQuery?.resultCount ?? -1
: -1; : h1.resultCount ?? -1;
const resultCount2 = h2.t === 'local' const resultCount2 = h2.t === 'local'
? h2.completedQuery?.resultCount ?? -1 ? h2.completedQuery?.resultCount ?? -1
: -1; : h2.resultCount ?? -1;
switch (this.sortOrder) { switch (this.sortOrder) {
case SortOrder.NameAsc: case SortOrder.NameAsc:
@@ -574,6 +573,7 @@ export class QueryHistoryManager extends DisposableObject {
const remoteQueryHistoryItem = item as RemoteQueryHistoryItem; const remoteQueryHistoryItem = item as RemoteQueryHistoryItem;
remoteQueryHistoryItem.status = event.status; remoteQueryHistoryItem.status = event.status;
remoteQueryHistoryItem.failureReason = event.failureReason; remoteQueryHistoryItem.failureReason = event.failureReason;
remoteQueryHistoryItem.resultCount = event.resultCount;
if (event.status === QueryStatus.Completed) { if (event.status === QueryStatus.Completed) {
remoteQueryHistoryItem.completed = true; remoteQueryHistoryItem.completed = true;
} }

View File

@@ -4,7 +4,10 @@ import * as fs from 'fs-extra';
import { window, commands, Uri, ExtensionContext, QuickPickItem, workspace, ViewColumn } from 'vscode'; import { window, commands, Uri, ExtensionContext, QuickPickItem, workspace, ViewColumn } from 'vscode';
import { Credentials } from '../authentication'; import { Credentials } from '../authentication';
import { UserCancellationException } from '../commandRunner'; import { UserCancellationException } from '../commandRunner';
import { showInformationMessageWithAction } from '../helpers'; import {
showInformationMessageWithAction,
pluralize
} from '../helpers';
import { logger } from '../logging'; import { logger } from '../logging';
import { QueryHistoryManager } from '../query-history'; import { QueryHistoryManager } from '../query-history';
import { createGist } from './gh-actions-api-client'; import { createGist } from './gh-actions-api-client';
@@ -106,9 +109,9 @@ export async function exportResultsToGist(
*/ */
const buildGistDescription = (query: RemoteQuery, analysesResults: AnalysisResults[]) => { const buildGistDescription = (query: RemoteQuery, analysesResults: AnalysisResults[]) => {
const resultCount = sumAnalysesResults(analysesResults); const resultCount = sumAnalysesResults(analysesResults);
const repositoryLabel = `${query.numRepositoriesQueried} ${query.numRepositoriesQueried === 1 ? 'repository' : 'repositories'}`; const resultLabel = pluralize(resultCount, 'result', 'results');
const repositoryCount = query.numRepositoriesQueried ? repositoryLabel : ''; const repositoryLabel = pluralize(query.repositoryCount, 'repository', 'repositories');
return `${query.queryName} (${query.language}) ${resultCount} results (${repositoryCount})`; return `${query.queryName} (${query.language}) ${resultLabel} (${repositoryLabel})`;
}; };
/** /**

View File

@@ -18,10 +18,16 @@ import {
import { Logger } from '../logging'; import { Logger } from '../logging';
import { getHtmlForWebview } from '../interface-utils'; import { getHtmlForWebview } from '../interface-utils';
import { assertNever } from '../pure/helpers-pure'; import { assertNever } from '../pure/helpers-pure';
import { AnalysisSummary, RemoteQueryResult } from './remote-query-result'; import {
AnalysisSummary,
RemoteQueryResult,
sumAnalysisSummariesResults
} from './remote-query-result';
import { RemoteQuery } from './remote-query'; import { RemoteQuery } from './remote-query';
import { RemoteQueryResult as RemoteQueryResultViewModel } from './shared/remote-query-result'; import {
import { AnalysisSummary as AnalysisResultViewModel } from './shared/remote-query-result'; AnalysisSummary as AnalysisResultViewModel,
RemoteQueryResult as RemoteQueryResultViewModel
} from './shared/remote-query-result';
import { showAndLogWarningMessage } from '../helpers'; import { showAndLogWarningMessage } from '../helpers';
import { URLSearchParams } from 'url'; import { URLSearchParams } from 'url';
import { SHOW_QUERY_TEXT_MSG } from '../query-history'; import { SHOW_QUERY_TEXT_MSG } from '../query-history';
@@ -73,7 +79,7 @@ export class RemoteQueriesInterfaceManager {
*/ */
private buildViewModel(query: RemoteQuery, queryResult: RemoteQueryResult): RemoteQueryResultViewModel { private buildViewModel(query: RemoteQuery, queryResult: RemoteQueryResult): RemoteQueryResultViewModel {
const queryFileName = path.basename(query.queryFilePath); const queryFileName = path.basename(query.queryFilePath);
const totalResultCount = queryResult.analysisSummaries.reduce((acc, cur) => acc + cur.resultCount, 0); const totalResultCount = sumAnalysisSummariesResults(queryResult.analysisSummaries);
const executionDuration = this.getDuration(queryResult.executionEndTime, query.executionStartTime); const executionDuration = this.getDuration(queryResult.executionEndTime, query.executionStartTime);
const analysisSummaries = this.buildAnalysisSummaries(queryResult.analysisSummaries); const analysisSummaries = this.buildAnalysisSummaries(queryResult.analysisSummaries);
const totalRepositoryCount = queryResult.analysisSummaries.length; const totalRepositoryCount = queryResult.analysisSummaries.length;

View File

@@ -15,7 +15,7 @@ import { RemoteQuery } from './remote-query';
import { RemoteQueriesMonitor } from './remote-queries-monitor'; import { RemoteQueriesMonitor } from './remote-queries-monitor';
import { getRemoteQueryIndex, getRepositoriesMetadata, RepositoriesMetadata } from './gh-actions-api-client'; import { getRemoteQueryIndex, getRepositoriesMetadata, RepositoriesMetadata } from './gh-actions-api-client';
import { RemoteQueryResultIndex } from './remote-query-result-index'; import { RemoteQueryResultIndex } from './remote-query-result-index';
import { RemoteQueryResult } from './remote-query-result'; import { RemoteQueryResult, sumAnalysisSummariesResults } from './remote-query-result';
import { DownloadLink } from './download-link'; import { DownloadLink } from './download-link';
import { AnalysesResultsManager } from './analyses-results-manager'; import { AnalysesResultsManager } from './analyses-results-manager';
import { assertNever } from '../pure/helpers-pure'; import { assertNever } from '../pure/helpers-pure';
@@ -41,7 +41,8 @@ export interface UpdatedQueryStatusEvent {
queryId: string; queryId: string;
status: QueryStatus; status: QueryStatus;
failureReason?: string; failureReason?: string;
numRepositoriesQueried?: number; repositoryCount?: number;
resultCount?: number;
} }
export class RemoteQueriesManager extends DisposableObject { export class RemoteQueriesManager extends DisposableObject {
@@ -249,7 +250,7 @@ export class RemoteQueriesManager extends DisposableObject {
} }
private async askToOpenResults(query: RemoteQuery, queryResult: RemoteQueryResult): Promise<void> { private async askToOpenResults(query: RemoteQuery, queryResult: RemoteQueryResult): Promise<void> {
const totalResultCount = queryResult.analysisSummaries.reduce((acc, cur) => acc + cur.resultCount, 0); const totalResultCount = sumAnalysisSummariesResults(queryResult.analysisSummaries);
const totalRepoCount = queryResult.analysisSummaries.length; const totalRepoCount = queryResult.analysisSummaries.length;
const message = `Query "${query.queryName}" run on ${totalRepoCount} repositories and returned ${totalResultCount} results`; const message = `Query "${query.queryName}" run on ${totalRepoCount} repositories and returned ${totalResultCount} results`;
@@ -317,10 +318,12 @@ export class RemoteQueriesManager extends DisposableObject {
if (resultIndex) { if (resultIndex) {
const metadata = await this.getRepositoriesMetadata(resultIndex, credentials); const metadata = await this.getRepositoriesMetadata(resultIndex, credentials);
const queryResult = this.mapQueryResult(executionEndTime, resultIndex, queryId, metadata); const queryResult = this.mapQueryResult(executionEndTime, resultIndex, queryId, metadata);
const resultCount = sumAnalysisSummariesResults(queryResult.analysisSummaries);
this.remoteQueryStatusUpdateEventEmitter.fire({ this.remoteQueryStatusUpdateEventEmitter.fire({
queryId, queryId,
status: QueryStatus.Completed, status: QueryStatus.Completed,
numRepositoriesQueried: queryResult.analysisSummaries.length, repositoryCount: queryResult.analysisSummaries.length,
resultCount
}); });
await this.storeJsonFile(queryId, 'query-result.json', queryResult); await this.storeJsonFile(queryId, 'query-result.json', queryResult);

View File

@@ -7,6 +7,7 @@ import { RemoteQuery } from './remote-query';
export interface RemoteQueryHistoryItem { export interface RemoteQueryHistoryItem {
readonly t: 'remote'; readonly t: 'remote';
failureReason?: string; failureReason?: string;
resultCount?: number;
status: QueryStatus; status: QueryStatus;
completed: boolean; completed: boolean;
readonly queryId: string, readonly queryId: string,

View File

@@ -18,3 +18,10 @@ export interface AnalysisSummary {
starCount?: number, starCount?: number,
lastUpdated?: number, lastUpdated?: number,
} }
/**
* Sums up the number of results for all repos queried via a remote query.
*/
export const sumAnalysisSummariesResults = (analysisSummaries: AnalysisSummary[]): number => {
return analysisSummaries.reduce((acc, cur) => acc + cur.resultCount, 0);
};

View File

@@ -8,5 +8,5 @@ export interface RemoteQuery {
controllerRepository: Repository; controllerRepository: Repository;
executionStartTime: number; // Use number here since it needs to be serialized and desserialized. executionStartTime: number; // Use number here since it needs to be serialized and desserialized.
actionsWorkflowRunId: number; actionsWorkflowRunId: number;
numRepositoriesQueried: number; repositoryCount: number;
} }

View File

@@ -11,6 +11,7 @@ import {
showAndLogErrorMessage, showAndLogErrorMessage,
showAndLogInformationMessage, showAndLogInformationMessage,
tryGetQueryMetadata, tryGetQueryMetadata,
pluralize,
tmpDir tmpDir
} from '../helpers'; } from '../helpers';
import { Credentials } from '../authentication'; import { Credentials } from '../authentication';
@@ -270,7 +271,7 @@ export async function runRemoteQuery(
} }
const workflowRunId = apiResponse.workflow_run_id; const workflowRunId = apiResponse.workflow_run_id;
const numRepositoriesQueried = apiResponse.repositories_queried.length; const repositoryCount = apiResponse.repositories_queried.length;
const remoteQuery = await buildRemoteQueryEntity( const remoteQuery = await buildRemoteQueryEntity(
queryFile, queryFile,
queryMetadata, queryMetadata,
@@ -279,7 +280,7 @@ export async function runRemoteQuery(
queryStartTime, queryStartTime,
workflowRunId, workflowRunId,
language, language,
numRepositoriesQueried); repositoryCount);
// don't return the path because it has been deleted // don't return the path because it has been deleted
return { query: remoteQuery }; return { query: remoteQuery };
@@ -352,44 +353,37 @@ async function runRemoteQueriesApiRequest(
const eol = os.EOL; const eol = os.EOL;
const eol2 = os.EOL + os.EOL; const eol2 = os.EOL + os.EOL;
/**
* Returns "N repository" if N is one, "N repositories" otherwise.
*/
function pluralizeRepositories(numRepositories: number) {
return `${numRepositories} ${numRepositories === 1 ? 'repository' : 'repositories'}`;
}
// exported for testing only // exported for testing only
export function parseResponse(owner: string, repo: string, response: QueriesResponse) { export function parseResponse(owner: string, repo: string, response: QueriesResponse) {
const repositoriesQueried = response.repositories_queried; const repositoriesQueried = response.repositories_queried;
const numRepositoriesQueried = repositoriesQueried.length; const repositoryCount = repositoriesQueried.length;
const popupMessage = `Successfully scheduled runs on ${pluralizeRepositories(numRepositoriesQueried)}. [Click here to see the progress](https://github.com/${owner}/${repo}/actions/runs/${response.workflow_run_id}).` const popupMessage = `Successfully scheduled runs on ${pluralize(repositoryCount, 'repository', 'repositories')}. [Click here to see the progress](https://github.com/${owner}/${repo}/actions/runs/${response.workflow_run_id}).`
+ (response.errors ? `${eol2}Some repositories could not be scheduled. See extension log for details.` : ''); + (response.errors ? `${eol2}Some repositories could not be scheduled. See extension log for details.` : '');
let logMessage = `Successfully scheduled runs on ${pluralizeRepositories(numRepositoriesQueried)}. See https://github.com/${owner}/${repo}/actions/runs/${response.workflow_run_id}.`; let logMessage = `Successfully scheduled runs on ${pluralize(repositoryCount, 'repository', 'repositories')}. See https://github.com/${owner}/${repo}/actions/runs/${response.workflow_run_id}.`;
logMessage += `${eol2}Repositories queried:${eol}${repositoriesQueried.join(', ')}`; logMessage += `${eol2}Repositories queried:${eol}${repositoriesQueried.join(', ')}`;
if (response.errors) { if (response.errors) {
const { invalid_repositories, repositories_without_database, private_repositories, cutoff_repositories, cutoff_repositories_count } = response.errors; const { invalid_repositories, repositories_without_database, private_repositories, cutoff_repositories, cutoff_repositories_count } = response.errors;
logMessage += `${eol2}Some repositories could not be scheduled.`; logMessage += `${eol2}Some repositories could not be scheduled.`;
if (invalid_repositories?.length) { if (invalid_repositories?.length) {
logMessage += `${eol2}${pluralizeRepositories(invalid_repositories.length)} invalid and could not be found:${eol}${invalid_repositories.join(', ')}`; logMessage += `${eol2}${pluralize(invalid_repositories.length, 'repository', 'repositories')} invalid and could not be found:${eol}${invalid_repositories.join(', ')}`;
} }
if (repositories_without_database?.length) { if (repositories_without_database?.length) {
logMessage += `${eol2}${pluralizeRepositories(repositories_without_database.length)} did not have a CodeQL database available:${eol}${repositories_without_database.join(', ')}`; logMessage += `${eol2}${pluralize(repositories_without_database.length, 'repository', 'repositories')} did not have a CodeQL database available:${eol}${repositories_without_database.join(', ')}`;
logMessage += `${eol}For each public repository that has not yet been added to the database service, we will try to create a database next time the store is updated.`; logMessage += `${eol}For each public repository that has not yet been added to the database service, we will try to create a database next time the store is updated.`;
} }
if (private_repositories?.length) { if (private_repositories?.length) {
logMessage += `${eol2}${pluralizeRepositories(private_repositories.length)} not public:${eol}${private_repositories.join(', ')}`; logMessage += `${eol2}${pluralize(private_repositories.length, 'repository', 'repositories')} not public:${eol}${private_repositories.join(', ')}`;
logMessage += `${eol}When using a public controller repository, only public repositories can be queried.`; logMessage += `${eol}When using a public controller repository, only public repositories can be queried.`;
} }
if (cutoff_repositories_count) { if (cutoff_repositories_count) {
logMessage += `${eol2}${pluralizeRepositories(cutoff_repositories_count)} over the limit for a single request`; logMessage += `${eol2}${pluralize(cutoff_repositories_count, 'repository', 'repositories')} over the limit for a single request`;
if (cutoff_repositories) { if (cutoff_repositories) {
logMessage += `:${eol}${cutoff_repositories.join(', ')}`; logMessage += `:${eol}${cutoff_repositories.join(', ')}`;
if (cutoff_repositories_count !== cutoff_repositories.length) { if (cutoff_repositories_count !== cutoff_repositories.length) {
const moreRepositories = cutoff_repositories_count - cutoff_repositories.length; const moreRepositories = cutoff_repositories_count - cutoff_repositories.length;
logMessage += `${eol}...${eol}And another ${pluralizeRepositories(moreRepositories)}.`; logMessage += `${eol}...${eol}And another ${pluralize(moreRepositories, 'repository', 'repositories')}.`;
} }
} else { } else {
logMessage += '.'; logMessage += '.';
@@ -436,7 +430,7 @@ async function buildRemoteQueryEntity(
queryStartTime: number, queryStartTime: number,
workflowRunId: number, workflowRunId: number,
language: string, language: string,
numRepositoriesQueried: number repositoryCount: number
): Promise<RemoteQuery> { ): Promise<RemoteQuery> {
// The query name is either the name as specified in the query metadata, or the file name. // The query name is either the name as specified in the query metadata, or the file name.
const queryName = queryMetadata?.name ?? path.basename(queryFilePath); const queryName = queryMetadata?.name ?? path.basename(queryFilePath);
@@ -454,6 +448,6 @@ async function buildRemoteQueryEntity(
}, },
executionStartTime: queryStartTime, executionStartTime: queryStartTime,
actionsWorkflowRunId: workflowRunId, actionsWorkflowRunId: workflowRunId,
numRepositoriesQueried: numRepositoriesQueried, repositoryCount,
}; };
} }

View File

@@ -6,5 +6,5 @@
"controllerRepository": { "owner": "dsp-testing", "name": "qc-controller" }, "controllerRepository": { "owner": "dsp-testing", "name": "qc-controller" },
"executionStartTime": 1649419081990, "executionStartTime": 1649419081990,
"actionsWorkflowRunId": 2115000864, "actionsWorkflowRunId": 2115000864,
"numRepositoriesQueried": 10 "repositoryCount": 10
} }

View File

@@ -27,10 +27,10 @@ describe('HistoryItemLabelProvider', () => {
expect(labelProvider.getLabel(fqi)).to.eq('xxx'); expect(labelProvider.getLabel(fqi)).to.eq('xxx');
fqi.userSpecifiedLabel = '%t %q %d %s %f %r %%'; fqi.userSpecifiedLabel = '%t %q %d %s %f %r %%';
expect(labelProvider.getLabel(fqi)).to.eq(`${dateStr} query-name db-name in progress query-file.ql 456 results %`); expect(labelProvider.getLabel(fqi)).to.eq(`${dateStr} query-name db-name in progress query-file.ql (456 results) %`);
fqi.userSpecifiedLabel = '%t %q %d %s %f %r %%::%t %q %d %s %f %r %%'; fqi.userSpecifiedLabel = '%t %q %d %s %f %r %%::%t %q %d %s %f %r %%';
expect(labelProvider.getLabel(fqi)).to.eq(`${dateStr} query-name db-name in progress query-file.ql 456 results %::${dateStr} query-name db-name in progress query-file.ql 456 results %`); expect(labelProvider.getLabel(fqi)).to.eq(`${dateStr} query-name db-name in progress query-file.ql (456 results) %::${dateStr} query-name db-name in progress query-file.ql (456 results) %`);
}); });
it('should interpolate query when not user specified', () => { it('should interpolate query when not user specified', () => {
@@ -40,10 +40,10 @@ describe('HistoryItemLabelProvider', () => {
config.format = '%t %q %d %s %f %r %%'; config.format = '%t %q %d %s %f %r %%';
expect(labelProvider.getLabel(fqi)).to.eq(`${dateStr} query-name db-name in progress query-file.ql 456 results %`); expect(labelProvider.getLabel(fqi)).to.eq(`${dateStr} query-name db-name in progress query-file.ql (456 results) %`);
config.format = '%t %q %d %s %f %r %%::%t %q %d %s %f %r %%'; config.format = '%t %q %d %s %f %r %%::%t %q %d %s %f %r %%';
expect(labelProvider.getLabel(fqi)).to.eq(`${dateStr} query-name db-name in progress query-file.ql 456 results %::${dateStr} query-name db-name in progress query-file.ql 456 results %`); expect(labelProvider.getLabel(fqi)).to.eq(`${dateStr} query-name db-name in progress query-file.ql (456 results) %::${dateStr} query-name db-name in progress query-file.ql (456 results) %`);
}); });
it('should get query short label', () => { it('should get query short label', () => {
@@ -102,17 +102,17 @@ describe('HistoryItemLabelProvider', () => {
config.format = '%t %q %d %s %f %r %%'; config.format = '%t %q %d %s %f %r %%';
expect(labelProvider.getLabel(fqi)).to.eq(`${dateStr} query-name (javascript) github/vscode-codeql-integration-tests in progress query-file.ql %`); expect(labelProvider.getLabel(fqi)).to.eq(`${dateStr} query-name (javascript) github/vscode-codeql-integration-tests in progress query-file.ql (16 results) %`);
config.format = '%t %q %d %s %f %r %%::%t %q %d %s %f %r %%'; config.format = '%t %q %d %s %f %r %%::%t %q %d %s %f %r %%';
expect(labelProvider.getLabel(fqi)).to.eq(`${dateStr} query-name (javascript) github/vscode-codeql-integration-tests in progress query-file.ql %::${dateStr} query-name (javascript) github/vscode-codeql-integration-tests in progress query-file.ql %`); expect(labelProvider.getLabel(fqi)).to.eq(`${dateStr} query-name (javascript) github/vscode-codeql-integration-tests in progress query-file.ql (16 results) %::${dateStr} query-name (javascript) github/vscode-codeql-integration-tests in progress query-file.ql (16 results) %`);
}); });
it('should use number of repositories instead of controller repo if available', () => { it('should use number of repositories instead of controller repo if available', () => {
const fqi = createMockRemoteQueryInfo(undefined, 2); const fqi = createMockRemoteQueryInfo(undefined, 2);
config.format = '%t %q %d %s %f %r %%'; config.format = '%t %q %d %s %f %r %%';
expect(labelProvider.getLabel(fqi)).to.eq(`${dateStr} query-name (javascript) 2 repositories in progress query-file.ql %`); expect(labelProvider.getLabel(fqi)).to.eq(`${dateStr} query-name (javascript) 2 repositories in progress query-file.ql (16 results) %`);
}); });
it('should get query short label', () => { it('should get query short label', () => {
@@ -126,7 +126,7 @@ describe('HistoryItemLabelProvider', () => {
expect(labelProvider.getShortLabel(fqi)).to.eq('query-name'); expect(labelProvider.getShortLabel(fqi)).to.eq('query-name');
}); });
function createMockRemoteQueryInfo(userSpecifiedLabel?: string, numRepositoriesQueried?: number) { function createMockRemoteQueryInfo(userSpecifiedLabel?: string, repositoryCount?: number) {
return { return {
t: 'remote', t: 'remote',
userSpecifiedLabel, userSpecifiedLabel,
@@ -139,9 +139,10 @@ describe('HistoryItemLabelProvider', () => {
name: 'vscode-codeql-integration-tests' name: 'vscode-codeql-integration-tests'
}, },
language: 'javascript', language: 'javascript',
numRepositoriesQueried, repositoryCount,
}, },
status: 'in progress', status: 'in progress',
resultCount: 16,
} as unknown as RemoteQueryHistoryItem; } as unknown as RemoteQueryHistoryItem;
} }
}); });

View File

@@ -456,11 +456,11 @@ describe('query-history', () => {
describe('getChildren', () => { describe('getChildren', () => {
const history = [ const history = [
item('a', 2, 'remote'), item('a', 2, 'remote', 24),
item('b', 10, 'local', 20), item('b', 10, 'local', 20),
item('c', 5, 'local', 30), item('c', 5, 'local', 30),
item('d', 1, 'local', 25), item('d', 1, 'local', 25),
item('e', 6, 'remote'), item('e', 6, 'remote', 5),
]; ];
let treeDataProvider: HistoryTreeDataProvider; let treeDataProvider: HistoryTreeDataProvider;
@@ -503,7 +503,7 @@ describe('query-history', () => {
}); });
it('should get children for result count ascending', async () => { it('should get children for result count ascending', async () => {
const expected = [history[0], history[4], history[1], history[3], history[2]]; const expected = [history[4], history[1], history[0], history[3], history[2]];
treeDataProvider.sortOrder = SortOrder.CountAsc; treeDataProvider.sortOrder = SortOrder.CountAsc;
const children = await treeDataProvider.getChildren(); const children = await treeDataProvider.getChildren();
@@ -511,7 +511,7 @@ describe('query-history', () => {
}); });
it('should get children for result count descending', async () => { it('should get children for result count descending', async () => {
const expected = [history[0], history[4], history[1], history[3], history[2]].reverse(); const expected = [history[4], history[1], history[0], history[3], history[2]].reverse();
treeDataProvider.sortOrder = SortOrder.CountDesc; treeDataProvider.sortOrder = SortOrder.CountDesc;
const children = await treeDataProvider.getChildren(); const children = await treeDataProvider.getChildren();
@@ -573,6 +573,7 @@ describe('query-history', () => {
}, },
repositories: [] repositories: []
}, },
resultCount,
t t
}; };
} }