Moved logic to get standard pack for variant analysis (#3384)
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
import { join } from "path";
|
||||
import type { BaseLogger } from "../common/logging";
|
||||
import type { QueryLanguage } from "../common/query-language";
|
||||
import type { CodeQLCliServer } from "../codeql-cli/cli";
|
||||
import type { QlPackDetails } from "./ql-pack-details";
|
||||
import { getQlPackFilePath } from "../common/ql";
|
||||
|
||||
export async function resolveCodeScanningQueryPack(
|
||||
logger: BaseLogger,
|
||||
cliServer: CodeQLCliServer,
|
||||
language: QueryLanguage,
|
||||
): Promise<QlPackDetails> {
|
||||
// Get pack
|
||||
void logger.log(`Downloading pack for language: ${language}`);
|
||||
const packName = `codeql/${language}-queries`;
|
||||
const packDownloadResult = await cliServer.packDownload([packName]);
|
||||
const downloadedPack = packDownloadResult.packs[0];
|
||||
|
||||
const packDir = join(
|
||||
packDownloadResult.packDir,
|
||||
downloadedPack.name,
|
||||
downloadedPack.version,
|
||||
);
|
||||
|
||||
// Resolve queries
|
||||
void logger.log(`Resolving queries for pack: ${packName}`);
|
||||
const suitePath = join(
|
||||
packDir,
|
||||
"codeql-suites",
|
||||
`${language}-code-scanning.qls`,
|
||||
);
|
||||
const resolvedQueries = await cliServer.resolveQueries(suitePath);
|
||||
|
||||
const problemQueries = await filterToOnlyProblemQueries(
|
||||
logger,
|
||||
cliServer,
|
||||
resolvedQueries,
|
||||
);
|
||||
|
||||
if (problemQueries.length === 0) {
|
||||
throw Error(
|
||||
`No problem queries found in published query pack: ${packName}.`,
|
||||
);
|
||||
}
|
||||
|
||||
// Return pack details
|
||||
const qlPackFilePath = await getQlPackFilePath(packDir);
|
||||
|
||||
const qlPackDetails: QlPackDetails = {
|
||||
queryFiles: problemQueries,
|
||||
qlPackRootPath: packDir,
|
||||
qlPackFilePath,
|
||||
language,
|
||||
};
|
||||
|
||||
return qlPackDetails;
|
||||
}
|
||||
|
||||
async function filterToOnlyProblemQueries(
|
||||
logger: BaseLogger,
|
||||
cliServer: CodeQLCliServer,
|
||||
queries: string[],
|
||||
): Promise<string[]> {
|
||||
const problemQueries: string[] = [];
|
||||
for (const query of queries) {
|
||||
const queryMetadata = await cliServer.resolveMetadata(query);
|
||||
if (
|
||||
queryMetadata.kind === "problem" ||
|
||||
queryMetadata.kind === "path-problem"
|
||||
) {
|
||||
problemQueries.push(query);
|
||||
} else {
|
||||
void logger.log(`Skipping non-problem query ${query}`);
|
||||
}
|
||||
}
|
||||
return problemQueries;
|
||||
}
|
||||
@@ -94,6 +94,7 @@ import { getQlPackFilePath } from "../common/ql";
|
||||
import { tryGetQueryMetadata } from "../codeql-cli/query-metadata";
|
||||
import { getOnDiskWorkspaceFolders } from "../common/vscode/workspace-folders";
|
||||
import { findVariantAnalysisQlPackRoot } from "./ql";
|
||||
import { resolveCodeScanningQueryPack } from "./code-scanning-pack";
|
||||
|
||||
const maxRetryCount = 3;
|
||||
|
||||
@@ -219,7 +220,7 @@ export class VariantAnalysisManager
|
||||
public async runVariantAnalysisFromPublishedPack(): Promise<void> {
|
||||
return withProgress(async (progress, token) => {
|
||||
progress({
|
||||
maxStep: 8,
|
||||
maxStep: 7,
|
||||
step: 0,
|
||||
message: "Determining query language",
|
||||
});
|
||||
@@ -230,53 +231,17 @@ export class VariantAnalysisManager
|
||||
}
|
||||
|
||||
progress({
|
||||
maxStep: 8,
|
||||
step: 1,
|
||||
message: "Downloading query pack",
|
||||
});
|
||||
|
||||
const packName = `codeql/${language}-queries`;
|
||||
const packDownloadResult = await this.cliServer.packDownload([packName]);
|
||||
const downloadedPack = packDownloadResult.packs[0];
|
||||
|
||||
const packDir = join(
|
||||
packDownloadResult.packDir,
|
||||
downloadedPack.name,
|
||||
downloadedPack.version,
|
||||
);
|
||||
|
||||
progress({
|
||||
maxStep: 8,
|
||||
maxStep: 7,
|
||||
step: 2,
|
||||
message: "Resolving queries in pack",
|
||||
message: "Downloading query pack and resolving queries",
|
||||
});
|
||||
|
||||
const suitePath = join(
|
||||
packDir,
|
||||
"codeql-suites",
|
||||
`${language}-code-scanning.qls`,
|
||||
);
|
||||
const resolvedQueries = await this.cliServer.resolveQueries(suitePath);
|
||||
|
||||
const problemQueries =
|
||||
await this.filterToOnlyProblemQueries(resolvedQueries);
|
||||
|
||||
if (problemQueries.length === 0) {
|
||||
void this.app.logger.showErrorMessage(
|
||||
`Unable to trigger variant analysis. No problem queries found in published query pack: ${packName}.`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const qlPackFilePath = await getQlPackFilePath(packDir);
|
||||
|
||||
// Build up details to pass to the functions that run the variant analysis.
|
||||
const qlPackDetails: QlPackDetails = {
|
||||
queryFiles: problemQueries,
|
||||
qlPackRootPath: packDir,
|
||||
qlPackFilePath,
|
||||
const qlPackDetails = await resolveCodeScanningQueryPack(
|
||||
this.app.logger,
|
||||
this.cliServer,
|
||||
language,
|
||||
};
|
||||
);
|
||||
|
||||
await this.runVariantAnalysis(
|
||||
qlPackDetails,
|
||||
@@ -291,24 +256,6 @@ export class VariantAnalysisManager
|
||||
});
|
||||
}
|
||||
|
||||
private async filterToOnlyProblemQueries(
|
||||
queries: string[],
|
||||
): Promise<string[]> {
|
||||
const problemQueries: string[] = [];
|
||||
for (const query of queries) {
|
||||
const queryMetadata = await this.cliServer.resolveMetadata(query);
|
||||
if (
|
||||
queryMetadata.kind === "problem" ||
|
||||
queryMetadata.kind === "path-problem"
|
||||
) {
|
||||
problemQueries.push(query);
|
||||
} else {
|
||||
void this.app.logger.log(`Skipping non-problem query ${query}`);
|
||||
}
|
||||
}
|
||||
return problemQueries;
|
||||
}
|
||||
|
||||
private async runVariantAnalysisCommand(queryFiles: Uri[]): Promise<void> {
|
||||
if (queryFiles.length === 0) {
|
||||
throw new Error("Please select a .ql file to run as a variant analysis");
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
import type { CodeQLCliServer } from "../../../../src/codeql-cli/cli";
|
||||
import type { App } from "../../../../src/common/app";
|
||||
import { QueryLanguage } from "../../../../src/common/query-language";
|
||||
import { ExtensionApp } from "../../../../src/common/vscode/vscode-app";
|
||||
import { resolveCodeScanningQueryPack } from "../../../../src/variant-analysis/code-scanning-pack";
|
||||
import { getActivatedExtension } from "../../global.helper";
|
||||
|
||||
describe("Code Scanning pack", () => {
|
||||
let cli: CodeQLCliServer;
|
||||
let app: App;
|
||||
|
||||
beforeEach(async () => {
|
||||
const extension = await getActivatedExtension();
|
||||
cli = extension.cliServer;
|
||||
app = new ExtensionApp(extension.ctx);
|
||||
});
|
||||
|
||||
it("should download pack for correct language and identify problem queries", async () => {
|
||||
const pack = await resolveCodeScanningQueryPack(
|
||||
app.logger,
|
||||
cli,
|
||||
QueryLanguage.Javascript,
|
||||
);
|
||||
// Should include queries. Just check that at least one known query exists.
|
||||
// It doesn't particularly matter which query we check for.
|
||||
expect(
|
||||
pack.queryFiles.some((q) => q.includes("PostMessageStar.ql")),
|
||||
).toBeTruthy();
|
||||
// Should not include non-problem queries.
|
||||
expect(
|
||||
pack.queryFiles.some((q) => q.includes("LinesOfCode.ql")),
|
||||
).toBeFalsy();
|
||||
});
|
||||
});
|
||||
@@ -477,41 +477,4 @@ describe("Variant Analysis Manager", () => {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
describe("runVariantAnalysisFromPublishedPack", () => {
|
||||
// Temporarily disabling this until we add a way to receive multiple queries in the
|
||||
// runVariantAnalysis function.
|
||||
it("should download pack for correct language and identify problem queries", async () => {
|
||||
const showQuickPickSpy = jest
|
||||
.spyOn(window, "showQuickPick")
|
||||
.mockResolvedValue(
|
||||
mockedQuickPickItem({
|
||||
label: "JavaScript",
|
||||
description: "javascript",
|
||||
language: "javascript",
|
||||
}),
|
||||
);
|
||||
|
||||
const runVariantAnalysisMock = jest.fn();
|
||||
variantAnalysisManager.runVariantAnalysis = runVariantAnalysisMock;
|
||||
|
||||
await variantAnalysisManager.runVariantAnalysisFromPublishedPack();
|
||||
|
||||
expect(showQuickPickSpy).toHaveBeenCalledTimes(1);
|
||||
expect(runVariantAnalysisMock).toHaveBeenCalledTimes(1);
|
||||
|
||||
console.log(runVariantAnalysisMock.mock.calls[0][0]);
|
||||
const queries: string[] =
|
||||
runVariantAnalysisMock.mock.calls[0][0].queryFiles;
|
||||
// Should include queries. Just check that at least one known query exists.
|
||||
// It doesn't particularly matter which query we check for.
|
||||
expect(
|
||||
queries.find((q) => q.includes("PostMessageStar.ql")),
|
||||
).toBeDefined();
|
||||
// Should not include non-problem queries.
|
||||
expect(
|
||||
queries.find((q) => q.includes("LinesOfCode.ql")),
|
||||
).not.toBeDefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user