Remove remote queries history item

This removes the remote queries history item as a supported history
item. This allows us to delete almost all code related to remote
queries except for the React view code which will be removed separately.

In the query serialization code, we now ignore remote queries.
This commit is contained in:
Koen Vlaswinkel
2023-02-14 10:19:59 +01:00
parent 89860d4f84
commit fb4d6db03d
24 changed files with 148 additions and 850 deletions

View File

@@ -652,7 +652,6 @@ async function activateWithInstalledDistribution(
void extLogger.log("Initializing query history.");
const qhm = new QueryHistoryManager(
app,
qs,
dbm,
localQueryResultsView,

View File

@@ -7,7 +7,6 @@ import {
getRawQueryName,
QueryHistoryInfo,
} from "./query-history-info";
import { RemoteQueryHistoryItem } from "../remote-queries/remote-query-history-item";
import { VariantAnalysisHistoryItem } from "./variant-analysis-history-item";
import { assertNever } from "../pure/helpers-pure";
import { pluralize } from "../pure/word";
@@ -34,9 +33,6 @@ export class HistoryItemLabelProvider {
case "local":
replacements = this.getLocalInterpolateReplacements(item);
break;
case "remote":
replacements = this.getRemoteInterpolateReplacements(item);
break;
case "variant-analysis":
replacements = this.getVariantAnalysisInterpolateReplacements(item);
break;
@@ -92,25 +88,6 @@ export class HistoryItemLabelProvider {
};
}
private getRemoteInterpolateReplacements(
item: RemoteQueryHistoryItem,
): InterpolateReplacements {
const resultCount = item.resultCount
? `(${pluralize(item.resultCount, "result", "results")})`
: "";
return {
t: new Date(item.remoteQuery.executionStartTime).toLocaleString(
env.language,
),
q: `${item.remoteQuery.queryName} (${item.remoteQuery.language})`,
d: buildRepoLabel(item),
r: resultCount,
s: humanizeQueryStatus(item.status),
f: basename(item.remoteQuery.queryFilePath),
"%": "%",
};
}
private getVariantAnalysisInterpolateReplacements(
item: VariantAnalysisHistoryItem,
): InterpolateReplacements {

View File

@@ -236,8 +236,6 @@ export class HistoryTreeDataProvider
switch (item.t) {
case "local":
return item.initialInfo.start.getTime();
case "remote":
return item.remoteQuery.executionStartTime;
case "variant-analysis":
return item.variantAnalysis.executionStartTime;
default:

View File

@@ -1,4 +1,3 @@
import { RemoteQueryHistoryItem } from "../remote-queries/remote-query-history-item";
import { VariantAnalysisHistoryItem } from "./variant-analysis-history-item";
import { LocalQueryInfo } from "../query-results";
import { assertNever } from "../pure/helpers-pure";
@@ -8,17 +7,12 @@ import {
getActionsWorkflowRunUrl as getVariantAnalysisActionsWorkflowRunUrl,
} from "../remote-queries/shared/variant-analysis";
export type QueryHistoryInfo =
| LocalQueryInfo
| RemoteQueryHistoryItem
| VariantAnalysisHistoryItem;
export type QueryHistoryInfo = LocalQueryInfo | VariantAnalysisHistoryItem;
export function getRawQueryName(item: QueryHistoryInfo): string {
switch (item.t) {
case "local":
return item.getQueryName();
case "remote":
return item.remoteQuery.queryName;
case "variant-analysis":
return item.variantAnalysis.query.name;
default:
@@ -37,8 +31,6 @@ export function getQueryId(item: QueryHistoryInfo): string {
switch (item.t) {
case "local":
return item.initialInfo.id;
case "remote":
return item.queryId;
case "variant-analysis":
return item.variantAnalysis.id.toString();
default:
@@ -50,8 +42,6 @@ export function getQueryText(item: QueryHistoryInfo): string {
switch (item.t) {
case "local":
return item.initialInfo.queryText;
case "remote":
return item.remoteQuery.queryText;
case "variant-analysis":
return item.variantAnalysis.query.text;
default:
@@ -59,47 +49,23 @@ export function getQueryText(item: QueryHistoryInfo): string {
}
}
export function buildRepoLabel(
item: RemoteQueryHistoryItem | VariantAnalysisHistoryItem,
): string {
if (item.t === "remote") {
// Return the number of repositories queried if available. Otherwise, use the controller repository name.
const repositoryCount = item.remoteQuery.repositoryCount;
export function buildRepoLabel(item: VariantAnalysisHistoryItem): string {
const totalScannedRepositoryCount =
item.variantAnalysis.scannedRepos?.length ?? 0;
const completedRepositoryCount =
item.variantAnalysis.scannedRepos?.filter((repo) =>
hasRepoScanCompleted(repo),
).length ?? 0;
if (repositoryCount) {
return pluralize(repositoryCount, "repository", "repositories");
}
return `${item.remoteQuery.controllerRepository.owner}/${item.remoteQuery.controllerRepository.name}`;
} else if (item.t === "variant-analysis") {
const totalScannedRepositoryCount =
item.variantAnalysis.scannedRepos?.length ?? 0;
const completedRepositoryCount =
item.variantAnalysis.scannedRepos?.filter((repo) =>
hasRepoScanCompleted(repo),
).length ?? 0;
return `${completedRepositoryCount}/${pluralize(
totalScannedRepositoryCount,
"repository",
"repositories",
)}`; // e.g. "2/3 repositories"
} else {
assertNever(item);
}
return `${completedRepositoryCount}/${pluralize(
totalScannedRepositoryCount,
"repository",
"repositories",
)}`; // e.g. "2/3 repositories"
}
export function getActionsWorkflowRunUrl(
item: RemoteQueryHistoryItem | VariantAnalysisHistoryItem,
item: VariantAnalysisHistoryItem,
): string {
if (item.t === "remote") {
const {
actionsWorkflowRunId: workflowRunId,
controllerRepository: { owner, name },
} = item.remoteQuery;
return `https://github.com/${owner}/${name}/actions/runs/${workflowRunId}`;
} else if (item.t === "variant-analysis") {
return getVariantAnalysisActionsWorkflowRunUrl(item.variantAnalysis);
} else {
assertNever(item);
}
return getVariantAnalysisActionsWorkflowRunUrl(item.variantAnalysis);
}

View File

@@ -53,8 +53,6 @@ import {
import { pathExists } from "fs-extra";
import { CliVersionConstraint } from "../cli";
import { HistoryItemLabelProvider } from "./history-item-label-provider";
import { cancelRemoteQuery } from "../remote-queries/gh-api/gh-actions-api-client";
import { RemoteQueryHistoryItem } from "../remote-queries/remote-query-history-item";
import { ResultsView } from "../interface";
import { WebviewReveal } from "../interface-utils";
import { EvalLogViewer } from "../eval-log-viewer";
@@ -65,7 +63,6 @@ import { QueryRunner } from "../queryRunner";
import { VariantAnalysisManager } from "../remote-queries/variant-analysis-manager";
import { VariantAnalysisHistoryItem } from "./variant-analysis-history-item";
import { getTotalResultCount } from "../remote-queries/shared/variant-analysis";
import { App } from "../common/app";
import { HistoryTreeDataProvider } from "./history-tree-data-provider";
import { redactableError } from "../pure/errors";
@@ -137,7 +134,6 @@ export class QueryHistoryManager extends DisposableObject {
readonly onDidCompleteQuery = this._onDidCompleteQuery.event;
constructor(
private readonly app: App,
private readonly qs: QueryRunner,
private readonly dbm: DatabaseManager,
private readonly localQueriesResultsView: ResultsView,
@@ -525,9 +521,6 @@ export class QueryHistoryManager extends DisposableObject {
case "local":
queryPath = finalSingleItem.initialInfo.queryPath;
break;
case "remote":
queryPath = finalSingleItem.remoteQuery.queryFilePath;
break;
default:
assertNever(finalSingleItem);
}
@@ -553,12 +546,6 @@ export class QueryHistoryManager extends DisposableObject {
return this.treeDataProvider.getCurrent();
}
getRemoteQueryById(queryId: string): RemoteQueryHistoryItem | undefined {
return this.treeDataProvider.allHistory.find(
(i) => i.t === "remote" && i.queryId === queryId,
) as RemoteQueryHistoryItem;
}
async removeDeletedQueries() {
await Promise.all(
this.treeDataProvider.allHistory.map(async (item) => {
@@ -595,8 +582,6 @@ export class QueryHistoryManager extends DisposableObject {
// We need to delete it from disk as well.
await item.completedQuery?.query.deleteQuery();
}
} else if (item.t === "remote") {
// Do nothing. TODO: Remove once remote queries are no longer supported.
} else if (item.t === "variant-analysis") {
await this.removeVariantAnalysis(item);
} else {
@@ -808,8 +793,6 @@ export class QueryHistoryManager extends DisposableObject {
if (queryHistoryItem.completedQuery) {
return queryHistoryItem.completedQuery.query.querySaveDir;
}
} else if (queryHistoryItem.t === "remote") {
return join(this.queryStorageDir, queryHistoryItem.queryId);
} else if (queryHistoryItem.t === "variant-analysis") {
return this.variantAnalysisManager.getVariantAnalysisStorageLocation(
queryHistoryItem.variantAnalysis.id,
@@ -840,12 +823,6 @@ export class QueryHistoryManager extends DisposableObject {
"timestamp",
);
}
} else if (finalSingleItem.t === "remote") {
externalFilePath = join(
this.queryStorageDir,
finalSingleItem.queryId,
"timestamp",
);
} else if (finalSingleItem.t === "variant-analysis") {
externalFilePath = join(
this.variantAnalysisManager.getVariantAnalysisStorageLocation(
@@ -1012,11 +989,6 @@ export class QueryHistoryManager extends DisposableObject {
if (item.status === QueryStatus.InProgress) {
if (item.t === "local") {
item.cancel();
} else if (item.t === "remote") {
void showAndLogInformationMessage(
"Cancelling variant analysis. This may take a while.",
);
await cancelRemoteQuery(this.app.credentials, item.remoteQuery);
} else if (item.t === "variant-analysis") {
await commands.executeCommand(
"codeQL.cancelVariantAnalysis",
@@ -1239,10 +1211,8 @@ export class QueryHistoryManager extends DisposableObject {
return;
}
// Remote queries and variant analysis only
if (finalSingleItem.t === "remote") {
// Do nothing. TODO: Remove this case once remote queries are removed.
} else if (finalSingleItem.t === "variant-analysis") {
// Variant analysis only
if (finalSingleItem.t === "variant-analysis") {
await commands.executeCommand(
"codeQL.exportVariantAnalysisResults",
finalSingleItem.variantAnalysis.id,
@@ -1475,8 +1445,6 @@ the file in the file explorer and dragging it into the workspace.`,
WebviewReveal.Forced,
false,
);
} else if (item.t === "remote") {
// Do nothing. TODO: Remove when remote queries is no longer supported.
} else if (item.t === "variant-analysis") {
await this.variantAnalysisManager.showView(item.variantAnalysis.id);
} else {

View File

@@ -10,7 +10,6 @@ import {
} from "./pure/helpers-pure";
import { CompletedQueryInfo, LocalQueryInfo } from "./query-results";
import { QueryHistoryInfo } from "./query-history/query-history-info";
import { QueryStatus } from "./query-status";
import { QueryEvaluationInfo } from "./run-queries-shared";
import { QueryResultType } from "./pure/legacy-messages";
import { redactableError } from "./pure/errors";
@@ -33,58 +32,57 @@ export async function deserializeQueryHistory(
}
const queries = obj.queries;
const parsedQueries = queries.map((q: QueryHistoryInfo) => {
// Need to explicitly set prototype since reading in from JSON will not
// do this automatically. Note that we can't call the constructor here since
// the constructor invokes extra logic that we don't want to do.
if (q.t === "local") {
Object.setPrototypeOf(q, LocalQueryInfo.prototype);
const parsedQueries = queries
// Remove remote queries, which are not supported anymore.
.filter((q: QueryHistoryInfo | { t: "remote" }) => q.t !== "remote")
.map((q: QueryHistoryInfo) => {
// Need to explicitly set prototype since reading in from JSON will not
// do this automatically. Note that we can't call the constructor here since
// the constructor invokes extra logic that we don't want to do.
if (q.t === "local") {
Object.setPrototypeOf(q, LocalQueryInfo.prototype);
// Date instances are serialized as strings. Need to
// convert them back to Date instances.
(q.initialInfo as any).start = new Date(q.initialInfo.start);
if (q.completedQuery) {
// Again, need to explicitly set prototypes.
Object.setPrototypeOf(q.completedQuery, CompletedQueryInfo.prototype);
Object.setPrototypeOf(
q.completedQuery.query,
QueryEvaluationInfo.prototype,
);
// deserialized queries do not need to be disposed
q.completedQuery.dispose = () => {
/**/
};
// Date instances are serialized as strings. Need to
// convert them back to Date instances.
(q.initialInfo as any).start = new Date(q.initialInfo.start);
if (q.completedQuery) {
// Again, need to explicitly set prototypes.
Object.setPrototypeOf(
q.completedQuery,
CompletedQueryInfo.prototype,
);
Object.setPrototypeOf(
q.completedQuery.query,
QueryEvaluationInfo.prototype,
);
// deserialized queries do not need to be disposed
q.completedQuery.dispose = () => {
/**/
};
// Previously, there was a typo in the completedQuery type. There was a field
// `sucessful` and it was renamed to `successful`. We need to handle this case.
if ("sucessful" in q.completedQuery) {
(q.completedQuery as any).successful = (
q.completedQuery as any
).sucessful;
delete (q.completedQuery as any).sucessful;
}
// Previously, there was a typo in the completedQuery type. There was a field
// `sucessful` and it was renamed to `successful`. We need to handle this case.
if ("sucessful" in q.completedQuery) {
(q.completedQuery as any).successful = (
q.completedQuery as any
).sucessful;
delete (q.completedQuery as any).sucessful;
}
if (!("successful" in q.completedQuery)) {
(q.completedQuery as any).successful =
q.completedQuery.result?.resultType === QueryResultType.SUCCESS;
if (!("successful" in q.completedQuery)) {
(q.completedQuery as any).successful =
q.completedQuery.result?.resultType === QueryResultType.SUCCESS;
}
}
}
} else if (q.t === "remote") {
// A bug was introduced that didn't set the completed flag in query history
// items. The following code makes sure that the flag is set in order to
// "patch" older query history items.
if (q.status === QueryStatus.Completed) {
q.completed = true;
}
}
return q;
});
return q;
});
// filter out queries that have been deleted on disk
// most likely another workspace has deleted them because the
// queries aged out.
return asyncFilter(parsedQueries, async (q) => {
if (q.t === "remote" || q.t === "variant-analysis") {
if (q.t === "variant-analysis") {
// the deserializer doesn't know where the remote queries are stored
// so we need to assume here that they exist. Later, we check to
// see if they exist on disk.

View File

@@ -47,9 +47,7 @@ export async function exportSelectedRemoteQueryResults(
);
}
if (queryHistoryItem.t === "remote") {
// Do nothing. TODO: Remove this branch once we stop supporting remote queries.
} else if (queryHistoryItem.t === "variant-analysis") {
if (queryHistoryItem.t === "variant-analysis") {
return commands.executeCommand(
"codeQL.exportVariantAnalysisResults",
queryHistoryItem.variantAnalysis.id,

View File

@@ -1,33 +1,6 @@
import { join } from "path";
import { pathExists, writeFile } from "fs-extra";
import { Credentials } from "../../common/authentication";
import { extLogger } from "../../common";
import { createDownloadPath, DownloadLink } from "../download-link";
import { RemoteQuery } from "../remote-query";
import { unzipFile } from "../../pure/zip";
import { VariantAnalysis } from "../shared/variant-analysis";
export async function cancelRemoteQuery(
credentials: Credentials,
remoteQuery: RemoteQuery,
): Promise<void> {
const octokit = await credentials.getOctokit();
const {
actionsWorkflowRunId,
controllerRepository: { owner, name },
} = remoteQuery;
const response = await octokit.request(
`POST /repos/${owner}/${name}/actions/runs/${actionsWorkflowRunId}/cancel`,
);
if (response.status >= 300) {
throw new Error(
`Error cancelling variant analysis: ${response.status} ${
response?.data?.message || ""
}`,
);
}
}
export async function cancelVariantAnalysis(
credentials: Credentials,
variantAnalysis: VariantAnalysis,
@@ -48,39 +21,3 @@ export async function cancelVariantAnalysis(
);
}
}
export async function downloadArtifactFromLink(
credentials: Credentials,
storagePath: string,
downloadLink: DownloadLink,
): Promise<string> {
const octokit = await credentials.getOctokit();
const extractedPath = createDownloadPath(storagePath, downloadLink);
// first check if we already have the artifact
if (!(await pathExists(extractedPath))) {
// Download the zipped artifact.
const response = await octokit.request(
`GET ${downloadLink.urlPath}/zip`,
{},
);
const zipFilePath = createDownloadPath(storagePath, downloadLink, "zip");
await unzipBuffer(response.data as ArrayBuffer, zipFilePath, extractedPath);
}
return join(extractedPath, downloadLink.innerFilePath || "");
}
async function unzipBuffer(
data: ArrayBuffer,
filePath: string,
destinationPath: string,
): Promise<void> {
void extLogger.log(`Saving file to ${filePath}`);
await writeFile(filePath, Buffer.from(data));
void extLogger.log(`Unzipping file to ${destinationPath}`);
await unzipFile(filePath, destinationPath);
}

View File

@@ -1,6 +1,5 @@
import { OctokitResponse } from "@octokit/types/dist-types";
import { Credentials } from "../../common/authentication";
import { RemoteQueriesSubmission } from "../shared/remote-queries";
import { VariantAnalysisSubmission } from "../shared/variant-analysis";
import {
VariantAnalysis,
@@ -8,10 +7,6 @@ import {
VariantAnalysisSubmissionRequest,
} from "./variant-analysis";
import { Repository } from "./repository";
import {
RemoteQueriesResponse,
RemoteQueriesSubmissionRequest,
} from "./remote-queries";
export async function submitVariantAnalysis(
credentials: Credentials,
@@ -116,40 +111,3 @@ export async function createGist(
}
return response.data.html_url;
}
export async function submitRemoteQueries(
credentials: Credentials,
submissionDetails: RemoteQueriesSubmission,
): Promise<RemoteQueriesResponse> {
const octokit = await credentials.getOctokit();
const {
ref,
language,
repositories,
repositoryLists,
repositoryOwners,
queryPack,
controllerRepoId,
} = submissionDetails;
const data: RemoteQueriesSubmissionRequest = {
ref,
language,
repositories,
repository_lists: repositoryLists,
repository_owners: repositoryOwners,
query_pack: queryPack,
};
const response: OctokitResponse<RemoteQueriesResponse> =
await octokit.request(
"POST /repositories/:controllerRepoId/code-scanning/codeql/queries",
{
controllerRepoId,
data,
},
);
return response.data;
}

View File

@@ -1,20 +0,0 @@
export interface RemoteQueriesSubmissionRequest {
ref: string;
language: string;
repositories?: string[];
repository_lists?: string[];
repository_owners?: string[];
query_pack: string;
}
export interface RemoteQueriesResponse {
workflow_run_id: number;
errors?: {
invalid_repositories?: string[];
repositories_without_database?: string[];
private_repositories?: string[];
cutoff_repositories?: string[];
cutoff_repositories_count?: number;
};
repositories_queried: string[];
}

View File

@@ -1,16 +0,0 @@
import { QueryStatus } from "../query-status";
import { RemoteQuery } from "./remote-query";
/**
* Information about a remote query.
*/
export interface RemoteQueryHistoryItem {
readonly t: "remote";
failureReason?: string;
resultCount?: number;
status: QueryStatus;
completed: boolean;
readonly queryId: string;
remoteQuery: RemoteQuery;
userSpecifiedLabel?: string;
}

View File

@@ -1,23 +0,0 @@
export interface RemoteQueryResultIndex {
artifactsUrlPath: string;
successes: RemoteQuerySuccessIndexItem[];
failures: RemoteQueryFailureIndexItem[];
}
export interface RemoteQuerySuccessIndexItem {
id: string;
artifactId: number;
nwo: string;
sha?: string;
resultCount: number;
bqrsFileSize: number;
sarifFileSize?: number;
sourceLocationPrefix: string;
}
export interface RemoteQueryFailureIndexItem {
id: string;
artifactId: number;
nwo: string;
error: string;
}

View File

@@ -1,20 +0,0 @@
import { DownloadLink } from "./download-link";
import { AnalysisFailure } from "./shared/analysis-failure";
export interface RemoteQueryResult {
executionEndTime: number; // Can't use a Date here since it needs to be serialized and desserialized.
analysisSummaries: AnalysisSummary[];
analysisFailures: AnalysisFailure[];
queryId: string;
}
export interface AnalysisSummary {
nwo: string;
databaseSha: string;
resultCount: number;
sourceLocationPrefix: string;
downloadLink: DownloadLink;
fileSizeInBytes: number;
starCount?: number;
lastUpdated?: number;
}

View File

@@ -1,8 +0,0 @@
import { RemoteQuery } from "./remote-query";
import { VariantAnalysis } from "./shared/variant-analysis";
export interface RemoteQuerySubmissionResult {
queryDirPath?: string;
query?: RemoteQuery;
variantAnalysis?: VariantAnalysis;
}

View File

@@ -1,10 +0,0 @@
export type RemoteQueryWorkflowStatus =
| "InProgress"
| "CompletedSuccessfully"
| "CompletedUnsuccessfully"
| "Cancelled";
export interface RemoteQueryWorkflowResult {
status: RemoteQueryWorkflowStatus;
error?: string;
}

View File

@@ -1,12 +0,0 @@
import { Repository as RemoteRepository } from "./repository";
export interface RemoteQuery {
queryName: string;
queryFilePath: string;
queryText: string;
language: string;
controllerRepository: RemoteRepository;
executionStartTime: number; // Use number here since it needs to be serialized and desserialized.
actionsWorkflowRunId: number;
repositoryCount: number;
}

View File

@@ -1,10 +0,0 @@
export interface RemoteQueriesSubmission {
ref: string;
language: string;
repositories?: string[];
repositoryLists?: string[];
repositoryOwners?: string[];
queryPack: string;
controllerRepoId: number;
}

View File

@@ -1,45 +0,0 @@
import { nanoid } from "nanoid";
import { RemoteQueryHistoryItem } from "../../../src/remote-queries/remote-query-history-item";
import { QueryStatus } from "../../../src/query-status";
export function createMockRemoteQueryHistoryItem({
date = new Date("2022-01-01T00:00:00.000Z"),
status = QueryStatus.InProgress,
failureReason = undefined,
resultCount = undefined,
repositoryCount = 0,
executionStartTime = date.getTime(),
userSpecifiedLabel = undefined,
}: {
date?: Date;
status?: QueryStatus;
failureReason?: string;
resultCount?: number;
repositoryCount?: number;
repositories?: string[];
executionStartTime?: number;
userSpecifiedLabel?: string;
}): RemoteQueryHistoryItem {
return {
t: "remote",
failureReason,
resultCount,
status,
completed: false,
queryId: nanoid(),
remoteQuery: {
queryName: "query-name",
queryFilePath: "query-file.ql",
queryText: "select 1",
language: "javascript",
controllerRepository: {
owner: "github",
name: "vscode-codeql-integration-tests",
},
executionStartTime,
actionsWorkflowRunId: 1,
repositoryCount,
},
userSpecifiedLabel,
};
}

View File

@@ -2,15 +2,12 @@ import { env } from "vscode";
import { QueryHistoryConfig } from "../../../../src/config";
import { HistoryItemLabelProvider } from "../../../../src/query-history/history-item-label-provider";
import { createMockLocalQueryInfo } from "../../../factories/query-history/local-query-history-item";
import { createMockRemoteQueryHistoryItem } from "../../../factories/query-history/remote-query-history-item";
import { QueryStatus } from "../../../../src/query-status";
describe("HistoryItemLabelProvider", () => {
let labelProvider: HistoryItemLabelProvider;
let config: QueryHistoryConfig;
const date = new Date("2022-01-01T00:00:00.000Z");
const dateStr = date.toLocaleString(env.language);
const executionStartTime = date.getTime();
const userSpecifiedLabel = "user-specified-name";
beforeEach(() => {
@@ -85,149 +82,4 @@ describe("HistoryItemLabelProvider", () => {
expect(labelProvider.getShortLabel(fqi2)).toBe("query-file.ql");
});
});
describe("remote queries", () => {
it("should interpolate query when user specified", () => {
const fqi = createMockRemoteQueryHistoryItem({ userSpecifiedLabel });
expect(labelProvider.getLabel(fqi)).toBe(userSpecifiedLabel);
fqi.userSpecifiedLabel = "%t %q %d %s %%";
expect(labelProvider.getLabel(fqi)).toBe(
`${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)).toBe(
`${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 = createMockRemoteQueryHistoryItem({
status: QueryStatus.Completed,
executionStartTime,
resultCount: 16,
});
expect(labelProvider.getLabel(fqi)).toBe(
"xxx query-name (javascript) xxx",
);
config.format = "%t %q %d %s %f %r %%";
expect(labelProvider.getLabel(fqi)).toBe(
`${dateStr} query-name (javascript) github/vscode-codeql-integration-tests completed query-file.ql (16 results) %`,
);
config.format = "%t %q %d %s %f %r %%::%t %q %d %s %f %r %%";
expect(labelProvider.getLabel(fqi)).toBe(
`${dateStr} query-name (javascript) github/vscode-codeql-integration-tests completed query-file.ql (16 results) %::${dateStr} query-name (javascript) github/vscode-codeql-integration-tests completed query-file.ql (16 results) %`,
);
});
it("should use number of repositories instead of controller repo if available", () => {
const fqi = createMockRemoteQueryHistoryItem({
status: QueryStatus.Completed,
executionStartTime,
resultCount: 16,
repositoryCount: 2,
});
config.format = "%t %q %d %s %f %r %%";
expect(labelProvider.getLabel(fqi)).toBe(
`${dateStr} query-name (javascript) 2 repositories completed query-file.ql (16 results) %`,
);
});
it("should get query short label", () => {
const fqi = createMockRemoteQueryHistoryItem({
status: QueryStatus.Completed,
executionStartTime,
userSpecifiedLabel,
});
// 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 = createMockRemoteQueryHistoryItem({});
expect(labelProvider.getShortLabel(fqi2)).toBe("query-name");
});
describe("when results are present", () => {
it("should display results if there are any", () => {
const fqi = createMockRemoteQueryHistoryItem({
status: QueryStatus.Completed,
executionStartTime,
resultCount: 16,
repositoryCount: 2,
});
config.format = "%t %q %d %s %f %r %%";
expect(labelProvider.getLabel(fqi)).toBe(
`${dateStr} query-name (javascript) 2 repositories completed query-file.ql (16 results) %`,
);
});
});
describe("when results are not present", () => {
it("should skip displaying them", () => {
const fqi = createMockRemoteQueryHistoryItem({
status: QueryStatus.Completed,
executionStartTime,
resultCount: 0,
repositoryCount: 2,
});
config.format = "%t %q %d %s %f %r %%";
expect(labelProvider.getLabel(fqi)).toBe(
`${dateStr} query-name (javascript) 2 repositories completed query-file.ql %`,
);
});
});
describe("when extra whitespace is present in the middle of the label", () => {
it("should squash it down to a single whitespace", () => {
const fqi = createMockRemoteQueryHistoryItem({
status: QueryStatus.Completed,
executionStartTime,
resultCount: 0,
repositoryCount: 2,
});
config.format = "%t %q %d %s %f %r %%";
expect(labelProvider.getLabel(fqi)).toBe(
`${dateStr} query-name (javascript) 2 repositories completed query-file.ql %`,
);
});
});
describe("when extra whitespace is present at the start of the label", () => {
it("should squash it down to a single whitespace", () => {
const fqi = createMockRemoteQueryHistoryItem({
status: QueryStatus.Completed,
executionStartTime,
resultCount: 0,
repositoryCount: 2,
});
config.format = " %t %q %d %s %f %r %%";
expect(labelProvider.getLabel(fqi)).toBe(
` ${dateStr} query-name (javascript) 2 repositories completed query-file.ql %`,
);
});
});
describe("when extra whitespace is present at the end of the label", () => {
it("should squash it down to a single whitespace", () => {
const fqi = createMockRemoteQueryHistoryItem({
status: QueryStatus.Completed,
executionStartTime,
resultCount: 0,
repositoryCount: 2,
});
config.format = "%t %q %d %s %f %r %% ";
expect(labelProvider.getLabel(fqi)).toBe(
`${dateStr} query-name (javascript) 2 repositories completed query-file.ql % `,
);
});
});
});
});

View File

@@ -19,15 +19,11 @@ import {
createMockLocalQueryInfo,
createMockQueryWithResults,
} from "../../../factories/query-history/local-query-history-item";
import { createMockRemoteQueryHistoryItem } from "../../../factories/query-history/remote-query-history-item";
import { RemoteQueryHistoryItem } from "../../../../src/remote-queries/remote-query-history-item";
import { shuffleHistoryItems } from "../../utils/query-history-helpers";
import { createMockVariantAnalysisHistoryItem } from "../../../factories/query-history/variant-analysis-history-item";
import { VariantAnalysisHistoryItem } from "../../../../src/query-history/variant-analysis-history-item";
import { QueryStatus } from "../../../../src/query-status";
import { VariantAnalysisStatus } from "../../../../src/remote-queries/shared/variant-analysis";
import { Credentials } from "../../../../src/common/authentication";
import { createMockApp } from "../../../__mocks__/appMock";
import {
HistoryTreeDataProvider,
SortOrder,
@@ -46,7 +42,6 @@ describe("HistoryTreeDataProvider", () => {
let allHistory: QueryHistoryInfo[];
let localQueryHistory: LocalQueryInfo[];
let remoteQueryHistory: RemoteQueryHistoryItem[];
let variantAnalysisHistory: VariantAnalysisHistoryItem[];
let historyTreeDataProvider: HistoryTreeDataProvider;
@@ -102,12 +97,6 @@ describe("HistoryTreeDataProvider", () => {
// in progress
createMockLocalQueryInfo({ resultCount: 0 }),
];
remoteQueryHistory = [
createMockRemoteQueryHistoryItem({ status: QueryStatus.Completed }),
createMockRemoteQueryHistoryItem({ status: QueryStatus.Failed }),
createMockRemoteQueryHistoryItem({ status: QueryStatus.InProgress }),
createMockRemoteQueryHistoryItem({ status: QueryStatus.InProgress }),
];
variantAnalysisHistory = [
createMockVariantAnalysisHistoryItem({
historyItemStatus: QueryStatus.Completed,
@@ -128,7 +117,6 @@ describe("HistoryTreeDataProvider", () => {
];
allHistory = shuffleHistoryItems([
...localQueryHistory,
...remoteQueryHistory,
...variantAnalysisHistory,
]);
@@ -233,12 +221,6 @@ describe("HistoryTreeDataProvider", () => {
describe("sorting", () => {
const history = [
createMockRemoteQueryHistoryItem({
userSpecifiedLabel: "a",
executionStartTime: 2,
resultCount: 24,
status: QueryStatus.Completed,
}),
createMockLocalQueryInfo({
userSpecifiedLabel: "b",
startTime: new Date(10),
@@ -275,12 +257,6 @@ describe("HistoryTreeDataProvider", () => {
historyItemStatus: QueryStatus.Failed,
variantAnalysisStatus: VariantAnalysisStatus.Failed,
}),
createMockRemoteQueryHistoryItem({
userSpecifiedLabel: "h",
executionStartTime: 6,
resultCount: 5,
status: QueryStatus.InProgress,
}),
];
let treeDataProvider: HistoryTreeDataProvider;
@@ -309,14 +285,12 @@ describe("HistoryTreeDataProvider", () => {
it("should get children for date ascending", async () => {
const expected = [
history[4],
history[2],
history[5],
history[0],
history[3],
history[7],
history[6],
history[1],
history[2],
history[4],
history[3],
];
treeDataProvider.sortOrder = SortOrder.DateAsc;
@@ -326,14 +300,12 @@ describe("HistoryTreeDataProvider", () => {
it("should get children for date descending", async () => {
const expected = [
history[4],
history[2],
history[5],
history[0],
history[3],
history[7],
history[6],
history[1],
history[2],
history[4],
history[3],
].reverse();
treeDataProvider.sortOrder = SortOrder.DateDesc;
@@ -344,14 +316,12 @@ describe("HistoryTreeDataProvider", () => {
it("should get children for result count ascending", async () => {
const expected = [
history[7],
history[5],
history[4],
history[1],
history[0],
history[3],
history[6],
history[0],
history[2],
history[5],
history[1],
];
treeDataProvider.sortOrder = SortOrder.CountAsc;
@@ -362,14 +332,12 @@ describe("HistoryTreeDataProvider", () => {
it("should get children for result count descending", async () => {
const expected = [
history[7],
history[5],
history[4],
history[1],
history[0],
history[3],
history[6],
history[0],
history[2],
history[5],
history[1],
].reverse();
treeDataProvider.sortOrder = SortOrder.CountDesc;
@@ -395,12 +363,6 @@ describe("HistoryTreeDataProvider", () => {
historyItemStatus: QueryStatus.Completed,
variantAnalysisStatus: VariantAnalysisStatus.Failed,
}),
createMockRemoteQueryHistoryItem({
userSpecifiedLabel: "d",
resultCount: 0,
executionStartTime: 50,
status: QueryStatus.Completed,
}),
createMockVariantAnalysisHistoryItem({
userSpecifiedLabel: "e",
resultCount: 0,
@@ -438,12 +400,6 @@ describe("HistoryTreeDataProvider", () => {
historyItemStatus: QueryStatus.Completed,
variantAnalysisStatus: VariantAnalysisStatus.Failed,
}),
createMockRemoteQueryHistoryItem({
userSpecifiedLabel: "d",
resultCount: 0,
executionStartTime: 50,
status: QueryStatus.Completed,
}),
createMockVariantAnalysisHistoryItem({
userSpecifiedLabel: "e",
resultCount: 0,
@@ -463,12 +419,8 @@ describe("HistoryTreeDataProvider", () => {
});
});
async function createMockQueryHistory(
allHistory: QueryHistoryInfo[],
credentials?: Credentials,
) {
async function createMockQueryHistory(allHistory: QueryHistoryInfo[]) {
const qhm = new QueryHistoryManager(
createMockApp({ credentials }),
{} as QueryRunner,
{} as DatabaseManager,
localQueriesResultsViewStub,

View File

@@ -10,7 +10,6 @@ import { VariantAnalysisHistoryItem } from "../../../../src/query-history/varian
import { createMockVariantAnalysis } from "../../../factories/remote-queries/shared/variant-analysis";
import { createMockScannedRepos } from "../../../factories/remote-queries/shared/scanned-repositories";
import { createMockLocalQueryInfo } from "../../../factories/query-history/local-query-history-item";
import { createMockRemoteQueryHistoryItem } from "../../../factories/query-history/remote-query-history-item";
import {
VariantAnalysisRepoStatus,
VariantAnalysisStatus,
@@ -19,7 +18,6 @@ import {
describe("Query history info", () => {
const date = new Date("2022-01-01T00:00:00.000Z");
const localQueryHistoryItem = createMockLocalQueryInfo({ startTime: date });
const remoteQueryHistoryItem = createMockRemoteQueryHistoryItem({});
const variantAnalysisHistoryItem: VariantAnalysisHistoryItem = {
t: "variant-analysis",
status: QueryStatus.InProgress,
@@ -42,12 +40,6 @@ describe("Query history info", () => {
expect(queryName).toBe(localQueryHistoryItem.getQueryName());
});
it("should get the name for remote query history items", () => {
const queryName = getRawQueryName(remoteQueryHistoryItem);
expect(queryName).toBe(remoteQueryHistoryItem.remoteQuery.queryName);
});
it("should get the name for variant analysis history items", () => {
const queryName = getRawQueryName(variantAnalysisHistoryItem);
@@ -64,12 +56,6 @@ describe("Query history info", () => {
expect(historyItemId).toBe(localQueryHistoryItem.initialInfo.id);
});
it("should get the ID for remote query history items", () => {
const historyItemId = getQueryId(remoteQueryHistoryItem);
expect(historyItemId).toBe(remoteQueryHistoryItem.queryId);
});
it("should get the ID for variant analysis history items", () => {
const historyItemId = getQueryId(variantAnalysisHistoryItem);
@@ -86,12 +72,6 @@ describe("Query history info", () => {
expect(queryText).toBe(localQueryHistoryItem.initialInfo.queryText);
});
it("should get the query text for remote query history items", () => {
const queryText = getQueryText(remoteQueryHistoryItem);
expect(queryText).toBe(remoteQueryHistoryItem.remoteQuery.queryText);
});
it("should get the query text for variant analysis history items", () => {
const queryText = getQueryText(variantAnalysisHistoryItem);
@@ -102,23 +82,6 @@ describe("Query history info", () => {
});
describe("buildRepoLabel", () => {
describe("repo label for remote query history items", () => {
it("should return controller repo when `repositoryCount` is 0", () => {
const repoLabel = buildRepoLabel(remoteQueryHistoryItem);
const expectedRepoLabel = `${remoteQueryHistoryItem.remoteQuery.controllerRepository.owner}/${remoteQueryHistoryItem.remoteQuery.controllerRepository.name}`;
expect(repoLabel).toBe(expectedRepoLabel);
});
it("should return number of repositories when `repositoryCount` is non-zero", () => {
const remoteQueryHistoryItem2 = createMockRemoteQueryHistoryItem({
repositoryCount: 3,
});
const repoLabel2 = buildRepoLabel(remoteQueryHistoryItem2);
const expectedRepoLabel2 = "3 repositories";
expect(repoLabel2).toBe(expectedRepoLabel2);
});
});
describe("repo label for variant analysis history items", () => {
it("should return label when `totalScannedRepositoryCount` is 0", () => {
const variantAnalysisHistoryItem0: VariantAnalysisHistoryItem = {
@@ -159,18 +122,6 @@ describe("Query history info", () => {
});
describe("getActionsWorkflowRunUrl", () => {
it("should get the run url for remote query history items", () => {
const actionsWorkflowRunUrl = getActionsWorkflowRunUrl(
remoteQueryHistoryItem,
);
const remoteQuery = remoteQueryHistoryItem.remoteQuery;
const fullName = `${remoteQuery.controllerRepository.owner}/${remoteQuery.controllerRepository.name}`;
expect(actionsWorkflowRunUrl).toBe(
`https://github.com/${fullName}/actions/runs/${remoteQuery.actionsWorkflowRunId}`,
);
});
it("should get the run url for variant analysis history items", () => {
const actionsWorkflowRunUrl = getActionsWorkflowRunUrl(
variantAnalysisHistoryItem,

View File

@@ -20,20 +20,14 @@ import {
createMockLocalQueryInfo,
createMockQueryWithResults,
} from "../../../factories/query-history/local-query-history-item";
import { createMockRemoteQueryHistoryItem } from "../../../factories/query-history/remote-query-history-item";
import { RemoteQueryHistoryItem } from "../../../../src/remote-queries/remote-query-history-item";
import { shuffleHistoryItems } from "../../utils/query-history-helpers";
import { createMockVariantAnalysisHistoryItem } from "../../../factories/query-history/variant-analysis-history-item";
import { VariantAnalysisHistoryItem } from "../../../../src/query-history/variant-analysis-history-item";
import { QueryStatus } from "../../../../src/query-status";
import { VariantAnalysisStatus } from "../../../../src/remote-queries/shared/variant-analysis";
import * as ghActionsApiClient from "../../../../src/remote-queries/gh-api/gh-actions-api-client";
import { QuickPickItem, TextEditor } from "vscode";
import { WebviewReveal } from "../../../../src/interface-utils";
import * as helpers from "../../../../src/helpers";
import { testCredentialsWithStub } from "../../../factories/authentication";
import { Credentials } from "../../../../src/common/authentication";
import { createMockApp } from "../../../__mocks__/appMock";
describe("QueryHistoryManager", () => {
const mockExtensionLocation = join(tmpDir.name, "mock-extension-location");
@@ -59,7 +53,6 @@ describe("QueryHistoryManager", () => {
let allHistory: QueryHistoryInfo[];
let localQueryHistory: LocalQueryInfo[];
let remoteQueryHistory: RemoteQueryHistoryItem[];
let variantAnalysisHistory: VariantAnalysisHistoryItem[];
beforeEach(() => {
@@ -127,12 +120,6 @@ describe("QueryHistoryManager", () => {
// in progress
createMockLocalQueryInfo({ resultCount: 0 }),
];
remoteQueryHistory = [
createMockRemoteQueryHistoryItem({ status: QueryStatus.Completed }),
createMockRemoteQueryHistoryItem({ status: QueryStatus.Failed }),
createMockRemoteQueryHistoryItem({ status: QueryStatus.InProgress }),
createMockRemoteQueryHistoryItem({ status: QueryStatus.InProgress }),
];
variantAnalysisHistory = [
createMockVariantAnalysisHistoryItem({
historyItemStatus: QueryStatus.Completed,
@@ -153,7 +140,6 @@ describe("QueryHistoryManager", () => {
];
allHistory = shuffleHistoryItems([
...localQueryHistory,
...remoteQueryHistory,
...variantAnalysisHistory,
]);
});
@@ -709,24 +695,9 @@ describe("QueryHistoryManager", () => {
});
describe("handleCancel", () => {
let mockCancelRemoteQuery: jest.SpiedFunction<
typeof ghActionsApiClient.cancelRemoteQuery
>;
const getOctokitStub = jest.fn();
const mockCredentials = testCredentialsWithStub(getOctokitStub);
beforeEach(async () => {
mockCancelRemoteQuery = jest
.spyOn(ghActionsApiClient, "cancelRemoteQuery")
.mockResolvedValue();
});
describe("if the item is in progress", () => {
it("should cancel a single local query", async () => {
queryHistoryManager = await createMockQueryHistory(
localQueryHistory,
mockCredentials,
);
queryHistoryManager = await createMockQueryHistory(localQueryHistory);
// cancelling the selected item
const inProgress1 = localQueryHistory[4];
@@ -737,10 +708,7 @@ describe("QueryHistoryManager", () => {
});
it("should cancel multiple local queries", async () => {
queryHistoryManager = await createMockQueryHistory(
localQueryHistory,
mockCredentials,
);
queryHistoryManager = await createMockQueryHistory(localQueryHistory);
// cancelling the selected item
const inProgress1 = localQueryHistory[4];
@@ -757,51 +725,8 @@ describe("QueryHistoryManager", () => {
expect(cancelSpy2).toBeCalled();
});
it("should cancel a single remote query", async () => {
queryHistoryManager = await createMockQueryHistory(
localQueryHistory,
mockCredentials,
);
// cancelling the selected item
const inProgress1 = remoteQueryHistory[2];
await queryHistoryManager.handleCancel(inProgress1, [inProgress1]);
expect(mockCancelRemoteQuery).toBeCalledWith(
mockCredentials,
inProgress1.remoteQuery,
);
});
it("should cancel multiple remote queries", async () => {
queryHistoryManager = await createMockQueryHistory(
localQueryHistory,
mockCredentials,
);
// cancelling the selected item
const inProgress1 = remoteQueryHistory[2];
const inProgress2 = remoteQueryHistory[3];
await queryHistoryManager.handleCancel(inProgress1, [
inProgress1,
inProgress2,
]);
expect(mockCancelRemoteQuery).toBeCalledWith(
mockCredentials,
inProgress1.remoteQuery,
);
expect(mockCancelRemoteQuery).toBeCalledWith(
mockCredentials,
inProgress2.remoteQuery,
);
});
it("should cancel a single variant analysis", async () => {
queryHistoryManager = await createMockQueryHistory(
localQueryHistory,
mockCredentials,
);
queryHistoryManager = await createMockQueryHistory(localQueryHistory);
// cancelling the selected item
const inProgress1 = variantAnalysisHistory[1];
@@ -814,10 +739,7 @@ describe("QueryHistoryManager", () => {
});
it("should cancel multiple variant analyses", async () => {
queryHistoryManager = await createMockQueryHistory(
localQueryHistory,
mockCredentials,
);
queryHistoryManager = await createMockQueryHistory(localQueryHistory);
// cancelling the selected item
const inProgress1 = variantAnalysisHistory[1];
@@ -840,10 +762,7 @@ describe("QueryHistoryManager", () => {
describe("if the item is not in progress", () => {
it("should not cancel a single local query", async () => {
queryHistoryManager = await createMockQueryHistory(
localQueryHistory,
mockCredentials,
);
queryHistoryManager = await createMockQueryHistory(localQueryHistory);
// cancelling the selected item
const completed = localQueryHistory[0];
@@ -854,10 +773,7 @@ describe("QueryHistoryManager", () => {
});
it("should not cancel multiple local queries", async () => {
queryHistoryManager = await createMockQueryHistory(
localQueryHistory,
mockCredentials,
);
queryHistoryManager = await createMockQueryHistory(localQueryHistory);
// cancelling the selected item
const completed = localQueryHistory[0];
@@ -871,48 +787,8 @@ describe("QueryHistoryManager", () => {
expect(cancelSpy2).not.toBeCalledTimes(1);
});
it("should not cancel a single remote query", async () => {
queryHistoryManager = await createMockQueryHistory(
localQueryHistory,
mockCredentials,
);
// cancelling the selected item
const completed = remoteQueryHistory[0];
await queryHistoryManager.handleCancel(completed, [completed]);
expect(mockCancelRemoteQuery).not.toBeCalledWith(
mockCredentials,
completed.remoteQuery,
);
});
it("should not cancel multiple remote queries", async () => {
queryHistoryManager = await createMockQueryHistory(
localQueryHistory,
mockCredentials,
);
// cancelling the selected item
const completed = remoteQueryHistory[0];
const failed = remoteQueryHistory[1];
await queryHistoryManager.handleCancel(completed, [completed, failed]);
expect(mockCancelRemoteQuery).not.toBeCalledWith(
mockCredentials,
completed.remoteQuery,
);
expect(mockCancelRemoteQuery).not.toBeCalledWith(
mockCredentials,
failed.remoteQuery,
);
});
it("should not cancel a single variant analysis", async () => {
queryHistoryManager = await createMockQueryHistory(
localQueryHistory,
mockCredentials,
);
queryHistoryManager = await createMockQueryHistory(localQueryHistory);
// cancelling the selected item
const completedVariantAnalysis = variantAnalysisHistory[0];
@@ -927,10 +803,7 @@ describe("QueryHistoryManager", () => {
});
it("should not cancel multiple variant analyses", async () => {
queryHistoryManager = await createMockQueryHistory(
localQueryHistory,
mockCredentials,
);
queryHistoryManager = await createMockQueryHistory(localQueryHistory);
// cancelling the selected item
const completedVariantAnalysis = variantAnalysisHistory[0];
@@ -1272,12 +1145,8 @@ describe("QueryHistoryManager", () => {
});
});
async function createMockQueryHistory(
allHistory: QueryHistoryInfo[],
credentials?: Credentials,
) {
async function createMockQueryHistory(allHistory: QueryHistoryInfo[]) {
const qhm = new QueryHistoryManager(
createMockApp({ credentials }),
{} as QueryRunner,
{} as DatabaseManager,
localQueriesResultsViewStub,

View File

@@ -19,8 +19,6 @@ import { ResultsView } from "../../../../src/interface";
import { EvalLogViewer } from "../../../../src/eval-log-viewer";
import { QueryRunner } from "../../../../src/queryRunner";
import { VariantAnalysisManager } from "../../../../src/remote-queries/variant-analysis-manager";
import { App } from "../../../../src/common/app";
import { createMockApp } from "../../../__mocks__/appMock";
import { QueryHistoryManager } from "../../../../src/query-history/query-history-manager";
// set a higher timeout since recursive delete may take a while, expecially on Windows.
@@ -37,7 +35,6 @@ describe("Variant Analyses and QueryHistoryManager", () => {
/** noop */
};
let app: App;
let qhm: QueryHistoryManager;
let rawQueryHistory: any;
let disposables: DisposableBucket;
@@ -71,10 +68,7 @@ describe("Variant Analyses and QueryHistoryManager", () => {
join(STORAGE_DIR, "workspace-query-history.json"),
).queries;
app = createMockApp({});
qhm = new QueryHistoryManager(
app,
{} as QueryRunner,
{} as DatabaseManager,
localQueriesResultsViewStub,

View File

@@ -3,7 +3,7 @@ import {
serializeQueryHistory,
} from "../../../src/query-serialization";
import { join } from "path";
import { writeFileSync, mkdirpSync } from "fs-extra";
import { writeFileSync, mkdirpSync, writeFile } from "fs-extra";
import { LocalQueryInfo, InitialQueryInfo } from "../../../src/query-results";
import { QueryWithResults } from "../../../src/run-queries-shared";
import { DatabaseInfo } from "../../../src/pure/interface-types";
@@ -11,11 +11,10 @@ import { CancellationTokenSource, Uri } from "vscode";
import { tmpDir } from "../../../src/helpers";
import { QueryResultType } from "../../../src/pure/legacy-messages";
import { QueryInProgress } from "../../../src/legacy-query-server/run-queries";
import { RemoteQueryHistoryItem } from "../../../src/remote-queries/remote-query-history-item";
import { VariantAnalysisHistoryItem } from "../../../src/query-history/variant-analysis-history-item";
import { QueryHistoryInfo } from "../../../src/query-history/query-history-info";
import { createMockRemoteQueryHistoryItem } from "../../factories/query-history/remote-query-history-item";
import { createMockVariantAnalysisHistoryItem } from "../../factories/query-history/variant-analysis-history-item";
import { nanoid } from "nanoid";
describe("serialize and deserialize", () => {
let infoSuccessRaw: LocalQueryInfo;
@@ -24,13 +23,11 @@ describe("serialize and deserialize", () => {
let infoLateFailure: LocalQueryInfo;
let infoInProgress: LocalQueryInfo;
let remoteQuery1: RemoteQueryHistoryItem;
let remoteQuery2: RemoteQueryHistoryItem;
let variantAnalysis1: VariantAnalysisHistoryItem;
let variantAnalysis2: VariantAnalysisHistoryItem;
let allHistory: QueryHistoryInfo[];
let expectedHistory: QueryHistoryInfo[];
let queryPath: string;
let cnt = 0;
@@ -70,9 +67,6 @@ describe("serialize and deserialize", () => {
);
infoInProgress = createMockFullQueryInfo("e");
remoteQuery1 = createMockRemoteQueryHistoryItem({});
remoteQuery2 = createMockRemoteQueryHistoryItem({});
variantAnalysis1 = createMockVariantAnalysisHistoryItem({});
variantAnalysis2 = createMockVariantAnalysisHistoryItem({});
@@ -82,25 +76,21 @@ describe("serialize and deserialize", () => {
infoEarlyFailure,
infoLateFailure,
infoInProgress,
remoteQuery1,
remoteQuery2,
variantAnalysis1,
variantAnalysis2,
];
// the expected results only contains the history with completed queries
expectedHistory = [
infoSuccessRaw,
infoSuccessInterpreted,
infoLateFailure,
variantAnalysis1,
variantAnalysis2,
];
});
it("should serialize and deserialize query history", async () => {
// the expected results only contains the history with completed queries
const expectedHistory = [
infoSuccessRaw,
infoSuccessInterpreted,
infoLateFailure,
remoteQuery1,
remoteQuery2,
variantAnalysis1,
variantAnalysis2,
];
const allHistoryPath = join(tmpDir.name, "workspace-query-history.json");
// serialize and deserialize
@@ -137,6 +127,61 @@ describe("serialize and deserialize", () => {
expect(allHistoryActual.length).toEqual(expectedHistory.length);
});
it("should remove remote queries from the history", async () => {
const path = join(tmpDir.name, "query-history-with-remote.json");
await writeFile(
path,
JSON.stringify({
version: 2,
queries: [
...allHistory,
{
t: "remote",
status: "InProgress",
completed: false,
queryId: nanoid(),
remoteQuery: {
queryName: "query-name",
queryFilePath: "query-file.ql",
queryText: "select 1",
language: "javascript",
controllerRepository: {
owner: "github",
name: "vscode-codeql-integration-tests",
},
executionStartTime: Date.now(),
actionsWorkflowRunId: 1,
repositoryCount: 0,
},
},
{
t: "remote",
status: "Completed",
completed: true,
queryId: nanoid(),
remoteQuery: {
queryName: "query-name",
queryFilePath: "query-file.ql",
queryText: "select 1",
language: "javascript",
controllerRepository: {
owner: "github",
name: "vscode-codeql-integration-tests",
},
executionStartTime: Date.now(),
actionsWorkflowRunId: 1,
repositoryCount: 0,
},
},
],
}),
"utf8",
);
const actual = await deserializeQueryHistory(path);
expect(actual.length).toEqual(expectedHistory.length);
});
it("should handle an invalid query history version", async () => {
const badPath = join(tmpDir.name, "bad-query-history.json");
writeFileSync(