Add support for running multiple queries in MRVA (#3274)
This commit is contained in:
@@ -1741,6 +1741,11 @@ export class CliVersionConstraint {
|
||||
"2.16.1",
|
||||
);
|
||||
|
||||
/**
|
||||
* CLI version where there is support for multiple queries on the pack create command.
|
||||
*/
|
||||
public static CLI_VERSION_WITH_MULTI_QUERY_PACK_CREATE = new SemVer("2.17.0");
|
||||
|
||||
constructor(private readonly cli: CodeQLCliServer) {
|
||||
/**/
|
||||
}
|
||||
@@ -1790,6 +1795,12 @@ export class CliVersionConstraint {
|
||||
));
|
||||
}
|
||||
|
||||
async supportsPackCreateWithMultipleQueries() {
|
||||
return this.isVersionAtLeast(
|
||||
CliVersionConstraint.CLI_VERSION_WITH_MULTI_QUERY_PACK_CREATE,
|
||||
);
|
||||
}
|
||||
|
||||
async supportsMrvaPackCreate(): Promise<boolean> {
|
||||
return (await this.cli.getFeatures()).mrvaPackCreate === true;
|
||||
}
|
||||
|
||||
@@ -5,13 +5,14 @@ import type { QueryLanguage } from "../common/query-language";
|
||||
* a variant analysis.
|
||||
*/
|
||||
export interface QlPackDetails {
|
||||
queryFile: string;
|
||||
// The absolute paths of the query files.
|
||||
queryFiles: string[];
|
||||
|
||||
// The path to the QL pack that is used for triggering a variant analysis.
|
||||
// The absolute path to the QL pack that is used for triggering a variant analysis.
|
||||
// If there is no query pack, this is the same as the directory of the query files.
|
||||
qlPackRootPath: string;
|
||||
|
||||
// The path to the QL pack file (a qlpack.yml or codeql-pack.yml) or undefined if
|
||||
// The absolute path to the QL pack file (a qlpack.yml or codeql-pack.yml) or undefined if
|
||||
// it doesn't exist.
|
||||
qlPackFilePath: string | undefined;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { CancellationToken } from "vscode";
|
||||
import { Uri, window } from "vscode";
|
||||
import { relative, join, sep, basename } from "path";
|
||||
import { join, sep, basename, relative } from "path";
|
||||
import { dump, load } from "js-yaml";
|
||||
import { copy, writeFile, readFile, mkdirp } from "fs-extra";
|
||||
import type { DirectoryResult } from "tmp-promise";
|
||||
@@ -34,7 +34,6 @@ import {
|
||||
QLPACK_FILENAMES,
|
||||
QLPACK_LOCK_FILENAMES,
|
||||
} from "../common/ql";
|
||||
import { tryGetQueryMetadata } from "../codeql-cli/query-metadata";
|
||||
import type { QlPackFile } from "../packaging/qlpack-file";
|
||||
import { expandShortPaths } from "../common/short-paths";
|
||||
import type { QlPackDetails } from "./ql-pack-details";
|
||||
@@ -56,10 +55,7 @@ async function generateQueryPack(
|
||||
qlPackDetails: QlPackDetails,
|
||||
tmpDir: RemoteQueryTempDir,
|
||||
): Promise<string> {
|
||||
const queryFile = qlPackDetails.queryFile;
|
||||
|
||||
const originalPackRoot = qlPackDetails.qlPackRootPath;
|
||||
const packRelativePath = relative(originalPackRoot, queryFile);
|
||||
const workspaceFolders = getOnDiskWorkspaceFolders();
|
||||
const extensionPacks = await getExtensionPacksToInject(
|
||||
cliServer,
|
||||
@@ -80,12 +76,7 @@ async function generateQueryPack(
|
||||
// Synthesize a query pack for the query.
|
||||
// copy only the query file to the query pack directory
|
||||
// and generate a synthetic query pack
|
||||
await createNewQueryPack(
|
||||
queryFile,
|
||||
queryPackDir,
|
||||
qlPackDetails.language,
|
||||
packRelativePath,
|
||||
);
|
||||
await createNewQueryPack(qlPackDetails, queryPackDir);
|
||||
// Clear the cliServer cache so that the previous qlpack text is purged from the CLI.
|
||||
await cliServer.clearCache();
|
||||
|
||||
@@ -94,13 +85,7 @@ async function generateQueryPack(
|
||||
} else if (!cliSupportsMrvaPackCreate) {
|
||||
// We need to copy the query pack to a temporary directory and then fix it up to work with MRVA.
|
||||
queryPackDir = tmpDir.queryPackDir;
|
||||
await copyExistingQueryPack(
|
||||
cliServer,
|
||||
originalPackRoot,
|
||||
queryFile,
|
||||
queryPackDir,
|
||||
packRelativePath,
|
||||
);
|
||||
await copyExistingQueryPack(cliServer, qlPackDetails, queryPackDir);
|
||||
|
||||
// We should already have all the dependencies available, but these older versions of the CLI
|
||||
// have a bug where they will not search `--additional-packs` during validation in `codeql pack bundle`.
|
||||
@@ -125,10 +110,23 @@ async function generateQueryPack(
|
||||
|
||||
let precompilationOpts: string[];
|
||||
if (cliSupportsMrvaPackCreate) {
|
||||
if (
|
||||
qlPackDetails.queryFiles.length > 1 &&
|
||||
!(await cliServer.cliConstraints.supportsPackCreateWithMultipleQueries())
|
||||
) {
|
||||
throw new Error(
|
||||
`Installed CLI version does not allow creating a MRVA pack with multiple queries`,
|
||||
);
|
||||
}
|
||||
|
||||
const queryOpts = qlPackDetails.queryFiles.flatMap((q) => [
|
||||
"--query",
|
||||
join(queryPackDir, relative(qlPackDetails.qlPackRootPath, q)),
|
||||
]);
|
||||
|
||||
precompilationOpts = [
|
||||
"--mrva",
|
||||
"--query",
|
||||
join(queryPackDir, packRelativePath),
|
||||
...queryOpts,
|
||||
// We need to specify the extension packs as dependencies so that they are included in the MRVA pack.
|
||||
// The version range doesn't matter, since they'll always be found by source lookup.
|
||||
...extensionPacks.map((p) => `--extension-pack=${p}@*`),
|
||||
@@ -166,23 +164,26 @@ async function generateQueryPack(
|
||||
}
|
||||
|
||||
async function createNewQueryPack(
|
||||
queryFile: string,
|
||||
qlPackDetails: QlPackDetails,
|
||||
queryPackDir: string,
|
||||
language: string | undefined,
|
||||
packRelativePath: string,
|
||||
) {
|
||||
void extLogger.log(`Copying ${queryFile} to ${queryPackDir}`);
|
||||
const targetQueryFileName = join(queryPackDir, packRelativePath);
|
||||
await copy(queryFile, targetQueryFileName);
|
||||
for (const queryFile of qlPackDetails.queryFiles) {
|
||||
void extLogger.log(`Copying ${queryFile} to ${queryPackDir}`);
|
||||
const relativeQueryPath = relative(qlPackDetails.qlPackRootPath, queryFile);
|
||||
const targetQueryFileName = join(queryPackDir, relativeQueryPath);
|
||||
await copy(queryFile, targetQueryFileName);
|
||||
}
|
||||
|
||||
void extLogger.log("Generating synthetic query pack");
|
||||
const syntheticQueryPack = {
|
||||
name: QUERY_PACK_NAME,
|
||||
version: "0.0.0",
|
||||
dependencies: {
|
||||
[`codeql/${language}-all`]: "*",
|
||||
[`codeql/${qlPackDetails.language}-all`]: "*",
|
||||
},
|
||||
defaultSuite: generateDefaultSuite(packRelativePath),
|
||||
defaultSuite: generateDefaultSuite(qlPackDetails),
|
||||
};
|
||||
|
||||
await writeFile(
|
||||
join(queryPackDir, FALLBACK_QLPACK_FILENAME),
|
||||
dump(syntheticQueryPack),
|
||||
@@ -191,12 +192,16 @@ async function createNewQueryPack(
|
||||
|
||||
async function copyExistingQueryPack(
|
||||
cliServer: CodeQLCliServer,
|
||||
originalPackRoot: string,
|
||||
queryFile: string,
|
||||
qlPackDetails: QlPackDetails,
|
||||
queryPackDir: string,
|
||||
packRelativePath: string,
|
||||
) {
|
||||
const toCopy = await cliServer.packPacklist(originalPackRoot, false);
|
||||
const originalPackRoot = qlPackDetails.qlPackRootPath;
|
||||
const queryFiles = qlPackDetails.queryFiles;
|
||||
|
||||
const toCopy = await cliServer.packPacklist(
|
||||
qlPackDetails.qlPackRootPath,
|
||||
false,
|
||||
);
|
||||
|
||||
// Also include query files that contain extensible predicates. These query files are not
|
||||
// needed for the query to run, but they are needed for the query pack to pass deep validation
|
||||
@@ -216,7 +221,7 @@ async function copyExistingQueryPack(
|
||||
[
|
||||
// also copy the lock file (either new name or old name) and the query file itself. These are not included in the packlist.
|
||||
...QLPACK_LOCK_FILENAMES.map((f) => join(originalPackRoot, f)),
|
||||
queryFile,
|
||||
...queryFiles,
|
||||
].forEach((absolutePath) => {
|
||||
if (absolutePath) {
|
||||
toCopy.push(absolutePath);
|
||||
@@ -241,7 +246,7 @@ async function copyExistingQueryPack(
|
||||
|
||||
void extLogger.log(`Copied ${copiedCount} files to ${queryPackDir}`);
|
||||
|
||||
await fixPackFile(queryPackDir, packRelativePath);
|
||||
await fixPackFile(queryPackDir, qlPackDetails);
|
||||
}
|
||||
|
||||
interface RemoteQueryTempDir {
|
||||
@@ -284,8 +289,6 @@ interface PreparedRemoteQuery {
|
||||
actionBranch: string;
|
||||
base64Pack: string;
|
||||
repoSelection: RepositorySelection;
|
||||
queryFile: string;
|
||||
queryMetadata: QueryMetadata | undefined;
|
||||
controllerRepo: Repository;
|
||||
queryStartTime: number;
|
||||
}
|
||||
@@ -298,8 +301,12 @@ export async function prepareRemoteQueryRun(
|
||||
token: CancellationToken,
|
||||
dbManager: DbManager,
|
||||
): Promise<PreparedRemoteQuery> {
|
||||
if (!qlPackDetails.queryFile.endsWith(".ql")) {
|
||||
throw new UserCancellationException("Not a CodeQL query file.");
|
||||
for (const queryFile of qlPackDetails.queryFiles) {
|
||||
if (!queryFile.endsWith(".ql")) {
|
||||
throw new UserCancellationException(
|
||||
`Not a CodeQL query file: ${queryFile}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
progress({
|
||||
@@ -351,17 +358,13 @@ export async function prepareRemoteQueryRun(
|
||||
message: "Sending request",
|
||||
});
|
||||
|
||||
const queryFile = qlPackDetails.queryFile;
|
||||
const actionBranch = getActionBranch();
|
||||
const queryStartTime = Date.now();
|
||||
const queryMetadata = await tryGetQueryMetadata(cliServer, queryFile);
|
||||
|
||||
return {
|
||||
actionBranch,
|
||||
base64Pack,
|
||||
repoSelection,
|
||||
queryFile,
|
||||
queryMetadata,
|
||||
controllerRepo,
|
||||
queryStartTime,
|
||||
};
|
||||
@@ -379,11 +382,11 @@ export async function prepareRemoteQueryRun(
|
||||
* to `*` versions.
|
||||
*
|
||||
* @param queryPackDir The directory containing the query pack
|
||||
* @param packRelativePath The relative path to the query pack from the root of the query pack
|
||||
* @param qlPackDetails The details of the original QL pack
|
||||
*/
|
||||
async function fixPackFile(
|
||||
queryPackDir: string,
|
||||
packRelativePath: string,
|
||||
qlPackDetails: QlPackDetails,
|
||||
): Promise<void> {
|
||||
const packPath = await getQlPackFilePath(queryPackDir);
|
||||
|
||||
@@ -397,7 +400,7 @@ async function fixPackFile(
|
||||
}
|
||||
const qlpack = load(await readFile(packPath, "utf8")) as QlPackFile;
|
||||
|
||||
updateDefaultSuite(qlpack, packRelativePath);
|
||||
updateDefaultSuite(qlpack, qlPackDetails);
|
||||
removeWorkspaceRefs(qlpack);
|
||||
|
||||
await writeFile(packPath, dump(qlpack));
|
||||
@@ -461,19 +464,23 @@ async function addExtensionPacksAsDependencies(
|
||||
await writeFile(qlpackFile, dump(syntheticQueryPack));
|
||||
}
|
||||
|
||||
function updateDefaultSuite(qlpack: QlPackFile, packRelativePath: string) {
|
||||
function updateDefaultSuite(qlpack: QlPackFile, qlPackDetails: QlPackDetails) {
|
||||
delete qlpack.defaultSuiteFile;
|
||||
qlpack.defaultSuite = generateDefaultSuite(packRelativePath);
|
||||
qlpack.defaultSuite = generateDefaultSuite(qlPackDetails);
|
||||
}
|
||||
|
||||
function generateDefaultSuite(packRelativePath: string) {
|
||||
function generateDefaultSuite(qlPackDetails: QlPackDetails) {
|
||||
const queries = qlPackDetails.queryFiles.map((query) => {
|
||||
const relativePath = relative(qlPackDetails.qlPackRootPath, query);
|
||||
return {
|
||||
query: relativePath.replace(/\\/g, "/"),
|
||||
};
|
||||
});
|
||||
return [
|
||||
{
|
||||
description: "Query suite for variant analysis",
|
||||
},
|
||||
{
|
||||
query: packRelativePath.replace(/\\/g, "/"),
|
||||
},
|
||||
...queries,
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -91,6 +91,7 @@ import { createMultiSelectionCommand } from "../common/vscode/selection-commands
|
||||
import { askForLanguage, findLanguage } from "../codeql-cli/query-language";
|
||||
import type { QlPackDetails } from "./ql-pack-details";
|
||||
import { findPackRoot, getQlPackFilePath } from "../common/ql";
|
||||
import { tryGetQueryMetadata } from "../codeql-cli/query-metadata";
|
||||
|
||||
const maxRetryCount = 3;
|
||||
|
||||
@@ -194,26 +195,22 @@ export class VariantAnalysisManager
|
||||
throw new Error("Please select a .ql file to run as a variant analysis");
|
||||
}
|
||||
|
||||
await this.runVariantAnalysisCommand(fileUri);
|
||||
await this.runVariantAnalysisCommand([fileUri]);
|
||||
}
|
||||
|
||||
private async runVariantAnalysisFromContextEditor(uri: Uri) {
|
||||
await this.runVariantAnalysisCommand(uri);
|
||||
await this.runVariantAnalysisCommand([uri]);
|
||||
}
|
||||
|
||||
private async runVariantAnalysisFromExplorer(fileURIs: Uri[]): Promise<void> {
|
||||
if (fileURIs.length !== 1) {
|
||||
throw new Error("Can only run a single query at a time");
|
||||
}
|
||||
|
||||
return this.runVariantAnalysisCommand(fileURIs[0]);
|
||||
return this.runVariantAnalysisCommand(fileURIs);
|
||||
}
|
||||
|
||||
private async runVariantAnalysisFromQueriesPanel(
|
||||
queryTreeViewItem: QueryTreeViewItem,
|
||||
): Promise<void> {
|
||||
if (queryTreeViewItem.path !== undefined) {
|
||||
await this.runVariantAnalysisCommand(Uri.file(queryTreeViewItem.path));
|
||||
await this.runVariantAnalysisCommand([Uri.file(queryTreeViewItem.path)]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -272,10 +269,8 @@ export class VariantAnalysisManager
|
||||
const qlPackFilePath = await getQlPackFilePath(packDir);
|
||||
|
||||
// Build up details to pass to the functions that run the variant analysis.
|
||||
// For now, only include the first problem query until we have support
|
||||
// for multiple queries.
|
||||
const qlPackDetails: QlPackDetails = {
|
||||
queryFile: problemQueries[0],
|
||||
queryFiles: problemQueries,
|
||||
qlPackRootPath: packDir,
|
||||
qlPackFilePath,
|
||||
language,
|
||||
@@ -312,14 +307,27 @@ export class VariantAnalysisManager
|
||||
return problemQueries;
|
||||
}
|
||||
|
||||
private async runVariantAnalysisCommand(uri: Uri): Promise<void> {
|
||||
// Build up details to pass to the functions that run the variant analysis.
|
||||
const qlPackRootPath = await findPackRoot(uri.fsPath);
|
||||
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");
|
||||
}
|
||||
|
||||
const qlPackRootPath = await findPackRoot(queryFiles[0].fsPath);
|
||||
const qlPackFilePath = await getQlPackFilePath(qlPackRootPath);
|
||||
|
||||
// Make sure that all remaining queries have the same pack root
|
||||
for (let i = 1; i < queryFiles.length; i++) {
|
||||
const packRoot = await findPackRoot(queryFiles[i].fsPath);
|
||||
if (packRoot !== qlPackRootPath) {
|
||||
throw new Error(
|
||||
"Please select queries that all belong to the same query pack",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Open popup to ask for language if not already hardcoded
|
||||
const language = qlPackFilePath
|
||||
? await findLanguage(this.cliServer, uri)
|
||||
? await findLanguage(this.cliServer, queryFiles[0])
|
||||
: await askForLanguage(this.cliServer);
|
||||
|
||||
if (!language) {
|
||||
@@ -327,7 +335,7 @@ export class VariantAnalysisManager
|
||||
}
|
||||
|
||||
const qlPackDetails: QlPackDetails = {
|
||||
queryFile: uri.fsPath,
|
||||
queryFiles: queryFiles.map((uri) => uri.fsPath),
|
||||
qlPackRootPath,
|
||||
qlPackFilePath,
|
||||
language,
|
||||
@@ -361,8 +369,6 @@ export class VariantAnalysisManager
|
||||
actionBranch,
|
||||
base64Pack,
|
||||
repoSelection,
|
||||
queryFile,
|
||||
queryMetadata,
|
||||
controllerRepo,
|
||||
queryStartTime,
|
||||
} = await prepareRemoteQueryRun(
|
||||
@@ -374,7 +380,15 @@ export class VariantAnalysisManager
|
||||
this.dbManager,
|
||||
);
|
||||
|
||||
const queryName = getQueryName(queryMetadata, queryFile);
|
||||
// For now we get the metadata for the first query in the pack.
|
||||
// and use that in the submission and query history. In the future
|
||||
// we'll need to consider how to handle having multiple queries.
|
||||
const firstQueryFile = qlPackDetails.queryFiles[0];
|
||||
const queryMetadata = await tryGetQueryMetadata(
|
||||
this.cliServer,
|
||||
firstQueryFile,
|
||||
);
|
||||
const queryName = getQueryName(queryMetadata, firstQueryFile);
|
||||
const language = qlPackDetails.language;
|
||||
const variantAnalysisLanguage = parseVariantAnalysisQueryLanguage(language);
|
||||
if (variantAnalysisLanguage === undefined) {
|
||||
@@ -383,12 +397,14 @@ export class VariantAnalysisManager
|
||||
);
|
||||
}
|
||||
|
||||
const queryText = await readFile(queryFile, "utf8");
|
||||
const queryText = await readFile(firstQueryFile, "utf8");
|
||||
|
||||
// TODO: Once we have basic support multiple queries, and qlPackDetails has
|
||||
// more than 1 queryFile, we should set this to have a proper value
|
||||
// (e.g. { language: variantAnalysisLanguage })
|
||||
const queries: VariantAnalysisQueries | undefined = undefined;
|
||||
const queries: VariantAnalysisQueries | undefined =
|
||||
qlPackDetails.queryFiles.length === 1
|
||||
? undefined
|
||||
: {
|
||||
language: qlPackDetails.language,
|
||||
};
|
||||
|
||||
const variantAnalysisSubmission: VariantAnalysisSubmission = {
|
||||
startTime: queryStartTime,
|
||||
@@ -396,7 +412,7 @@ export class VariantAnalysisManager
|
||||
controllerRepoId: controllerRepo.id,
|
||||
query: {
|
||||
name: queryName,
|
||||
filePath: queryFile,
|
||||
filePath: firstQueryFile,
|
||||
pack: base64Pack,
|
||||
language: variantAnalysisLanguage,
|
||||
text: queryText,
|
||||
|
||||
@@ -104,7 +104,7 @@ describe("Variant Analysis Manager", () => {
|
||||
const qlPackRootPath = getFileOrDir("data-remote-qlpack");
|
||||
const qlPackFilePath = getFileOrDir("data-remote-qlpack/qlpack.yml");
|
||||
const qlPackDetails: QlPackDetails = {
|
||||
queryFile: filePath,
|
||||
queryFiles: [filePath],
|
||||
qlPackRootPath,
|
||||
qlPackFilePath,
|
||||
language: QueryLanguage.Javascript,
|
||||
@@ -132,7 +132,7 @@ describe("Variant Analysis Manager", () => {
|
||||
const filePath = getFileOrDir("data-remote-no-qlpack/in-pack.ql");
|
||||
const qlPackRootPath = getFileOrDir("data-remote-no-qlpack");
|
||||
const qlPackDetails: QlPackDetails = {
|
||||
queryFile: filePath,
|
||||
queryFiles: [filePath],
|
||||
qlPackRootPath,
|
||||
qlPackFilePath: undefined,
|
||||
language: QueryLanguage.Javascript,
|
||||
@@ -165,7 +165,7 @@ describe("Variant Analysis Manager", () => {
|
||||
"data-remote-qlpack-nested/codeql-pack.yml",
|
||||
);
|
||||
const qlPackDetails: QlPackDetails = {
|
||||
queryFile: filePath,
|
||||
queryFiles: [filePath],
|
||||
qlPackRootPath,
|
||||
qlPackFilePath,
|
||||
language: QueryLanguage.Javascript,
|
||||
@@ -193,7 +193,7 @@ describe("Variant Analysis Manager", () => {
|
||||
const filePath = getFileOrDir("data-remote-no-qlpack/in-pack.ql");
|
||||
const qlPackRootPath = getFileOrDir("data-remote-no-qlpack");
|
||||
const qlPackDetails: QlPackDetails = {
|
||||
queryFile: filePath,
|
||||
queryFiles: [filePath],
|
||||
qlPackRootPath,
|
||||
qlPackFilePath: undefined,
|
||||
language: QueryLanguage.Javascript,
|
||||
@@ -369,7 +369,7 @@ describe("Variant Analysis Manager", () => {
|
||||
}) {
|
||||
const filePath = getFileOrDir(queryPath);
|
||||
const qlPackDetails: QlPackDetails = {
|
||||
queryFile: filePath,
|
||||
queryFiles: [filePath],
|
||||
qlPackRootPath: getFileOrDir(qlPackRootPath),
|
||||
qlPackFilePath: qlPackFilePath && getFileOrDir(qlPackFilePath),
|
||||
language: QueryLanguage.Javascript,
|
||||
@@ -464,7 +464,7 @@ describe("Variant Analysis Manager", () => {
|
||||
describe("runVariantAnalysisFromPublishedPack", () => {
|
||||
// Temporarily disabling this until we add a way to receive multiple queries in the
|
||||
// runVariantAnalysis function.
|
||||
it.skip("should download pack for correct language and identify problem queries", async () => {
|
||||
it("should download pack for correct language and identify problem queries", async () => {
|
||||
const showQuickPickSpy = jest
|
||||
.spyOn(window, "showQuickPick")
|
||||
.mockResolvedValue(
|
||||
@@ -483,15 +483,17 @@ describe("Variant Analysis Manager", () => {
|
||||
expect(showQuickPickSpy).toHaveBeenCalledTimes(1);
|
||||
expect(runVariantAnalysisMock).toHaveBeenCalledTimes(1);
|
||||
|
||||
const queries: Uri[] = runVariantAnalysisMock.mock.calls[0][0];
|
||||
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.fsPath.includes("PostMessageStar.ql")),
|
||||
queries.find((q) => q.includes("PostMessageStar.ql")),
|
||||
).toBeDefined();
|
||||
// Should not include non-problem queries.
|
||||
expect(
|
||||
queries.find((q) => q.fsPath.includes("LinesOfCode.ql")),
|
||||
queries.find((q) => q.includes("LinesOfCode.ql")),
|
||||
).not.toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user