refactor: config file parsing (#27863)

This commit is contained in:
Rhys Arkins 2024-03-12 08:37:59 +01:00 committed by GitHub
parent 480b11f0ca
commit cda68de084
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 86 additions and 66 deletions

75
lib/config/parse.ts Normal file
View file

@ -0,0 +1,75 @@
import jsonValidator from 'json-dup-key-validator';
import JSON5 from 'json5';
import upath from 'upath';
import { logger } from '../logger';
import { parseJson } from '../util/common';
export function parseFileConfig(
fileName: string,
fileContents: string,
):
| { success: true; parsedContents: unknown }
| { success: false; validationError: string; validationMessage: string } {
const fileType = upath.extname(fileName);
if (fileType === '.json5') {
try {
return { success: true, parsedContents: JSON5.parse(fileContents) };
} catch (err) /* istanbul ignore next */ {
logger.debug({ fileName, fileContents }, 'Error parsing JSON5 file');
const validationError = 'Invalid JSON5 (parsing failed)';
const validationMessage = `JSON5.parse error: \`${err.message.replaceAll(
'`',
"'",
)}\``;
return {
success: false,
validationError,
validationMessage,
};
}
} else {
let allowDuplicateKeys = true;
let jsonValidationError = jsonValidator.validate(
fileContents,
allowDuplicateKeys,
);
if (jsonValidationError) {
const validationError = 'Invalid JSON (parsing failed)';
const validationMessage = jsonValidationError;
return {
success: false,
validationError,
validationMessage,
};
}
allowDuplicateKeys = false;
jsonValidationError = jsonValidator.validate(
fileContents,
allowDuplicateKeys,
);
if (jsonValidationError) {
const validationError = 'Duplicate keys in JSON';
const validationMessage = JSON.stringify(jsonValidationError);
return {
success: false,
validationError,
validationMessage,
};
}
try {
return {
success: true,
parsedContents: parseJson(fileContents, fileName),
};
} catch (err) /* istanbul ignore next */ {
logger.debug({ fileContents }, 'Error parsing renovate config');
const validationError = 'Invalid JSON (parsing failed)';
const validationMessage = `JSON.parse error: \`${err.message.replaceAll(
'`',
"'",
)}\``;
return { success: false, validationError, validationMessage };
}
}
}

View file

@ -1,12 +1,10 @@
import is from '@sindresorhus/is'; import is from '@sindresorhus/is';
import jsonValidator from 'json-dup-key-validator';
import JSON5 from 'json5';
import upath from 'upath';
import { mergeChildConfig } from '../../../config'; import { mergeChildConfig } from '../../../config';
import { configFileNames } from '../../../config/app-strings'; import { configFileNames } from '../../../config/app-strings';
import { decryptConfig } from '../../../config/decrypt'; import { decryptConfig } from '../../../config/decrypt';
import { migrateAndValidate } from '../../../config/migrate-validate'; import { migrateAndValidate } from '../../../config/migrate-validate';
import { migrateConfig } from '../../../config/migration'; import { migrateConfig } from '../../../config/migration';
import { parseFileConfig } from '../../../config/parse';
import * as presets from '../../../config/presets'; import * as presets from '../../../config/presets';
import { applySecretsToConfig } from '../../../config/secrets'; import { applySecretsToConfig } from '../../../config/secrets';
import type { RenovateConfig } from '../../../config/types'; import type { RenovateConfig } from '../../../config/types';
@ -131,71 +129,18 @@ export async function detectRepoFileConfig(): Promise<RepoFileConfig> {
configFileRaw = '{}'; configFileRaw = '{}';
} }
const fileType = upath.extname(configFileName); const parseResult = parseFileConfig(configFileName, configFileRaw);
if (fileType === '.json5') { if (!parseResult.success) {
try { return {
configFileParsed = JSON5.parse(configFileRaw); configFileName,
} catch (err) /* istanbul ignore next */ { configFileParseError: {
logger.debug( validationError: parseResult.validationError,
{ renovateConfig: configFileRaw }, validationMessage: parseResult.validationMessage,
'Error parsing renovate config renovate.json5', },
); };
const validationError = 'Invalid JSON5 (parsing failed)';
const validationMessage = `JSON5.parse error: \`${err.message.replaceAll(
'`',
"'",
)}\``;
return {
configFileName,
configFileParseError: { validationError, validationMessage },
};
}
} else {
let allowDuplicateKeys = true;
let jsonValidationError = jsonValidator.validate(
configFileRaw,
allowDuplicateKeys,
);
if (jsonValidationError) {
const validationError = 'Invalid JSON (parsing failed)';
const validationMessage = jsonValidationError;
return {
configFileName,
configFileParseError: { validationError, validationMessage },
};
}
allowDuplicateKeys = false;
jsonValidationError = jsonValidator.validate(
configFileRaw,
allowDuplicateKeys,
);
if (jsonValidationError) {
const validationError = 'Duplicate keys in JSON';
const validationMessage = JSON.stringify(jsonValidationError);
return {
configFileName,
configFileParseError: { validationError, validationMessage },
};
}
try {
configFileParsed = parseJson(configFileRaw, configFileName);
} catch (err) /* istanbul ignore next */ {
logger.debug(
{ renovateConfig: configFileRaw },
'Error parsing renovate config',
);
const validationError = 'Invalid JSON (parsing failed)';
const validationMessage = `JSON.parse error: \`${err.message.replaceAll(
'`',
"'",
)}\``;
return {
configFileName,
configFileParseError: { validationError, validationMessage },
};
}
} }
configFileParsed = parseResult.parsedContents;
logger.debug( logger.debug(
{ fileName: configFileName, config: configFileParsed }, { fileName: configFileName, config: configFileParsed },
'Repository config', 'Repository config',