Merge pull request #2407 from github/koesie10/query-language

Use `QueryLanguage` type for representing query languages
This commit is contained in:
Koen Vlaswinkel
2023-06-02 14:13:04 +02:00
committed by GitHub
5 changed files with 55 additions and 12 deletions

View File

@@ -4,6 +4,7 @@ import { writeFile } from "fs-extra";
import { dump as dumpYaml } from "js-yaml";
import {
getOnDiskWorkspaceFolders,
isQueryLanguage,
showAndLogExceptionWithTelemetry,
} from "../helpers";
import { TeeLogger } from "../common";
@@ -15,7 +16,6 @@ import { fetchExternalApiQueries } from "./queries";
import { QueryResultType } from "../pure/new-messages";
import { join } from "path";
import { redactableError } from "../pure/errors";
import { QueryLanguage } from "../common/query-language";
export type RunQueryOptions = {
cliServer: Pick<CodeQLCliServer, "resolveQlpacks">;
@@ -41,7 +41,14 @@ export async function runQuery({
// For a reference of what this should do in the future, see the previous implementation in
// https://github.com/github/vscode-codeql/blob/089d3566ef0bc67d9b7cc66e8fd6740b31c1c0b0/extensions/ql-vscode/src/data-extensions-editor/external-api-usage-query.ts#L33-L72
const query = fetchExternalApiQueries[databaseItem.language as QueryLanguage];
if (!isQueryLanguage(databaseItem.language)) {
void showAndLogExceptionWithTelemetry(
redactableError`Unsupported database language ${databaseItem.language}`,
);
return;
}
const query = fetchExternalApiQueries[databaseItem.language];
if (!query) {
void showAndLogExceptionWithTelemetry(
redactableError`No external API usage query found for language ${databaseItem.language}`,

View File

@@ -16,12 +16,12 @@ import { DatabaseItemImpl } from "./database-item-impl";
import {
getFirstWorkspaceFolder,
isFolderAlreadyInWorkspace,
isQueryLanguage,
showAndLogExceptionWithTelemetry,
showNeverAskAgainDialog,
} from "../../helpers";
import { existsSync } from "fs";
import { QlPackGenerator } from "../../qlpack-generator";
import { QueryLanguage } from "../../common/query-language";
import { asError, getErrorMessage } from "../../pure/helpers-pure";
import { DatabaseItem, PersistedDatabaseItem } from "./database-item";
import { redactableError } from "../../pure/errors";
@@ -213,6 +213,13 @@ export class DatabaseManager extends DisposableObject {
return;
}
if (!isQueryLanguage(databaseItem.language)) {
void this.logger.log(
"Could not create skeleton QL pack because the selected database's language is not supported.",
);
return;
}
const firstWorkspaceFolder = getFirstWorkspaceFolder();
const folderName = `codeql-custom-queries-${databaseItem.language}`;
@@ -243,7 +250,7 @@ export class DatabaseManager extends DisposableObject {
try {
const qlPackGenerator = new QlPackGenerator(
folderName,
databaseItem.language as QueryLanguage,
databaseItem.language,
this.cli,
firstWorkspaceFolder,
);

View File

@@ -18,7 +18,7 @@ import { QueryMetadata } from "./pure/interface-types";
import { telemetryListener } from "./telemetry";
import { RedactableError } from "./pure/errors";
import { getQlPackPath } from "./pure/ql";
import { dbSchemeToLanguage } from "./common/query-language";
import { dbSchemeToLanguage, QueryLanguage } from "./common/query-language";
import { isCodespacesTemplate } from "./config";
import { AppCommandManager } from "./common/commands";
@@ -548,6 +548,10 @@ export async function isLikelyDbLanguageFolder(dbPath: string) {
);
}
export function isQueryLanguage(language: string): language is QueryLanguage {
return Object.values(QueryLanguage).includes(language as QueryLanguage);
}
/**
* Finds the language that a query targets.
* If it can't be autodetected, prompt the user to specify the language manually.
@@ -555,7 +559,7 @@ export async function isLikelyDbLanguageFolder(dbPath: string) {
export async function findLanguage(
cliServer: CodeQLCliServer,
queryUri: Uri | undefined,
): Promise<string | undefined> {
): Promise<QueryLanguage | undefined> {
const uri = queryUri || Window.activeTextEditor?.document.uri;
if (uri !== undefined) {
try {
@@ -565,7 +569,14 @@ export async function findLanguage(
);
const language = Object.keys(queryInfo.byLanguage)[0];
void extLogger.log(`Detected query language: ${language}`);
return language;
if (isQueryLanguage(language)) {
return language;
}
void extLogger.log(
"Query language is unsupported. Select language manually.",
);
} catch (e) {
void extLogger.log(
"Could not autodetect query language. Select language manually.",
@@ -580,7 +591,7 @@ export async function findLanguage(
export async function askForLanguage(
cliServer: CodeQLCliServer,
throwOnEmpty = true,
): Promise<string | undefined> {
): Promise<QueryLanguage | undefined> {
const language = await Window.showQuickPick(
await cliServer.getSupportedLanguages(),
{
@@ -597,7 +608,18 @@ export async function askForLanguage(
"Language not found. Language must be specified manually.",
);
}
return undefined;
}
if (!isQueryLanguage(language)) {
void showAndLogErrorMessage(
`Language '${language}' is not supported. Only languages ${Object.values(
QueryLanguage,
).join(", ")} are supported.`,
);
return undefined;
}
return language;
}

View File

@@ -41,7 +41,7 @@ export const QUERY_LANGUAGE_TO_DATABASE_REPO: QueryLanguagesToDatabaseMap = {
};
export class SkeletonQueryWizard {
private language: string | undefined;
private language: QueryLanguage | undefined;
private fileName = "example.ql";
private qlPackStoragePath: string | undefined;
@@ -154,6 +154,9 @@ export class SkeletonQueryWizard {
if (this.folderName === undefined) {
throw new Error("Folder name is undefined");
}
if (this.language === undefined) {
throw new Error("Language is undefined");
}
this.progress({
message: "Creating skeleton QL pack around query",
@@ -164,7 +167,7 @@ export class SkeletonQueryWizard {
try {
const qlPackGenerator = new QlPackGenerator(
this.folderName,
this.language as QueryLanguage,
this.language,
this.cliServer,
this.qlPackStoragePath,
);
@@ -181,6 +184,9 @@ export class SkeletonQueryWizard {
if (this.folderName === undefined) {
throw new Error("Folder name is undefined");
}
if (this.language === undefined) {
throw new Error("Language is undefined");
}
this.progress({
message:
@@ -192,7 +198,7 @@ export class SkeletonQueryWizard {
try {
const qlPackGenerator = new QlPackGenerator(
this.folderName,
this.language as QueryLanguage,
this.language,
this.cliServer,
this.qlPackStoragePath,
);

View File

@@ -39,6 +39,7 @@ import {
QLPACK_FILENAMES,
QLPACK_LOCK_FILENAMES,
} from "../pure/ql";
import { QueryLanguage } from "../common/query-language";
export interface QlPack {
name: string;
@@ -76,7 +77,7 @@ async function generateQueryPack(
const targetQueryFileName = join(queryPackDir, packRelativePath);
const workspaceFolders = getOnDiskWorkspaceFolders();
let language: string | undefined;
let language: QueryLanguage | undefined;
// Check if the query is already in a query pack.
// If so, copy the entire query pack to the temporary directory.