diff --git a/extensions/ql-vscode/src/history-item-label-provider.ts b/extensions/ql-vscode/src/history-item-label-provider.ts index 081832371..f47ec4d55 100644 --- a/extensions/ql-vscode/src/history-item-label-provider.ts +++ b/extensions/ql-vscode/src/history-item-label-provider.ts @@ -65,12 +65,14 @@ export class HistoryItemLabelProvider { } private getRemoteInterpolateReplacements(item: RemoteQueryHistoryItem): InterpolateReplacements { + const numRepositoriesQueried = item.remoteQuery.numRepositoriesQueried; + const numRepositoriesLabel = `${numRepositoriesQueried} ${numRepositoriesQueried === 1 ? 'repository' : 'repositories'}`; return { t: new Date(item.remoteQuery.executionStartTime).toLocaleString(env.language), - q: item.remoteQuery.queryName, + q: `${item.remoteQuery.queryName} (${item.remoteQuery.language})`, - // There is no database name for remote queries. Instead use the controller repository name. - d: `${item.remoteQuery.controllerRepository.owner}/${item.remoteQuery.controllerRepository.name}`, + // Return the number of repositories queried if available. Otherwise, use the controller repository name. + d: numRepositoriesQueried ? numRepositoriesLabel : `${item.remoteQuery.controllerRepository.owner}/${item.remoteQuery.controllerRepository.name}`, // There is no synchronous way to get the results count. r: '', diff --git a/extensions/ql-vscode/src/remote-queries/remote-queries-manager.ts b/extensions/ql-vscode/src/remote-queries/remote-queries-manager.ts index 879c84f2b..dec859618 100644 --- a/extensions/ql-vscode/src/remote-queries/remote-queries-manager.ts +++ b/extensions/ql-vscode/src/remote-queries/remote-queries-manager.ts @@ -41,6 +41,7 @@ export interface UpdatedQueryStatusEvent { queryId: string; status: QueryStatus; failureReason?: string; + numRepositoriesQueried?: number; } export class RemoteQueriesManager extends DisposableObject { @@ -314,9 +315,13 @@ export class RemoteQueriesManager extends DisposableObject { ): Promise { const resultIndex = await getRemoteQueryIndex(credentials, remoteQuery); if (resultIndex) { - this.remoteQueryStatusUpdateEventEmitter.fire({ queryId, status: QueryStatus.Completed }); const metadata = await this.getRepositoriesMetadata(resultIndex, credentials); const queryResult = this.mapQueryResult(executionEndTime, resultIndex, queryId, metadata); + this.remoteQueryStatusUpdateEventEmitter.fire({ + queryId, + status: QueryStatus.Completed, + numRepositoriesQueried: queryResult.analysisSummaries.length, + }); await this.storeJsonFile(queryId, 'query-result.json', queryResult); diff --git a/extensions/ql-vscode/src/remote-queries/remote-query.ts b/extensions/ql-vscode/src/remote-queries/remote-query.ts index 2ef898b06..34b13f1c9 100644 --- a/extensions/ql-vscode/src/remote-queries/remote-query.ts +++ b/extensions/ql-vscode/src/remote-queries/remote-query.ts @@ -8,4 +8,5 @@ export interface RemoteQuery { controllerRepository: Repository; executionStartTime: number; // Use number here since it needs to be serialized and desserialized. actionsWorkflowRunId: number; + numRepositoriesQueried: number; } diff --git a/extensions/ql-vscode/src/remote-queries/run-remote-query.ts b/extensions/ql-vscode/src/remote-queries/run-remote-query.ts index ce3bd9fb0..e1e25782d 100644 --- a/extensions/ql-vscode/src/remote-queries/run-remote-query.ts +++ b/extensions/ql-vscode/src/remote-queries/run-remote-query.ts @@ -258,17 +258,19 @@ export async function runRemoteQuery( }); const actionBranch = getActionBranch(); - const workflowRunId = await runRemoteQueriesApiRequest(credentials, actionBranch, language, repoSelection, owner, repo, base64Pack, dryRun); + const apiResponse = await runRemoteQueriesApiRequest(credentials, actionBranch, language, repoSelection, owner, repo, base64Pack, dryRun); const queryStartTime = Date.now(); const queryMetadata = await tryGetQueryMetadata(cliServer, queryFile); if (dryRun) { return { queryDirPath: remoteQueryDir.path }; } else { - if (!workflowRunId) { + if (!apiResponse) { return; } + const workflowRunId = apiResponse.workflow_run_id; + const numRepositoriesQueried = apiResponse.repositories_queried.length; const remoteQuery = await buildRemoteQueryEntity( queryFile, queryMetadata, @@ -276,7 +278,8 @@ export async function runRemoteQuery( repo, queryStartTime, workflowRunId, - language); + language, + numRepositoriesQueried); // don't return the path because it has been deleted return { query: remoteQuery }; @@ -301,7 +304,7 @@ async function runRemoteQueriesApiRequest( repo: string, queryPackBase64: string, dryRun = false -): Promise { +): Promise { const data = { ref, language, @@ -336,7 +339,7 @@ async function runRemoteQueriesApiRequest( ); const { popupMessage, logMessage } = parseResponse(owner, repo, response.data); void showAndLogInformationMessage(popupMessage, { fullMessage: logMessage }); - return response.data.workflow_run_id; + return response.data; } catch (error: any) { if (error.status === 404) { void showAndLogErrorMessage(`Controller repository was not found. Please make sure it's a valid repo name.${eol}`); @@ -432,7 +435,8 @@ async function buildRemoteQueryEntity( controllerRepoName: string, queryStartTime: number, workflowRunId: number, - language: string + language: string, + numRepositoriesQueried: number ): Promise { // The query name is either the name as specified in the query metadata, or the file name. const queryName = queryMetadata?.name ?? path.basename(queryFilePath); @@ -449,6 +453,7 @@ async function buildRemoteQueryEntity( name: controllerRepoName, }, executionStartTime: queryStartTime, - actionsWorkflowRunId: workflowRunId + actionsWorkflowRunId: workflowRunId, + numRepositoriesQueried: numRepositoriesQueried, }; } diff --git a/extensions/ql-vscode/src/vscode-tests/no-workspace/history-item-label-provider.test.ts b/extensions/ql-vscode/src/vscode-tests/no-workspace/history-item-label-provider.test.ts index e5fd2f9ad..f1a378d41 100644 --- a/extensions/ql-vscode/src/vscode-tests/no-workspace/history-item-label-provider.test.ts +++ b/extensions/ql-vscode/src/vscode-tests/no-workspace/history-item-label-provider.test.ts @@ -89,23 +89,30 @@ describe('HistoryItemLabelProvider', () => { expect(labelProvider.getLabel(fqi)).to.eq('xxx'); fqi.userSpecifiedLabel = '%t %q %d %s %%'; - expect(labelProvider.getLabel(fqi)).to.eq(`${dateStr} query-name github/vscode-codeql-integration-tests in progress %`); + expect(labelProvider.getLabel(fqi)).to.eq(`${dateStr} query-name (javascript) github/vscode-codeql-integration-tests in progress %`); fqi.userSpecifiedLabel = '%t %q %d %s %%::%t %q %d %s %%'; - expect(labelProvider.getLabel(fqi)).to.eq(`${dateStr} query-name github/vscode-codeql-integration-tests in progress %::${dateStr} query-name github/vscode-codeql-integration-tests in progress %`); + expect(labelProvider.getLabel(fqi)).to.eq(`${dateStr} query-name (javascript) github/vscode-codeql-integration-tests in progress %::${dateStr} query-name (javascript) github/vscode-codeql-integration-tests in progress %`); }); it('should interpolate query when not user specified', () => { const fqi = createMockRemoteQueryInfo(); - expect(labelProvider.getLabel(fqi)).to.eq('xxx query-name xxx'); + expect(labelProvider.getLabel(fqi)).to.eq('xxx query-name (javascript) xxx'); config.format = '%t %q %d %s %f %r %%'; - expect(labelProvider.getLabel(fqi)).to.eq(`${dateStr} query-name 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 %`); config.format = '%t %q %d %s %f %r %%::%t %q %d %s %f %r %%'; - expect(labelProvider.getLabel(fqi)).to.eq(`${dateStr} query-name github/vscode-codeql-integration-tests in progress query-file.ql %::${dateStr} query-name 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 %::${dateStr} query-name (javascript) github/vscode-codeql-integration-tests in progress query-file.ql %`); + }); + + it('should use number of repositories instead of controller repo if available', () => { + const fqi = createMockRemoteQueryInfo(undefined, 2); + + 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 %`); }); it('should get query short label', () => { @@ -119,7 +126,7 @@ describe('HistoryItemLabelProvider', () => { expect(labelProvider.getShortLabel(fqi)).to.eq('query-name'); }); - function createMockRemoteQueryInfo(userSpecifiedLabel?: string) { + function createMockRemoteQueryInfo(userSpecifiedLabel?: string, numRepositoriesQueried?: number) { return { t: 'remote', userSpecifiedLabel, @@ -130,7 +137,9 @@ describe('HistoryItemLabelProvider', () => { controllerRepository: { owner: 'github', name: 'vscode-codeql-integration-tests' - } + }, + language: 'javascript', + numRepositoriesQueried, }, status: 'in progress', } as unknown as RemoteQueryHistoryItem;