UNPKG

renovate

Version:

Automated dependency updates. Flexible so you don't need to be.

207 lines (206 loc) • 9.39 kB
import { CONFIG_VALIDATION } from "../../constants/error-messages.js"; import { get, set } from "../../util/cache/memory/index.js"; import { regEx } from "../../util/regex.js"; import { GlobalConfig } from "../global.js"; import { logger } from "../../logger/index.js"; import { clone } from "../../util/clone.js"; import { massageConfig } from "../massage.js"; import { removedPresets } from "./common.js"; import { mergeChildConfig } from "../utils.js"; import { migrateConfig } from "../migration.js"; import { compile } from "../../util/template/index.js"; import { ExternalHostError } from "../../types/errors/external-host-error.js"; import { getPreset as getPreset$1, isInternal } from "./internal/index.js"; import { PRESET_DEP_NOT_FOUND } from "./util.js"; import { parsePreset } from "./parse.js"; import { isArray, isNullOrUndefined, isObject, isString } from "@sindresorhus/is"; //#region lib/config/presets/index.ts const presetSourceLoaders = { forgejo: () => import("./forgejo/index.js"), gitea: () => import("./gitea/index.js"), github: () => import("./github/index.js"), gitlab: () => import("./gitlab/index.js"), http: () => import("./http/index.js"), local: () => import("./local/index.js"), npm: () => import("./npm/index.js") }; const presetCacheNamespace = "preset"; function replaceArgs(obj, argMapping) { if (isString(obj)) { let returnStr = obj; for (const [arg, argVal] of Object.entries(argMapping)) { const re = regEx(`{{${arg}}}`, "g", false); returnStr = returnStr.replace(re, argVal); } return returnStr; } if (isArray(obj)) { const returnArray = []; for (const item of obj) returnArray.push(replaceArgs(item, argMapping)); return returnArray; } if (isObject(obj)) { const returnObj = {}; for (const [key, val] of Object.entries(obj)) returnObj[key] = replaceArgs(val, argMapping); return returnObj; } return obj; } async function getPreset(preset, baseConfig) { logger.trace(`getPreset(${preset})`); const newPreset = removedPresets[preset]; if (newPreset) return getPreset(newPreset, baseConfig); if (newPreset === null) return {}; const { presetSource, repo, presetPath, presetName, tag, params, rawParams } = parsePreset(preset); let presetConfig; if (presetSource === "internal") presetConfig = getPreset$1({ repo, presetPath, presetName, tag }); else { const cacheKey = `preset:${preset}`; const packageCache = GlobalConfig.get("presetCachePersistence") ? await import("../../util/cache/package/index.js") : void 0; if (packageCache) presetConfig = await packageCache.get(presetCacheNamespace, cacheKey); else presetConfig = get(cacheKey); if (isNullOrUndefined(presetConfig)) { presetConfig = await (await presetSourceLoaders[presetSource]()).getPreset({ repo, presetPath, presetName, tag }); if (packageCache) await packageCache.set(presetCacheNamespace, cacheKey, presetConfig, 15); else set(cacheKey, presetConfig); } } if (!presetConfig) throw new Error(PRESET_DEP_NOT_FOUND); logger.trace({ presetConfig }, `Found preset ${preset}`); if (params) { const argMapping = {}; for (const [index, value] of params.entries()) argMapping[`arg${index}`] = value; if (rawParams) argMapping.args = rawParams; presetConfig = replaceArgs(presetConfig, argMapping); } logger.trace({ presetConfig }, `Applied params to preset ${preset}`); const presetKeys = Object.keys(presetConfig); if (presetKeys.length === 2 && presetKeys.includes("description") && presetKeys.includes("extends")) delete presetConfig.description; const packageListKeys = ["description", "matchPackageNames"]; if (presetKeys.every((key) => packageListKeys.includes(key))) delete presetConfig.description; const { migratedConfig } = migrateConfig(presetConfig); return massageConfig(migratedConfig); } /** * @param [mergeInternalPresets=true] when resolving the config presets, whether to merge Renovate internal presets into the resulting configuration. * When set to `false`, this will resolve these internal presets (recursively), but not merge them. * This is primarily intended to be used by "shallow config" resolution (for logging purposes). */ async function resolveConfigPresets(inputConfig, baseConfig, _ignorePresets, existingPresets = [], mergeInternalPresets = true) { const allVisitedPresets = { merged: /* @__PURE__ */ new Set(), unmerged: /* @__PURE__ */ new Set() }; let ignorePresets = clone(_ignorePresets); if (!ignorePresets || ignorePresets.length === 0) ignorePresets = inputConfig.ignorePresets ?? []; logger.trace({ config: inputConfig, existingPresets, mergeInternalPresets }, "resolveConfigPresets"); let config = {}; if (inputConfig.extends?.length) { inputConfig.extends = inputConfig.extends.map((tmpl) => compile(tmpl, {})); for (const preset of inputConfig.extends) { if (!mergeInternalPresets && isInternal(preset)) { logger.once.trace({ ignoredPreset: preset, mergeInternalPresets }, "Not merging preset"); allVisitedPresets.unmerged.add(preset); continue; } if (shouldResolvePreset(preset, existingPresets, ignorePresets)) { logger.trace(`Resolving preset "${preset}"`); const { config: presetConfig, visitedPresets } = await resolveConfigPresets(await fetchPreset(preset, baseConfig, inputConfig, existingPresets), baseConfig ?? inputConfig, ignorePresets, existingPresets.concat([preset]), mergeInternalPresets); if (inputConfig?.ignoreDeps?.length === 0) delete presetConfig.description; config = mergeChildConfig(config, presetConfig); allVisitedPresets.merged.add(preset); for (const mergedPreset of visitedPresets.merged) allVisitedPresets.merged.add(mergedPreset); for (const unmergedPreset of visitedPresets.unmerged) allVisitedPresets.unmerged.add(unmergedPreset); } } } logger.trace({ config }, `Post-preset resolve config`); config = mergeChildConfig(config, inputConfig); delete config.extends; delete config.ignorePresets; logger.trace({ config }, `Post-merge resolve config`); for (const [key, val] of Object.entries(config)) { const ignoredKeys = ["content", "onboardingConfig"]; if (isArray(val)) { config[key] = []; for (const element of val) if (isObject(element)) { const { config: presetConfig, visitedPresets: visited } = await resolveConfigPresets(element, baseConfig, ignorePresets, existingPresets, mergeInternalPresets); config[key].push(presetConfig); for (const mergedPreset of visited.merged) allVisitedPresets.merged.add(mergedPreset); for (const unmergedPreset of visited.unmerged) allVisitedPresets.unmerged.add(unmergedPreset); } else config[key].push(element); } else if (isObject(val) && !ignoredKeys.includes(key)) { logger.trace(`Resolving object "${key}"`); const { config: presetConfig, visitedPresets: visited } = await resolveConfigPresets(val, baseConfig, ignorePresets, existingPresets, mergeInternalPresets); config[key] = presetConfig; for (const mergedPreset of visited.merged) allVisitedPresets.merged.add(mergedPreset); for (const unmergedPreset of visited.unmerged) allVisitedPresets.unmerged.add(unmergedPreset); } } logger.trace({ config: inputConfig }, "Input config"); logger.trace({ config, visitedPresets: allVisitedPresets }, "Resolved config"); return { config, visitedPresets: { merged: Array.from(allVisitedPresets.merged), unmerged: Array.from(allVisitedPresets.unmerged) } }; } async function fetchPreset(preset, baseConfig, inputConfig, existingPresets) { try { return await getPreset(preset, baseConfig ?? inputConfig); } catch (err) { logger.debug({ preset, err }, "Preset fetch error"); if (err instanceof ExternalHostError) throw err; if (err.message === "rate-limit-exceeded") throw err; const error = new Error(CONFIG_VALIDATION); if (err.message === "dep not found") error.validationError = `Cannot find preset's package (${preset})`; else if (err.message === "preset renovate-config not found") error.validationError = `Preset package is missing a renovate-config entry (${preset})`; else if (err.message === "preset not found") error.validationError = `Preset name not found within published preset config (${preset})`; else if (err.message === "invalid preset") error.validationError = `Preset is invalid (${preset})`; else if (err.message === "prohibited sub-preset") error.validationError = `Sub-presets cannot be combined with a custom path (${preset})`; else if (err.message === "invalid preset JSON") error.validationError = `Preset is invalid JSON (${preset})`; else error.validationError = `Preset caused unexpected error (${preset})`; if (existingPresets.length) error.validationError += ". Note: this is a *nested* preset so please contact the preset author if you are unable to fix it yourself."; logger.info({ validationError: error.validationError }, "Throwing preset error"); throw error; } } function shouldResolvePreset(preset, existingPresets, ignorePresets) { if (existingPresets.includes(preset)) { logger.debug(`Already seen preset ${preset} in [${existingPresets.join(", ")}]`); return false; } if (ignorePresets.includes(preset)) { logger.debug(`Ignoring preset ${preset} in [${existingPresets.join(", ")}]`); return false; } return true; } //#endregion export { resolveConfigPresets }; //# sourceMappingURL=index.js.map