Refactor configuration errors (#2105)

Refactor the existing classes of configuration errors into their own file; consolidate the place we check for configuration errors into `codeql.ts`, where the actual command invocations happen.

Also, rename the `UserError` type to `ConfigurationError` to standardize on a single term.
This commit is contained in:
Angela P Wen 2024-02-08 09:20:03 -08:00 committed by GitHub
parent fc9f9e5ef9
commit 1515e2bb20
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
54 changed files with 654 additions and 502 deletions

View file

@ -15,7 +15,7 @@ import {
codeQlVersionAbove,
GitHubVersion,
prettyPrintPack,
UserError,
ConfigurationError,
} from "./util";
// Property names from the user-supplied config file.
@ -332,7 +332,7 @@ export async function getLanguages(
// If the languages parameter was not given and no languages were
// detected then fail here as this is a workflow configuration error.
if (languages.length === 0) {
throw new UserError(getNoLanguagesError());
throw new ConfigurationError(getNoLanguagesError());
}
// Make sure they are supported
@ -350,7 +350,7 @@ export async function getLanguages(
// Any unknown languages here would have come directly from the input
// since we filter unknown languages coming from the GitHub API.
if (unknownLanguages.length > 0) {
throw new UserError(getUnknownLanguagesError(unknownLanguages));
throw new ConfigurationError(getUnknownLanguagesError(unknownLanguages));
}
return parsedLanguages;
@ -631,7 +631,7 @@ function parseQueriesFromInput(
? rawQueriesInput.trim().slice(1).trim()
: rawQueriesInput?.trim() ?? "";
if (queriesInputCombines && trimmedInput.length === 0) {
throw new UserError(
throw new ConfigurationError(
getConfigFilePropertyError(
undefined,
"queries",
@ -664,11 +664,11 @@ export function parsePacksFromInput(
}
if (languages.length > 1) {
throw new UserError(
throw new ConfigurationError(
"Cannot specify a 'packs' input in a multi-language analysis. Use a codeql-config.yml file instead and specify packs by language.",
);
} else if (languages.length === 0) {
throw new UserError(
throw new ConfigurationError(
"No languages specified. Cannot process the packs input.",
);
}
@ -677,7 +677,7 @@ export function parsePacksFromInput(
if (packsInputCombines) {
rawPacksInput = rawPacksInput.trim().substring(1).trim();
if (!rawPacksInput) {
throw new UserError(
throw new ConfigurationError(
getConfigFilePropertyError(
undefined,
"packs",
@ -715,7 +715,7 @@ export function parsePacksFromInput(
*/
export function parsePacksSpecification(packStr: string): Pack {
if (typeof packStr !== "string") {
throw new UserError(getPacksStrInvalid(packStr));
throw new ConfigurationError(getPacksStrInvalid(packStr));
}
packStr = packStr.trim();
@ -743,14 +743,14 @@ export function parsePacksSpecification(packStr: string): Pack {
: undefined;
if (!PACK_IDENTIFIER_PATTERN.test(packName)) {
throw new UserError(getPacksStrInvalid(packStr));
throw new ConfigurationError(getPacksStrInvalid(packStr));
}
if (version) {
try {
new semver.Range(version);
} catch (e) {
// The range string is invalid. OK to ignore the caught error
throw new UserError(getPacksStrInvalid(packStr));
throw new ConfigurationError(getPacksStrInvalid(packStr));
}
}
@ -764,12 +764,12 @@ export function parsePacksSpecification(packStr: string): Pack {
path.normalize(packPath).split(path.sep).join("/") !==
packPath.split(path.sep).join("/"))
) {
throw new UserError(getPacksStrInvalid(packStr));
throw new ConfigurationError(getPacksStrInvalid(packStr));
}
if (!packPath && pathStart) {
// 0 length path
throw new UserError(getPacksStrInvalid(packStr));
throw new ConfigurationError(getPacksStrInvalid(packStr));
}
return {
@ -852,7 +852,9 @@ function parseRegistries(
? (yaml.load(registriesInput) as RegistryConfigWithCredentials[])
: undefined;
} catch (e) {
throw new UserError("Invalid registries input. Must be a YAML string.");
throw new ConfigurationError(
"Invalid registries input. Must be a YAML string.",
);
}
}
@ -868,12 +870,16 @@ function isLocal(configPath: string): boolean {
function getLocalConfig(configFile: string, workspacePath: string): UserConfig {
// Error if the config file is now outside of the workspace
if (!(configFile + path.sep).startsWith(workspacePath + path.sep)) {
throw new UserError(getConfigFileOutsideWorkspaceErrorMessage(configFile));
throw new ConfigurationError(
getConfigFileOutsideWorkspaceErrorMessage(configFile),
);
}
// Error if the file does not exist
if (!fs.existsSync(configFile)) {
throw new UserError(getConfigFileDoesNotExistErrorMessage(configFile));
throw new ConfigurationError(
getConfigFileDoesNotExistErrorMessage(configFile),
);
}
return yaml.load(fs.readFileSync(configFile, "utf8")) as UserConfig;
@ -890,7 +896,9 @@ async function getRemoteConfig(
const pieces = format.exec(configFile);
// 5 = 4 groups + the whole expression
if (pieces === null || pieces.groups === undefined || pieces.length < 5) {
throw new UserError(getConfigFileRepoFormatInvalidMessage(configFile));
throw new ConfigurationError(
getConfigFileRepoFormatInvalidMessage(configFile),
);
}
const response = await api
@ -906,9 +914,11 @@ async function getRemoteConfig(
if ("content" in response.data && response.data.content !== undefined) {
fileContents = response.data.content;
} else if (Array.isArray(response.data)) {
throw new UserError(getConfigFileDirectoryGivenMessage(configFile));
throw new ConfigurationError(
getConfigFileDirectoryGivenMessage(configFile),
);
} else {
throw new UserError(getConfigFileFormatInvalidMessage(configFile));
throw new ConfigurationError(getConfigFileFormatInvalidMessage(configFile));
}
return yaml.load(
@ -1008,7 +1018,7 @@ function createRegistriesBlock(registries: RegistryConfigWithCredentials[]): {
!Array.isArray(registries) ||
registries.some((r) => !r.url || !r.packages)
) {
throw new UserError(
throw new ConfigurationError(
"Invalid 'registries' input. Must be an array of objects with 'url' and 'packages' properties.",
);
}
@ -1071,7 +1081,7 @@ function validateBuildModeInput(
}
if (!Object.values(BuildMode).includes(buildModeInput as BuildMode)) {
throw new UserError(
throw new ConfigurationError(
`Invalid build mode: '${buildModeInput}'. Supported build modes are: ${Object.values(
BuildMode,
).join(", ")}.`,