Merge pull request #2744 from github/starcke/general-setup

Move pack setup out of fetch queries.
This commit is contained in:
Anders Starcke Henriksen
2023-08-25 09:26:01 +02:00
committed by GitHub
5 changed files with 140 additions and 108 deletions

View File

@@ -9,22 +9,16 @@ import { join } from "path";
import { App } from "../common/app";
import { withProgress } from "../common/vscode/progress";
import { pickExtensionPack } from "./extension-pack-picker";
import {
showAndLogErrorMessage,
showAndLogExceptionWithTelemetry,
} from "../common/logging";
import { showAndLogErrorMessage } from "../common/logging";
import { dir } from "tmp-promise";
import { fetchExternalApiQueries } from "./queries";
import { telemetryListener } from "../common/vscode/telemetry";
import { redactableError } from "../common/errors";
import { extLogger } from "../common/logging/vscode";
import { isQueryLanguage } from "../common/query-language";
import { setUpPack } from "./external-api-usage-queries";
import { DisposableObject } from "../common/disposable-object";
import { ModelDetailsPanel } from "./methods-usage/methods-usage-panel";
import { Mode } from "./shared/mode";
import { showResolvableLocation } from "../databases/local-databases/locations";
import { Usage } from "./external-api-usage";
import { setUpPack } from "./data-extensions-editor-queries";
const SUPPORTED_LANGUAGES: string[] = ["java", "csharp"];
@@ -138,19 +132,12 @@ export class DataExtensionsEditorModule extends DisposableObject {
return;
}
const query = fetchExternalApiQueries[language];
if (!query) {
void showAndLogExceptionWithTelemetry(
extLogger,
telemetryListener,
redactableError`No external API usage query found for language ${language}`,
);
return;
}
// Create new temporary directory for query files and pack dependencies
const queryDir = (await dir({ unsafeCleanup: true })).path;
await setUpPack(queryDir, query, language);
const success = await setUpPack(queryDir, language);
if (!success) {
return;
}
await this.cliServer.packInstall(queryDir);
const view = new DataExtensionsEditorView(

View File

@@ -0,0 +1,38 @@
import { join } from "path";
import { QueryLanguage } from "../common/query-language";
import { writeFile } from "fs-extra";
import { dump } from "js-yaml";
import { prepareExternalApiQuery } from "./external-api-usage-queries";
/**
* setUpPack sets up a directory to use for the data extension editor queries.
* @param queryDir The directory to set up.
* @param language The language to use for the queries.
* @returns true if the setup was successful, false otherwise.
*/
export async function setUpPack(
queryDir: string,
language: QueryLanguage,
): Promise<boolean> {
// Create the external API query
const externalApiQuerySuccess = await prepareExternalApiQuery(
queryDir,
language,
);
if (!externalApiQuerySuccess) {
return false;
}
// Set up a synthetic query pack to resolve dependencies.
const syntheticQueryPack = {
name: "codeql/external-api-usage",
version: "0.0.0",
dependencies: {
[`codeql/${language}-all`]: "*",
},
};
const qlpackFile = join(queryDir, "codeql-pack.yml");
await writeFile(qlpackFile, dump(syntheticQueryPack), "utf8");
return true;
}

View File

@@ -12,9 +12,8 @@ import { telemetryListener } from "../common/vscode/telemetry";
import { join } from "path";
import { Mode } from "./shared/mode";
import { writeFile } from "fs-extra";
import { Query } from "./queries/query";
import { QueryLanguage } from "../common/query-language";
import { dump } from "js-yaml";
import { fetchExternalApiQueries } from "./queries";
type RunQueryOptions = {
cliServer: Pick<CodeQLCliServer, "resolveQlpacks">;
@@ -27,36 +26,34 @@ type RunQueryOptions = {
token: CancellationToken;
};
export async function setUpPack(
export async function prepareExternalApiQuery(
queryDir: string,
query: Query,
language: QueryLanguage,
) {
Object.values(Mode).map(async (mode) => {
const queryFile = join(
queryDir,
`FetchExternalApis${mode.charAt(0).toUpperCase() + mode.slice(1)}Mode.ql`,
): Promise<boolean> {
// Resolve the query that we want to run.
const query = fetchExternalApiQueries[language];
if (!query) {
void showAndLogExceptionWithTelemetry(
extLogger,
telemetryListener,
redactableError`No external API usage query found for language ${language}`,
);
return false;
}
// Create the query file.
Object.values(Mode).map(async (mode) => {
const queryFile = join(queryDir, queryNameFromMode(mode));
await writeFile(queryFile, query[`${mode}ModeQuery`], "utf8");
});
// Create any dependencies
if (query.dependencies) {
for (const [filename, contents] of Object.entries(query.dependencies)) {
const dependencyFile = join(queryDir, filename);
await writeFile(dependencyFile, contents, "utf8");
}
}
const syntheticQueryPack = {
name: "codeql/external-api-usage",
version: "0.0.0",
dependencies: {
[`codeql/${language}-all`]: "*",
},
};
const qlpackFile = join(queryDir, "codeql-pack.yml");
await writeFile(qlpackFile, dump(syntheticQueryPack), "utf8");
return true;
}
export async function runQuery(
@@ -145,3 +142,9 @@ export async function readQueryResults({
return cliServer.bqrsDecode(bqrsPath, resultSet.name);
}
function queryNameFromMode(mode: Mode): string {
return `FetchExternalApis${
mode.charAt(0).toUpperCase() + mode.slice(1)
}Mode.ql`;
}

View File

@@ -0,0 +1,72 @@
import { readFile, readFileSync, readdir } from "fs-extra";
import { join } from "path";
import { load } from "js-yaml";
import { setUpPack } from "../../../../src/data-extensions-editor/data-extensions-editor-queries";
import { dirSync } from "tmp-promise";
import { fetchExternalApiQueries } from "../../../../src/data-extensions-editor/queries";
import { QueryLanguage } from "../../../../src/common/query-language";
import { Mode } from "../../../../src/data-extensions-editor/shared/mode";
describe("setUpPack", () => {
const languages = Object.keys(fetchExternalApiQueries).flatMap((lang) => {
const queryDir = dirSync({ unsafeCleanup: true }).name;
const query = fetchExternalApiQueries[lang as QueryLanguage];
if (!query) {
return [];
}
return { language: lang as QueryLanguage, queryDir, query };
});
test.each(languages)(
"should create files for $language",
async ({ language, queryDir, query }) => {
await setUpPack(queryDir, language);
const queryFiles = await readdir(queryDir);
expect(queryFiles.sort()).toEqual(
[
"codeql-pack.yml",
"FetchExternalApisApplicationMode.ql",
"FetchExternalApisFrameworkMode.ql",
"AutomodelVsCode.qll",
].sort(),
);
const suiteFileContents = await readFile(
join(queryDir, "codeql-pack.yml"),
"utf8",
);
const suiteYaml = load(suiteFileContents);
expect(suiteYaml).toEqual({
name: "codeql/external-api-usage",
version: "0.0.0",
dependencies: {
[`codeql/${language}-all`]: "*",
},
});
Object.values(Mode).forEach((mode) => {
expect(
readFileSync(
join(
queryDir,
`FetchExternalApis${
mode.charAt(0).toUpperCase() + mode.slice(1)
}Mode.ql`,
),
"utf8",
),
).toEqual(query[`${mode}ModeQuery`]);
});
for (const [filename, contents] of Object.entries(
query.dependencies ?? {},
)) {
expect(await readFile(join(queryDir, filename), "utf8")).toEqual(
contents,
);
}
},
);
});

View File

@@ -1,7 +1,6 @@
import {
readQueryResults,
runQuery,
setUpPack,
} from "../../../../src/data-extensions-editor/external-api-usage-queries";
import { createMockLogger } from "../../../__mocks__/loggerMock";
import { DatabaseKind } from "../../../../src/databases/local-databases";
@@ -14,75 +13,8 @@ import { showAndLogExceptionWithTelemetry } from "../../../../src/common/logging
import { QueryLanguage } from "../../../../src/common/query-language";
import { mockedUri } from "../../utils/mocking.helpers";
import { Mode } from "../../../../src/data-extensions-editor/shared/mode";
import { readFile, readFileSync, readdir } from "fs-extra";
import { join } from "path";
import { load } from "js-yaml";
describe("external api usage query", () => {
describe("setUpPack", () => {
const languages = Object.keys(fetchExternalApiQueries).flatMap((lang) => {
const queryDir = dirSync({ unsafeCleanup: true }).name;
const query = fetchExternalApiQueries[lang as QueryLanguage];
if (!query) {
return [];
}
return { language: lang as QueryLanguage, queryDir, query };
});
test.each(languages)(
"should create files for $language",
async ({ language, queryDir, query }) => {
await setUpPack(queryDir, query, language);
const queryFiles = await readdir(queryDir);
expect(queryFiles.sort()).toEqual(
[
"codeql-pack.yml",
"FetchExternalApisApplicationMode.ql",
"FetchExternalApisFrameworkMode.ql",
"AutomodelVsCode.qll",
].sort(),
);
const suiteFileContents = await readFile(
join(queryDir, "codeql-pack.yml"),
"utf8",
);
const suiteYaml = load(suiteFileContents);
expect(suiteYaml).toEqual({
name: "codeql/external-api-usage",
version: "0.0.0",
dependencies: {
[`codeql/${language}-all`]: "*",
},
});
Object.values(Mode).forEach((mode) => {
expect(
readFileSync(
join(
queryDir,
`FetchExternalApis${
mode.charAt(0).toUpperCase() + mode.slice(1)
}Mode.ql`,
),
"utf8",
),
).toEqual(query[`${mode}ModeQuery`]);
});
for (const [filename, contents] of Object.entries(
query.dependencies ?? {},
)) {
expect(await readFile(join(queryDir, filename), "utf8")).toEqual(
contents,
);
}
},
);
});
describe("runQuery", () => {
const language = Object.keys(fetchExternalApiQueries)[
Math.floor(Math.random() * Object.keys(fetchExternalApiQueries).length)