Merge pull request #2054 from github/koesie10/codeql-pack-yml

Handle `codeql-pack.yml` files everywhere
This commit is contained in:
Koen Vlaswinkel
2023-02-09 15:36:00 +01:00
committed by GitHub
7 changed files with 112 additions and 30 deletions

View File

@@ -19,6 +19,7 @@ import { CancellationToken, Uri } from "vscode";
import { ProgressCallback } from "../commandRunner";
import { QueryRunner } from "../queryRunner";
import { redactableError } from "../pure/errors";
import { QLPACK_FILENAMES } from "../pure/ql";
export async function qlpackOfDatabase(
cli: CodeQLCliServer,
@@ -113,7 +114,7 @@ async function resolveContextualQuery(
// Work out the enclosing pack.
const packContents = await cli.packPacklist(query, false);
const packFilePath = packContents.find((p) =>
["codeql-pack.yml", "qlpack.yml"].includes(basename(p)),
QLPACK_FILENAMES.includes(basename(p)),
);
if (packFilePath === undefined) {
// Should not happen; we already resolved this query.

View File

@@ -845,6 +845,7 @@ async function activateWithInstalledDistribution(
documentSelector: [
{ language: "ql", scheme: "file" },
{ language: "yaml", scheme: "file", pattern: "**/qlpack.yml" },
{ language: "yaml", scheme: "file", pattern: "**/codeql-pack.yml" },
],
synchronize: {
configurationSection: "codeQL",

View File

@@ -23,6 +23,7 @@ import { extLogger, OutputChannelLogger } from "./common";
import { QueryMetadata } from "./pure/interface-types";
import { telemetryListener } from "./telemetry";
import { RedactableError } from "./pure/errors";
import { getQlPackPath } from "./pure/ql";
// Shared temporary folder for the extension.
export const tmpDir = dirSync({
@@ -387,17 +388,22 @@ async function findDbschemePack(
): Promise<{ name: string; isLibraryPack: boolean }> {
for (const { packDir, packName } of packs) {
if (packDir !== undefined) {
const qlpack = load(
await readFile(join(packDir, "qlpack.yml"), "utf8"),
) as { dbscheme?: string; library?: boolean };
if (
qlpack.dbscheme !== undefined &&
basename(qlpack.dbscheme) === basename(dbschemePath)
) {
return {
name: packName,
isLibraryPack: qlpack.library === true,
const qlpackPath = await getQlPackPath(packDir);
if (qlpackPath !== undefined) {
const qlpack = load(await readFile(qlpackPath, "utf8")) as {
dbscheme?: string;
library?: boolean;
};
if (
qlpack.dbscheme !== undefined &&
basename(qlpack.dbscheme) === basename(dbschemePath)
) {
return {
name: packName,
isLibraryPack: qlpack.library === true,
};
}
}
}
}

View File

@@ -0,0 +1,19 @@
import { join } from "path";
import { pathExists } from "fs-extra";
export const QLPACK_FILENAMES = ["qlpack.yml", "codeql-pack.yml"];
export const FALLBACK_QLPACK_FILENAME = QLPACK_FILENAMES[0];
export async function getQlPackPath(
packRoot: string,
): Promise<string | undefined> {
for (const filename of QLPACK_FILENAMES) {
const path = join(packRoot, filename);
if (await pathExists(path)) {
return path;
}
}
return undefined;
}

View File

@@ -19,6 +19,7 @@ import {
} from "./helpers";
import { ProgressCallback, UserCancellationException } from "./commandRunner";
import { getErrorMessage } from "./pure/helpers-pure";
import { FALLBACK_QLPACK_FILENAME, getQlPackPath } from "./pure/ql";
const QUICK_QUERIES_DIR_NAME = "quick-queries";
const QUICK_QUERY_QUERY_NAME = "quick-query.ql";
@@ -112,7 +113,7 @@ export async function displayQuickQuery(
const dbscheme = await getPrimaryDbscheme(datasetFolder);
const qlpack = (await getQlPackForDbscheme(cliServer, dbscheme))
.dbschemePack;
const qlPackFile = join(queriesDir, "qlpack.yml");
const qlPackFile = await getQlPackPath(queriesDir);
const qlFile = join(queriesDir, QUICK_QUERY_QUERY_NAME);
const shouldRewrite = await checkShouldRewrite(qlPackFile, qlpack);
@@ -126,7 +127,7 @@ export async function displayQuickQuery(
},
};
await writeFile(
qlPackFile,
qlPackFile ?? join(queriesDir, FALLBACK_QLPACK_FILENAME),
QLPACK_FILE_HEADER + dump(quickQueryQlpackYaml),
"utf8",
);
@@ -158,7 +159,13 @@ export async function displayQuickQuery(
}
}
async function checkShouldRewrite(qlPackFile: string, newDependency: string) {
async function checkShouldRewrite(
qlPackFile: string | undefined,
newDependency: string,
) {
if (!qlPackFile) {
return true;
}
if (!(await pathExists(qlPackFile))) {
return true;
}

View File

@@ -1,7 +1,7 @@
import { CancellationToken, Uri, window } from "vscode";
import { relative, join, sep, dirname, parse, basename } from "path";
import { dump, load } from "js-yaml";
import { pathExists, copy, writeFile, readFile, mkdirp } from "fs-extra";
import { copy, writeFile, readFile, mkdirp } from "fs-extra";
import { dir, tmpName } from "tmp-promise";
import {
askForLanguage,
@@ -30,6 +30,11 @@ import {
} from "./repository-selection";
import { Repository } from "./shared/repository";
import { DbManager } from "../databases/db-manager";
import {
getQlPackPath,
FALLBACK_QLPACK_FILENAME,
QLPACK_FILENAMES,
} from "../pure/ql";
export interface QlPack {
name: string;
@@ -67,7 +72,7 @@ async function generateQueryPack(
const targetQueryFileName = join(queryPackDir, packRelativePath);
let language: string | undefined;
if (await getExistingPackFile(originalPackRoot)) {
if (await getQlPackPath(originalPackRoot)) {
// don't include ql files. We only want the queryFile to be copied.
const toCopy = await cliServer.packPacklist(originalPackRoot, false);
@@ -120,7 +125,10 @@ async function generateQueryPack(
},
defaultSuite: generateDefaultSuite(packRelativePath),
};
await writeFile(join(queryPackDir, "qlpack.yml"), dump(syntheticQueryPack));
await writeFile(
join(queryPackDir, FALLBACK_QLPACK_FILENAME),
dump(syntheticQueryPack),
);
}
if (!language) {
throw new UserCancellationException("Could not determine language.");
@@ -163,7 +171,7 @@ async function generateQueryPack(
async function findPackRoot(queryFile: string): Promise<string> {
// recursively find the directory containing qlpack.yml
let dir = dirname(queryFile);
while (!(await getExistingPackFile(dir))) {
while (!(await getQlPackPath(dir))) {
dir = dirname(dir);
if (isFileSystemRoot(dir)) {
// there is no qlpack.yml in this directory or any parent directory.
@@ -175,16 +183,6 @@ async function findPackRoot(queryFile: string): Promise<string> {
return dir;
}
async function getExistingPackFile(dir: string) {
if (await pathExists(join(dir, "qlpack.yml"))) {
return join(dir, "qlpack.yml");
}
if (await pathExists(join(dir, "codeql-pack.yml"))) {
return join(dir, "codeql-pack.yml");
}
return undefined;
}
function isFileSystemRoot(dir: string): boolean {
const pathObj = parse(dir);
return pathObj.root === dir && pathObj.base === "";
@@ -319,12 +317,14 @@ async function fixPackFile(
queryPackDir: string,
packRelativePath: string,
): Promise<void> {
const packPath = await getExistingPackFile(queryPackDir);
const packPath = await getQlPackPath(queryPackDir);
// This should not happen since we create the pack ourselves.
if (!packPath) {
throw new Error(
`Could not find qlpack.yml or codeql-pack.yml file in '${queryPackDir}'`,
`Could not find ${QLPACK_FILENAMES.join(
" or ",
)} file in '${queryPackDir}'`,
);
}
const qlpack = load(await readFile(packPath, "utf8")) as QlPack;

View File

@@ -0,0 +1,48 @@
import { join } from "path";
import { dirSync } from "tmp-promise";
import { DirResult } from "tmp";
import { writeFile } from "fs-extra";
import { getQlPackPath } from "../../../src/pure/ql";
describe("getQlPackPath", () => {
let tmpDir: DirResult;
beforeEach(() => {
tmpDir = dirSync({
prefix: "queries_",
keep: false,
unsafeCleanup: true,
});
});
afterEach(() => {
tmpDir.removeCallback();
});
it("should find a qlpack.yml when it exists", async () => {
await writeFile(join(tmpDir.name, "qlpack.yml"), "name: test");
const result = await getQlPackPath(tmpDir.name);
expect(result).toEqual(join(tmpDir.name, "qlpack.yml"));
});
it("should find a codeql-pack.yml when it exists", async () => {
await writeFile(join(tmpDir.name, "codeql-pack.yml"), "name: test");
const result = await getQlPackPath(tmpDir.name);
expect(result).toEqual(join(tmpDir.name, "codeql-pack.yml"));
});
it("should find a qlpack.yml when both exist", async () => {
await writeFile(join(tmpDir.name, "qlpack.yml"), "name: test");
await writeFile(join(tmpDir.name, "codeql-pack.yml"), "name: test");
const result = await getQlPackPath(tmpDir.name);
expect(result).toEqual(join(tmpDir.name, "qlpack.yml"));
});
it("should find nothing when it doesn't exist", async () => {
const result = await getQlPackPath(tmpDir.name);
expect(result).toEqual(undefined);
});
});