diff --git a/extensions/ql-vscode/package.json b/extensions/ql-vscode/package.json index 833031f45..fc27b26d3 100644 --- a/extensions/ql-vscode/package.json +++ b/extensions/ql-vscode/package.json @@ -302,8 +302,8 @@ "properties": { "codeQL.queryHistory.format": { "type": "string", - "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" + "default": "${queryName} on ${databaseName} - ${status} ${resultCount} [${startTime}]", + "markdownDescription": "Default string for how to label query history items.\n\nThe following variables are supported:\n* **${startTime}** - the time of the query\n* **${queryName}** - the human-readable query name\n* **${queryFileBasename}** - the query file's base name\n* **${queryLanguage}** - the query language\n* **${databaseName}** - the database name\n* **${resultCount}** - the number of results\n* **${status}** - a status string" }, "codeQL.queryHistory.ttl": { "type": "number", diff --git a/extensions/ql-vscode/src/query-history/history-item-label-provider.ts b/extensions/ql-vscode/src/query-history/history-item-label-provider.ts index b2bb24b04..86f2c4e32 100644 --- a/extensions/ql-vscode/src/query-history/history-item-label-provider.ts +++ b/extensions/ql-vscode/src/query-history/history-item-label-provider.ts @@ -12,17 +12,36 @@ import type { VariantAnalysisHistoryItem } from "./variant-analysis-history-item import { assertNever } from "../common/helpers-pure"; import { pluralize } from "../common/word"; import { humanizeQueryStatus } from "./query-status"; +import { substituteConfigVariables } from "../common/config-template"; -interface InterpolateReplacements { - t: string; // Start time - q: string; // Query name - d: string; // Database/repositories count - r: string; // Result count/Empty - s: string; // Status - f: string; // Query file name - l: string; // Query language - "%": "%"; // Percent sign -} +type LabelVariables = { + startTime: string; + queryName: string; + databaseName: string; + resultCount: string; + status: string; + queryFileBasename: string; + queryLanguage: string; +}; + +const legacyVariableInterpolateReplacements: Record< + keyof LabelVariables, + string +> = { + startTime: "t", + queryName: "q", + databaseName: "d", + resultCount: "r", + status: "s", + queryFileBasename: "f", + queryLanguage: "l", +}; + +// If any of the "legacy" variables are used, we need to use legacy interpolation. +const legacyLabelRegex = new RegExp( + `%([${Object.values(legacyVariableInterpolateReplacements).join("")}%])`, + "g", +); export class HistoryItemLabelProvider { constructor(private config: QueryHistoryConfig) { @@ -30,21 +49,26 @@ export class HistoryItemLabelProvider { } getLabel(item: QueryHistoryInfo) { - let replacements: InterpolateReplacements; + let variables: LabelVariables; switch (item.t) { case "local": - replacements = this.getLocalInterpolateReplacements(item); + variables = this.getLocalVariables(item); break; case "variant-analysis": - replacements = this.getVariantAnalysisInterpolateReplacements(item); + variables = this.getVariantAnalysisVariables(item); break; default: assertNever(item); } - const rawLabel = item.userSpecifiedLabel ?? (this.config.format || "%q"); + const rawLabel = + item.userSpecifiedLabel ?? (this.config.format || "${queryName}"); - return this.interpolate(rawLabel, replacements); + if (legacyLabelRegex.test(rawLabel)) { + return this.legacyInterpolate(rawLabel, variables); + } + + return substituteConfigVariables(rawLabel, variables).replace(/\s+/g, " "); } /** @@ -59,55 +83,60 @@ export class HistoryItemLabelProvider { : getRawQueryName(item); } - private interpolate( + private legacyInterpolate( rawLabel: string, - replacements: InterpolateReplacements, + variables: LabelVariables, ): string { - const label = rawLabel.replace( - /%(.)/g, - (match, key: keyof InterpolateReplacements) => { - const replacement = replacements[key]; - return replacement !== undefined ? replacement : match; + const replacements = Object.entries(variables).reduce( + (acc, [key, value]) => { + acc[ + legacyVariableInterpolateReplacements[key as keyof LabelVariables] + ] = value; + return acc; }, + { + "%": "%", + } as Record, ); + const label = rawLabel.replace(/%(.)/g, (match, key: string) => { + const replacement = replacements[key]; + return replacement !== undefined ? replacement : match; + }); + return label.replace(/\s+/g, " "); } - private getLocalInterpolateReplacements( - item: LocalQueryInfo, - ): InterpolateReplacements { + private getLocalVariables(item: LocalQueryInfo): LabelVariables { const { resultCount = 0, message = "in progress" } = item.completedQuery || {}; return { - t: item.startTime, - q: item.getQueryName(), - d: item.databaseName, - r: `(${resultCount} results)`, - s: message, - f: item.getQueryFileName(), - l: this.getLanguageLabel(item), - "%": "%", + startTime: item.startTime, + queryName: item.getQueryName(), + databaseName: item.databaseName, + resultCount: `(${resultCount} results)`, + status: message, + queryFileBasename: item.getQueryFileName(), + queryLanguage: this.getLanguageLabel(item), }; } - private getVariantAnalysisInterpolateReplacements( + private getVariantAnalysisVariables( item: VariantAnalysisHistoryItem, - ): InterpolateReplacements { + ): LabelVariables { const resultCount = item.resultCount ? `(${pluralize(item.resultCount, "result", "results")})` : ""; return { - t: new Date(item.variantAnalysis.executionStartTime).toLocaleString( - env.language, - ), - q: `${item.variantAnalysis.query.name} (${item.variantAnalysis.language})`, - d: buildRepoLabel(item), - r: resultCount, - s: humanizeQueryStatus(item.status), - f: basename(item.variantAnalysis.query.filePath), - l: this.getLanguageLabel(item), - "%": "%", + startTime: new Date( + item.variantAnalysis.executionStartTime, + ).toLocaleString(env.language), + queryName: `${item.variantAnalysis.query.name} (${item.variantAnalysis.language})`, + databaseName: buildRepoLabel(item), + resultCount, + status: humanizeQueryStatus(item.status), + queryFileBasename: basename(item.variantAnalysis.query.filePath), + queryLanguage: this.getLanguageLabel(item), }; } diff --git a/extensions/ql-vscode/test/vscode-tests/no-workspace/query-history/history-item-label-provider.test.ts b/extensions/ql-vscode/test/vscode-tests/no-workspace/query-history/history-item-label-provider.test.ts index 0cd2b3463..3ed0a7ee6 100644 --- a/extensions/ql-vscode/test/vscode-tests/no-workspace/query-history/history-item-label-provider.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/no-workspace/query-history/history-item-label-provider.test.ts @@ -21,241 +21,489 @@ describe("HistoryItemLabelProvider", () => { beforeEach(() => { config = { - format: "xxx %q xxx", + format: "xxx ${queryName} xxx", ttlInMillis: 0, onDidChangeConfiguration: jest.fn(), }; labelProvider = new HistoryItemLabelProvider(config); }); - describe("local queries", () => { - it("should interpolate query when user specified", () => { - const fqi = createMockLocalQueryInfo({ - startTime: date, - userSpecifiedLabel, - resultCount: 456, - hasMetadata: true, + describe("modern format", () => { + describe("local queries", () => { + it("should interpolate query when user specified", () => { + const fqi = createMockLocalQueryInfo({ + startTime: date, + userSpecifiedLabel, + resultCount: 456, + hasMetadata: true, + }); + + expect(labelProvider.getLabel(fqi)).toBe("user-specified-name"); + + fqi.userSpecifiedLabel = + "${startTime} ${queryName} ${databaseName} ${status} ${queryFileBasename} ${resultCount} %"; + expect(labelProvider.getLabel(fqi)).toBe( + `${dateStr} query-name db-name finished in 0 seconds query-file.ql (456 results) %`, + ); + + fqi.userSpecifiedLabel = "%t %q %d %s %f %r %%::%t %q %d %s %f %r %%"; + expect(labelProvider.getLabel(fqi)).toBe( + `${dateStr} query-name db-name finished in 0 seconds query-file.ql (456 results) %::${dateStr} query-name db-name finished in 0 seconds query-file.ql (456 results) %`, + ); }); - expect(labelProvider.getLabel(fqi)).toBe("user-specified-name"); + it("should interpolate query when not user specified", () => { + const fqi = createMockLocalQueryInfo({ + startTime: date, + resultCount: 456, + hasMetadata: true, + }); - fqi.userSpecifiedLabel = "%t %q %d %s %f %r %%"; - expect(labelProvider.getLabel(fqi)).toBe( - `${dateStr} query-name db-name finished in 0 seconds query-file.ql (456 results) %`, - ); + expect(labelProvider.getLabel(fqi)).toBe("xxx query-name xxx"); - fqi.userSpecifiedLabel = "%t %q %d %s %f %r %%::%t %q %d %s %f %r %%"; - expect(labelProvider.getLabel(fqi)).toBe( - `${dateStr} query-name db-name finished in 0 seconds query-file.ql (456 results) %::${dateStr} query-name db-name finished in 0 seconds query-file.ql (456 results) %`, - ); + config.format = + "${startTime} ${queryName} ${databaseName} ${status} ${queryFileBasename} ${resultCount} %"; + expect(labelProvider.getLabel(fqi)).toBe( + `${dateStr} query-name db-name finished in 0 seconds query-file.ql (456 results) %`, + ); + + config.format = + "${startTime} ${queryName} ${databaseName} ${status} ${queryFileBasename} ${resultCount} %::${startTime} ${queryName} ${databaseName} ${status} ${queryFileBasename} ${resultCount} %"; + expect(labelProvider.getLabel(fqi)).toBe( + `${dateStr} query-name db-name finished in 0 seconds query-file.ql (456 results) %::${dateStr} query-name db-name finished in 0 seconds query-file.ql (456 results) %`, + ); + }); + + it("should get query short label", () => { + const fqi = createMockLocalQueryInfo({ + startTime: date, + userSpecifiedLabel, + hasMetadata: true, + resultCount: 456, + }); + + // fall back on user specified if one exists. + expect(labelProvider.getShortLabel(fqi)).toBe("user-specified-name"); + + // use query name if no user-specified label exists + fqi.userSpecifiedLabel = undefined; + expect(labelProvider.getShortLabel(fqi)).toBe("query-name"); + + // use file name if no user-specified label exists and the query is not yet completed (meaning it has no results) + const fqi2 = createMockLocalQueryInfo({ + startTime: date, + hasMetadata: true, + }); + expect(labelProvider.getShortLabel(fqi2)).toBe("query-file.ql"); + }); }); - it("should interpolate query when not user specified", () => { - const fqi = createMockLocalQueryInfo({ - startTime: date, - resultCount: 456, - hasMetadata: true, + describe("variant analyses", () => { + it("should interpolate query when user specified", () => { + const fqi = createMockVariantAnalysisHistoryItem({ + userSpecifiedLabel, + executionStartTime, + }); + + expect(labelProvider.getLabel(fqi)).toBe(userSpecifiedLabel); + + fqi.userSpecifiedLabel = + "${startTime} ${queryName} ${databaseName} ${status} %"; + expect(labelProvider.getLabel(fqi)).toBe( + `${dateStr} a-query-name (javascript) 1/3 repositories in progress %`, + ); + + fqi.userSpecifiedLabel = + "${startTime} ${queryName} ${databaseName} ${status} %::${startTime} ${queryName} ${databaseName} ${status} %"; + expect(labelProvider.getLabel(fqi)).toBe( + `${dateStr} a-query-name (javascript) 1/3 repositories in progress %::${dateStr} a-query-name (javascript) 1/3 repositories in progress %`, + ); }); - expect(labelProvider.getLabel(fqi)).toBe("xxx query-name xxx"); + it("should interpolate query when not user-specified", () => { + const fqi = createMockVariantAnalysisHistoryItem({ + historyItemStatus: QueryStatus.Completed, + variantAnalysisStatus: VariantAnalysisStatus.Succeeded, + executionStartTime, + resultCount: 16, + }); - config.format = "%t %q %d %s %f %r %%"; - expect(labelProvider.getLabel(fqi)).toBe( - `${dateStr} query-name db-name finished in 0 seconds query-file.ql (456 results) %`, - ); + expect(labelProvider.getLabel(fqi)).toBe( + "xxx a-query-name (javascript) xxx", + ); - config.format = "%t %q %d %s %f %r %%::%t %q %d %s %f %r %%"; - expect(labelProvider.getLabel(fqi)).toBe( - `${dateStr} query-name db-name finished in 0 seconds query-file.ql (456 results) %::${dateStr} query-name db-name finished in 0 seconds query-file.ql (456 results) %`, - ); - }); + config.format = + "${startTime} ${queryName} ${databaseName} ${status} ${queryFileBasename} ${resultCount} %"; + expect(labelProvider.getLabel(fqi)).toBe( + `${dateStr} a-query-name (javascript) 1/3 repositories completed a-query-file-path (16 results) %`, + ); - it("should get query short label", () => { - const fqi = createMockLocalQueryInfo({ - startTime: date, - userSpecifiedLabel, - hasMetadata: true, - resultCount: 456, + config.format = + "${startTime} ${queryName} ${databaseName} ${status} ${queryFileBasename} ${resultCount} %::${startTime} ${queryName} ${databaseName} ${status} ${queryFileBasename} ${resultCount} %"; + expect(labelProvider.getLabel(fqi)).toBe( + `${dateStr} a-query-name (javascript) 1/3 repositories completed a-query-file-path (16 results) %::${dateStr} a-query-name (javascript) 1/3 repositories completed a-query-file-path (16 results) %`, + ); }); - // fall back on user specified if one exists. - expect(labelProvider.getShortLabel(fqi)).toBe("user-specified-name"); + it("should get query short label", () => { + const fqi = createMockVariantAnalysisHistoryItem({ + historyItemStatus: QueryStatus.Completed, + variantAnalysisStatus: VariantAnalysisStatus.Succeeded, + executionStartTime, + userSpecifiedLabel, + }); - // use query name if no user-specified label exists - fqi.userSpecifiedLabel = undefined; - expect(labelProvider.getShortLabel(fqi)).toBe("query-name"); + // fall back on user specified if one exists. + expect(labelProvider.getShortLabel(fqi)).toBe("user-specified-name"); - // use file name if no user-specified label exists and the query is not yet completed (meaning it has no results) - const fqi2 = createMockLocalQueryInfo({ - startTime: date, - hasMetadata: true, + // use query name if no user-specified label exists + const fqi2 = createMockVariantAnalysisHistoryItem({}); + + expect(labelProvider.getShortLabel(fqi2)).toBe("a-query-name"); + }); + + describe("when results are present", () => { + it("should display results if there are any", () => { + const fqi = createMockVariantAnalysisHistoryItem({ + historyItemStatus: QueryStatus.Completed, + resultCount: 16, + variantAnalysis: createMockVariantAnalysis({ + status: VariantAnalysisStatus.Succeeded, + executionStartTime, + scannedRepos: createMockScannedRepos([ + VariantAnalysisRepoStatus.Succeeded, + VariantAnalysisRepoStatus.Succeeded, + ]), + }), + }); + config.format = + "${startTime} ${queryName} ${databaseName} ${status} ${queryFileBasename} ${resultCount} %"; + expect(labelProvider.getLabel(fqi)).toBe( + `${dateStr} a-query-name (javascript) 2/2 repositories completed a-query-file-path (16 results) %`, + ); + }); + }); + + describe("when results are not present", () => { + it("should skip displaying them", () => { + const fqi = createMockVariantAnalysisHistoryItem({ + historyItemStatus: QueryStatus.Completed, + resultCount: 0, + variantAnalysis: createMockVariantAnalysis({ + status: VariantAnalysisStatus.Succeeded, + executionStartTime, + scannedRepos: createMockScannedRepos([ + VariantAnalysisRepoStatus.Succeeded, + VariantAnalysisRepoStatus.Succeeded, + ]), + }), + }); + config.format = + "${startTime} ${queryName} ${databaseName} ${status} ${queryFileBasename} ${resultCount} %"; + expect(labelProvider.getLabel(fqi)).toBe( + `${dateStr} a-query-name (javascript) 2/2 repositories completed a-query-file-path %`, + ); + }); + }); + + describe("when extra whitespace is present in the middle of the label", () => { + it("should squash it down to a single whitespace", () => { + const fqi = createMockVariantAnalysisHistoryItem({ + historyItemStatus: QueryStatus.Completed, + resultCount: 0, + variantAnalysis: createMockVariantAnalysis({ + status: VariantAnalysisStatus.Succeeded, + executionStartTime, + scannedRepos: createMockScannedRepos([ + VariantAnalysisRepoStatus.Succeeded, + VariantAnalysisRepoStatus.Succeeded, + ]), + }), + }); + config.format = + "${startTime} ${queryName} ${databaseName} ${status} ${queryFileBasename} ${resultCount} %"; + expect(labelProvider.getLabel(fqi)).toBe( + `${dateStr} a-query-name (javascript) 2/2 repositories completed a-query-file-path %`, + ); + }); + }); + + describe("when extra whitespace is present at the start of the label", () => { + it("should squash it down to a single whitespace", () => { + const fqi = createMockVariantAnalysisHistoryItem({ + historyItemStatus: QueryStatus.Completed, + resultCount: 0, + variantAnalysis: createMockVariantAnalysis({ + status: VariantAnalysisStatus.Succeeded, + executionStartTime, + scannedRepos: createMockScannedRepos([ + VariantAnalysisRepoStatus.Succeeded, + VariantAnalysisRepoStatus.Succeeded, + ]), + }), + }); + config.format = + " ${startTime} ${queryName} ${databaseName} ${status} ${queryFileBasename} ${resultCount} %"; + expect(labelProvider.getLabel(fqi)).toBe( + ` ${dateStr} a-query-name (javascript) 2/2 repositories completed a-query-file-path %`, + ); + }); + }); + + describe("when extra whitespace is present at the end of the label", () => { + it("should squash it down to a single whitespace", () => { + const fqi = createMockVariantAnalysisHistoryItem({ + historyItemStatus: QueryStatus.Completed, + resultCount: 0, + variantAnalysis: createMockVariantAnalysis({ + status: VariantAnalysisStatus.Succeeded, + executionStartTime, + scannedRepos: createMockScannedRepos([ + VariantAnalysisRepoStatus.Succeeded, + VariantAnalysisRepoStatus.Succeeded, + ]), + }), + }); + config.format = + "${startTime} ${queryName} ${databaseName} ${status} ${queryFileBasename} ${resultCount} % "; + expect(labelProvider.getLabel(fqi)).toBe( + `${dateStr} a-query-name (javascript) 2/2 repositories completed a-query-file-path % `, + ); + }); }); - expect(labelProvider.getShortLabel(fqi2)).toBe("query-file.ql"); }); }); - describe("variant analyses", () => { - it("should interpolate query when user specified", () => { - const fqi = createMockVariantAnalysisHistoryItem({ - userSpecifiedLabel, - executionStartTime, + describe("legacy format", () => { + describe("local queries", () => { + it("should interpolate query when user specified", () => { + const fqi = createMockLocalQueryInfo({ + startTime: date, + userSpecifiedLabel, + resultCount: 456, + hasMetadata: true, + }); + + expect(labelProvider.getLabel(fqi)).toBe("user-specified-name"); + + fqi.userSpecifiedLabel = "%t %q %d %s %f %r %%"; + expect(labelProvider.getLabel(fqi)).toBe( + `${dateStr} query-name db-name finished in 0 seconds query-file.ql (456 results) %`, + ); + + fqi.userSpecifiedLabel = "%t %q %d %s %f %r %%::%t %q %d %s %f %r %%"; + expect(labelProvider.getLabel(fqi)).toBe( + `${dateStr} query-name db-name finished in 0 seconds query-file.ql (456 results) %::${dateStr} query-name db-name finished in 0 seconds query-file.ql (456 results) %`, + ); }); - expect(labelProvider.getLabel(fqi)).toBe(userSpecifiedLabel); + it("should interpolate query when not user specified", () => { + const fqi = createMockLocalQueryInfo({ + startTime: date, + resultCount: 456, + hasMetadata: true, + }); - fqi.userSpecifiedLabel = "%t %q %d %s %%"; - expect(labelProvider.getLabel(fqi)).toBe( - `${dateStr} a-query-name (javascript) 1/3 repositories in progress %`, - ); + expect(labelProvider.getLabel(fqi)).toBe("xxx query-name xxx"); - fqi.userSpecifiedLabel = "%t %q %d %s %%::%t %q %d %s %%"; - expect(labelProvider.getLabel(fqi)).toBe( - `${dateStr} a-query-name (javascript) 1/3 repositories in progress %::${dateStr} a-query-name (javascript) 1/3 repositories in progress %`, - ); - }); + config.format = "%t %q %d %s %f %r %%"; + expect(labelProvider.getLabel(fqi)).toBe( + `${dateStr} query-name db-name finished in 0 seconds query-file.ql (456 results) %`, + ); - it("should interpolate query when not user-specified", () => { - const fqi = createMockVariantAnalysisHistoryItem({ - historyItemStatus: QueryStatus.Completed, - variantAnalysisStatus: VariantAnalysisStatus.Succeeded, - executionStartTime, - resultCount: 16, + config.format = "%t %q %d %s %f %r %%::%t %q %d %s %f %r %%"; + expect(labelProvider.getLabel(fqi)).toBe( + `${dateStr} query-name db-name finished in 0 seconds query-file.ql (456 results) %::${dateStr} query-name db-name finished in 0 seconds query-file.ql (456 results) %`, + ); }); - expect(labelProvider.getLabel(fqi)).toBe( - "xxx a-query-name (javascript) xxx", - ); + it("should get query short label", () => { + const fqi = createMockLocalQueryInfo({ + startTime: date, + userSpecifiedLabel, + hasMetadata: true, + resultCount: 456, + }); - config.format = "%t %q %d %s %f %r %%"; - expect(labelProvider.getLabel(fqi)).toBe( - `${dateStr} a-query-name (javascript) 1/3 repositories completed a-query-file-path (16 results) %`, - ); + // fall back on user specified if one exists. + expect(labelProvider.getShortLabel(fqi)).toBe("user-specified-name"); - config.format = "%t %q %d %s %f %r %%::%t %q %d %s %f %r %%"; - expect(labelProvider.getLabel(fqi)).toBe( - `${dateStr} a-query-name (javascript) 1/3 repositories completed a-query-file-path (16 results) %::${dateStr} a-query-name (javascript) 1/3 repositories completed a-query-file-path (16 results) %`, - ); + // use query name if no user-specified label exists + fqi.userSpecifiedLabel = undefined; + expect(labelProvider.getShortLabel(fqi)).toBe("query-name"); + + // use file name if no user-specified label exists and the query is not yet completed (meaning it has no results) + const fqi2 = createMockLocalQueryInfo({ + startTime: date, + hasMetadata: true, + }); + expect(labelProvider.getShortLabel(fqi2)).toBe("query-file.ql"); + }); }); - it("should get query short label", () => { - const fqi = createMockVariantAnalysisHistoryItem({ - historyItemStatus: QueryStatus.Completed, - variantAnalysisStatus: VariantAnalysisStatus.Succeeded, - executionStartTime, - userSpecifiedLabel, + describe("variant analyses", () => { + it("should interpolate query when user specified", () => { + const fqi = createMockVariantAnalysisHistoryItem({ + userSpecifiedLabel, + executionStartTime, + }); + + expect(labelProvider.getLabel(fqi)).toBe(userSpecifiedLabel); + + fqi.userSpecifiedLabel = "%t %q %d %s %%"; + expect(labelProvider.getLabel(fqi)).toBe( + `${dateStr} a-query-name (javascript) 1/3 repositories in progress %`, + ); + + fqi.userSpecifiedLabel = "%t %q %d %s %%::%t %q %d %s %%"; + expect(labelProvider.getLabel(fqi)).toBe( + `${dateStr} a-query-name (javascript) 1/3 repositories in progress %::${dateStr} a-query-name (javascript) 1/3 repositories in progress %`, + ); }); - // fall back on user specified if one exists. - expect(labelProvider.getShortLabel(fqi)).toBe("user-specified-name"); - - // use query name if no user-specified label exists - const fqi2 = createMockVariantAnalysisHistoryItem({}); - - expect(labelProvider.getShortLabel(fqi2)).toBe("a-query-name"); - }); - - describe("when results are present", () => { - it("should display results if there are any", () => { + it("should interpolate query when not user-specified", () => { const fqi = createMockVariantAnalysisHistoryItem({ historyItemStatus: QueryStatus.Completed, + variantAnalysisStatus: VariantAnalysisStatus.Succeeded, + executionStartTime, resultCount: 16, - variantAnalysis: createMockVariantAnalysis({ - status: VariantAnalysisStatus.Succeeded, - executionStartTime, - scannedRepos: createMockScannedRepos([ - VariantAnalysisRepoStatus.Succeeded, - VariantAnalysisRepoStatus.Succeeded, - ]), - }), }); + + expect(labelProvider.getLabel(fqi)).toBe( + "xxx a-query-name (javascript) xxx", + ); + config.format = "%t %q %d %s %f %r %%"; expect(labelProvider.getLabel(fqi)).toBe( - `${dateStr} a-query-name (javascript) 2/2 repositories completed a-query-file-path (16 results) %`, + `${dateStr} a-query-name (javascript) 1/3 repositories completed a-query-file-path (16 results) %`, + ); + + config.format = "%t %q %d %s %f %r %%::%t %q %d %s %f %r %%"; + expect(labelProvider.getLabel(fqi)).toBe( + `${dateStr} a-query-name (javascript) 1/3 repositories completed a-query-file-path (16 results) %::${dateStr} a-query-name (javascript) 1/3 repositories completed a-query-file-path (16 results) %`, ); }); - }); - describe("when results are not present", () => { - it("should skip displaying them", () => { + it("should get query short label", () => { const fqi = createMockVariantAnalysisHistoryItem({ historyItemStatus: QueryStatus.Completed, - resultCount: 0, - variantAnalysis: createMockVariantAnalysis({ - status: VariantAnalysisStatus.Succeeded, - executionStartTime, - scannedRepos: createMockScannedRepos([ - VariantAnalysisRepoStatus.Succeeded, - VariantAnalysisRepoStatus.Succeeded, - ]), - }), + variantAnalysisStatus: VariantAnalysisStatus.Succeeded, + executionStartTime, + userSpecifiedLabel, }); - config.format = "%t %q %d %s %f %r %%"; - expect(labelProvider.getLabel(fqi)).toBe( - `${dateStr} a-query-name (javascript) 2/2 repositories completed a-query-file-path %`, - ); + + // fall back on user specified if one exists. + expect(labelProvider.getShortLabel(fqi)).toBe("user-specified-name"); + + // use query name if no user-specified label exists + const fqi2 = createMockVariantAnalysisHistoryItem({}); + + expect(labelProvider.getShortLabel(fqi2)).toBe("a-query-name"); }); - }); - describe("when extra whitespace is present in the middle of the label", () => { - it("should squash it down to a single whitespace", () => { - const fqi = createMockVariantAnalysisHistoryItem({ - historyItemStatus: QueryStatus.Completed, - resultCount: 0, - variantAnalysis: createMockVariantAnalysis({ - status: VariantAnalysisStatus.Succeeded, - executionStartTime, - scannedRepos: createMockScannedRepos([ - VariantAnalysisRepoStatus.Succeeded, - VariantAnalysisRepoStatus.Succeeded, - ]), - }), + describe("when results are present", () => { + it("should display results if there are any", () => { + const fqi = createMockVariantAnalysisHistoryItem({ + historyItemStatus: QueryStatus.Completed, + resultCount: 16, + variantAnalysis: createMockVariantAnalysis({ + status: VariantAnalysisStatus.Succeeded, + executionStartTime, + scannedRepos: createMockScannedRepos([ + VariantAnalysisRepoStatus.Succeeded, + VariantAnalysisRepoStatus.Succeeded, + ]), + }), + }); + config.format = "%t %q %d %s %f %r %%"; + expect(labelProvider.getLabel(fqi)).toBe( + `${dateStr} a-query-name (javascript) 2/2 repositories completed a-query-file-path (16 results) %`, + ); }); - config.format = "%t %q %d %s %f %r %%"; - expect(labelProvider.getLabel(fqi)).toBe( - `${dateStr} a-query-name (javascript) 2/2 repositories completed a-query-file-path %`, - ); }); - }); - describe("when extra whitespace is present at the start of the label", () => { - it("should squash it down to a single whitespace", () => { - const fqi = createMockVariantAnalysisHistoryItem({ - historyItemStatus: QueryStatus.Completed, - resultCount: 0, - variantAnalysis: createMockVariantAnalysis({ - status: VariantAnalysisStatus.Succeeded, - executionStartTime, - scannedRepos: createMockScannedRepos([ - VariantAnalysisRepoStatus.Succeeded, - VariantAnalysisRepoStatus.Succeeded, - ]), - }), + describe("when results are not present", () => { + it("should skip displaying them", () => { + const fqi = createMockVariantAnalysisHistoryItem({ + historyItemStatus: QueryStatus.Completed, + resultCount: 0, + variantAnalysis: createMockVariantAnalysis({ + status: VariantAnalysisStatus.Succeeded, + executionStartTime, + scannedRepos: createMockScannedRepos([ + VariantAnalysisRepoStatus.Succeeded, + VariantAnalysisRepoStatus.Succeeded, + ]), + }), + }); + config.format = "%t %q %d %s %f %r %%"; + expect(labelProvider.getLabel(fqi)).toBe( + `${dateStr} a-query-name (javascript) 2/2 repositories completed a-query-file-path %`, + ); }); - config.format = " %t %q %d %s %f %r %%"; - expect(labelProvider.getLabel(fqi)).toBe( - ` ${dateStr} a-query-name (javascript) 2/2 repositories completed a-query-file-path %`, - ); }); - }); - describe("when extra whitespace is present at the end of the label", () => { - it("should squash it down to a single whitespace", () => { - const fqi = createMockVariantAnalysisHistoryItem({ - historyItemStatus: QueryStatus.Completed, - resultCount: 0, - variantAnalysis: createMockVariantAnalysis({ - status: VariantAnalysisStatus.Succeeded, - executionStartTime, - scannedRepos: createMockScannedRepos([ - VariantAnalysisRepoStatus.Succeeded, - VariantAnalysisRepoStatus.Succeeded, - ]), - }), + describe("when extra whitespace is present in the middle of the label", () => { + it("should squash it down to a single whitespace", () => { + const fqi = createMockVariantAnalysisHistoryItem({ + historyItemStatus: QueryStatus.Completed, + resultCount: 0, + variantAnalysis: createMockVariantAnalysis({ + status: VariantAnalysisStatus.Succeeded, + executionStartTime, + scannedRepos: createMockScannedRepos([ + VariantAnalysisRepoStatus.Succeeded, + VariantAnalysisRepoStatus.Succeeded, + ]), + }), + }); + config.format = "%t %q %d %s %f %r %%"; + expect(labelProvider.getLabel(fqi)).toBe( + `${dateStr} a-query-name (javascript) 2/2 repositories completed a-query-file-path %`, + ); + }); + }); + + describe("when extra whitespace is present at the start of the label", () => { + it("should squash it down to a single whitespace", () => { + const fqi = createMockVariantAnalysisHistoryItem({ + historyItemStatus: QueryStatus.Completed, + resultCount: 0, + variantAnalysis: createMockVariantAnalysis({ + status: VariantAnalysisStatus.Succeeded, + executionStartTime, + scannedRepos: createMockScannedRepos([ + VariantAnalysisRepoStatus.Succeeded, + VariantAnalysisRepoStatus.Succeeded, + ]), + }), + }); + config.format = " %t %q %d %s %f %r %%"; + expect(labelProvider.getLabel(fqi)).toBe( + ` ${dateStr} a-query-name (javascript) 2/2 repositories completed a-query-file-path %`, + ); + }); + }); + + describe("when extra whitespace is present at the end of the label", () => { + it("should squash it down to a single whitespace", () => { + const fqi = createMockVariantAnalysisHistoryItem({ + historyItemStatus: QueryStatus.Completed, + resultCount: 0, + variantAnalysis: createMockVariantAnalysis({ + status: VariantAnalysisStatus.Succeeded, + executionStartTime, + scannedRepos: createMockScannedRepos([ + VariantAnalysisRepoStatus.Succeeded, + VariantAnalysisRepoStatus.Succeeded, + ]), + }), + }); + config.format = "%t %q %d %s %f %r %% "; + expect(labelProvider.getLabel(fqi)).toBe( + `${dateStr} a-query-name (javascript) 2/2 repositories completed a-query-file-path % `, + ); }); - config.format = "%t %q %d %s %f %r %% "; - expect(labelProvider.getLabel(fqi)).toBe( - `${dateStr} a-query-name (javascript) 2/2 repositories completed a-query-file-path % `, - ); }); }); });