renovate 44.28.0 → 44.29.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config/options/index.js +1 -2
- package/dist/config/options/index.js.map +1 -1
- package/dist/config/presets/index.js +39 -12
- package/dist/config/presets/index.js.map +1 -1
- package/dist/config/presets/parse.js +64 -7
- package/dist/config/presets/parse.js.map +1 -1
- package/dist/config/presets/relative.js +66 -0
- package/dist/config/presets/relative.js.map +1 -0
- package/dist/config/presets/util.js +3 -1
- package/dist/config/presets/util.js.map +1 -1
- package/dist/config/validation.js +48 -4
- package/dist/config/validation.js.map +1 -1
- package/dist/global-config-option-defaults.generated.js +1 -1
- package/dist/global-config-option-defaults.generated.js.map +1 -1
- package/dist/logger/bunyan.js +2 -2
- package/dist/logger/bunyan.js.map +1 -1
- package/dist/logger/cmd-serializer.js +2 -1
- package/dist/logger/cmd-serializer.js.map +1 -1
- package/dist/modules/datasource/go/goproxy-parser.js +2 -2
- package/dist/modules/datasource/go/goproxy-parser.js.map +1 -1
- package/dist/modules/datasource/index.js +3 -3
- package/dist/modules/datasource/index.js.map +1 -1
- package/dist/modules/datasource/nuget/common.js +2 -1
- package/dist/modules/datasource/nuget/common.js.map +1 -1
- package/dist/modules/datasource/packagist/schema.js +2 -2
- package/dist/modules/datasource/packagist/schema.js.map +1 -1
- package/dist/modules/datasource/rpm/providers/common.js +3 -2
- package/dist/modules/datasource/rpm/providers/common.js.map +1 -1
- package/dist/modules/manager/ant/update.js +2 -1
- package/dist/modules/manager/ant/update.js.map +1 -1
- package/dist/modules/manager/bazel-module/parser/fragments.js +4 -3
- package/dist/modules/manager/bazel-module/parser/fragments.js.map +1 -1
- package/dist/modules/manager/bun/extract.js +2 -2
- package/dist/modules/manager/bun/extract.js.map +1 -1
- package/dist/modules/manager/circleci/extract.js +2 -1
- package/dist/modules/manager/circleci/extract.js.map +1 -1
- package/dist/modules/manager/deno/post.js +2 -2
- package/dist/modules/manager/deno/post.js.map +1 -1
- package/dist/modules/manager/fingerprint.generated.js +1 -1
- package/dist/modules/manager/fingerprint.generated.js.map +1 -1
- package/dist/modules/manager/helm-values/extract.js +2 -1
- package/dist/modules/manager/helm-values/extract.js.map +1 -1
- package/dist/modules/manager/helm-values/util.js +3 -2
- package/dist/modules/manager/helm-values/util.js.map +1 -1
- package/dist/modules/manager/npm/extract/common/dependency.js +1 -1
- package/dist/modules/manager/npm/extract/common/dependency.js.map +1 -1
- package/dist/modules/manager/npm/extract/post/monorepo.js +3 -3
- package/dist/modules/manager/npm/extract/post/monorepo.js.map +1 -1
- package/dist/modules/manager/npm/post-update/rules.js +2 -2
- package/dist/modules/manager/npm/post-update/rules.js.map +1 -1
- package/dist/modules/manager/osgi/extract.js +2 -2
- package/dist/modules/manager/osgi/extract.js.map +1 -1
- package/dist/modules/manager/pipenv/extract.js +2 -2
- package/dist/modules/manager/pipenv/extract.js.map +1 -1
- package/dist/modules/manager/pre-commit/parsing.js +3 -2
- package/dist/modules/manager/pre-commit/parsing.js.map +1 -1
- package/dist/modules/manager/proto/schema.js +2 -1
- package/dist/modules/manager/proto/schema.js.map +1 -1
- package/dist/modules/manager/renovate-config/extract.js +16 -2
- package/dist/modules/manager/renovate-config/extract.js.map +1 -1
- package/dist/modules/manager/woodpecker/extract.js +2 -2
- package/dist/modules/manager/woodpecker/extract.js.map +1 -1
- package/dist/modules/versioning/apk/index.js +2 -1
- package/dist/modules/versioning/apk/index.js.map +1 -1
- package/dist/modules/versioning/bazel-module/bzlmod-version.js +2 -1
- package/dist/modules/versioning/bazel-module/bzlmod-version.js.map +1 -1
- package/dist/modules/versioning/bazel-module/index.js +2 -1
- package/dist/modules/versioning/bazel-module/index.js.map +1 -1
- package/dist/modules/versioning/conan/common.js +2 -1
- package/dist/modules/versioning/conan/common.js.map +1 -1
- package/dist/modules/versioning/conan/range.js +5 -3
- package/dist/modules/versioning/conan/range.js.map +1 -1
- package/dist/modules/versioning/gradle/compare.js +1 -1
- package/dist/modules/versioning/gradle/compare.js.map +1 -1
- package/dist/modules/versioning/lambda-node/index.js +2 -1
- package/dist/modules/versioning/lambda-node/index.js.map +1 -1
- package/dist/modules/versioning/maven/compare.js +4 -3
- package/dist/modules/versioning/maven/compare.js.map +1 -1
- package/dist/modules/versioning/pep440/range.js +2 -1
- package/dist/modules/versioning/pep440/range.js.map +1 -1
- package/dist/modules/versioning/pvp/index.js +2 -1
- package/dist/modules/versioning/pvp/index.js.map +1 -1
- package/dist/modules/versioning/ruby/index.js +2 -1
- package/dist/modules/versioning/ruby/index.js.map +1 -1
- package/dist/util/cache/package/impl/file.js +2 -1
- package/dist/util/cache/package/impl/file.js.map +1 -1
- package/dist/util/cache/package/legacy.js +2 -1
- package/dist/util/cache/package/legacy.js.map +1 -1
- package/dist/util/date.js +2 -1
- package/dist/util/date.js.map +1 -1
- package/dist/util/exec/docker/index.js +2 -2
- package/dist/util/exec/docker/index.js.map +1 -1
- package/dist/util/exec/index.js +2 -2
- package/dist/util/exec/index.js.map +1 -1
- package/dist/util/exec/utils.js +2 -2
- package/dist/util/exec/utils.js.map +1 -1
- package/dist/util/fingerprint.js.map +1 -1
- package/dist/util/git/index.js +3 -3
- package/dist/util/git/index.js.map +1 -1
- package/dist/util/git/instrument.js +3 -2
- package/dist/util/git/instrument.js.map +1 -1
- package/dist/util/host-rules.js +1 -1
- package/dist/util/host-rules.js.map +1 -1
- package/dist/util/http/github.js +2 -2
- package/dist/util/http/github.js.map +1 -1
- package/dist/util/object.js.map +1 -1
- package/dist/util/result.js.map +1 -1
- package/dist/util/s3.js +2 -2
- package/dist/util/s3.js.map +1 -1
- package/dist/util/schema-utils/index.js.map +1 -1
- package/dist/util/timestamp.js +2 -1
- package/dist/util/timestamp.js.map +1 -1
- package/dist/workers/global/config/parse/index.js +2 -2
- package/dist/workers/global/config/parse/index.js.map +1 -1
- package/dist/workers/global/index.js +2 -2
- package/dist/workers/global/index.js.map +1 -1
- package/dist/workers/repository/update/branch/execute-post-upgrade-commands.js +2 -2
- package/dist/workers/repository/update/branch/execute-post-upgrade-commands.js.map +1 -1
- package/dist/workers/repository/update/pr/changelog/release-notes.js +2 -2
- package/dist/workers/repository/update/pr/changelog/release-notes.js.map +1 -1
- package/package.json +2 -2
- package/renovate-schema.json +2 -2
|
@@ -11,18 +11,40 @@ import { migrateConfig } from "../migration.js";
|
|
|
11
11
|
import { compile } from "../../util/template/index.js";
|
|
12
12
|
import { ExternalHostError } from "../../types/errors/external-host-error.js";
|
|
13
13
|
import { getPreset as getPreset$1, isInternal } from "./internal/index.js";
|
|
14
|
-
import { PRESET_DEP_NOT_FOUND } from "./util.js";
|
|
14
|
+
import { PRESET_DEP_NOT_FOUND, PRESET_RELATIVE_NO_PARENT } from "./util.js";
|
|
15
15
|
import { parsePreset } from "./parse.js";
|
|
16
|
+
import { canonicalizeRelativePresets } from "./relative.js";
|
|
16
17
|
import { isArray, isNullOrUndefined, isObject, isString } from "@sindresorhus/is";
|
|
17
18
|
//#region lib/config/presets/index.ts
|
|
18
|
-
const
|
|
19
|
-
forgejo:
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
19
|
+
const presetSources = {
|
|
20
|
+
forgejo: {
|
|
21
|
+
load: () => import("./forgejo/index.js"),
|
|
22
|
+
repoHosted: true
|
|
23
|
+
},
|
|
24
|
+
gitea: {
|
|
25
|
+
load: () => import("./gitea/index.js"),
|
|
26
|
+
repoHosted: true
|
|
27
|
+
},
|
|
28
|
+
github: {
|
|
29
|
+
load: () => import("./github/index.js"),
|
|
30
|
+
repoHosted: true
|
|
31
|
+
},
|
|
32
|
+
gitlab: {
|
|
33
|
+
load: () => import("./gitlab/index.js"),
|
|
34
|
+
repoHosted: true
|
|
35
|
+
},
|
|
36
|
+
http: {
|
|
37
|
+
load: () => import("./http/index.js"),
|
|
38
|
+
repoHosted: false
|
|
39
|
+
},
|
|
40
|
+
local: {
|
|
41
|
+
load: () => import("./local/index.js"),
|
|
42
|
+
repoHosted: true
|
|
43
|
+
},
|
|
44
|
+
npm: {
|
|
45
|
+
load: () => import("./npm/index.js"),
|
|
46
|
+
repoHosted: false
|
|
47
|
+
}
|
|
26
48
|
};
|
|
27
49
|
const presetCacheNamespace = "preset";
|
|
28
50
|
function replaceArgs(obj, argMapping) {
|
|
@@ -51,7 +73,9 @@ async function getPreset(preset, baseConfig) {
|
|
|
51
73
|
const newPreset = removedPresets[preset];
|
|
52
74
|
if (newPreset) return getPreset(newPreset, baseConfig);
|
|
53
75
|
if (newPreset === null) return {};
|
|
54
|
-
const
|
|
76
|
+
const parsedPreset = parsePreset(preset);
|
|
77
|
+
const { presetSource, repo, presetPath, presetName, tag, params, rawParams } = parsedPreset;
|
|
78
|
+
if (presetSource === "relative") throw new Error(PRESET_RELATIVE_NO_PARENT);
|
|
55
79
|
let presetConfig;
|
|
56
80
|
if (presetSource === "internal") presetConfig = getPreset$1({
|
|
57
81
|
repo,
|
|
@@ -65,7 +89,7 @@ async function getPreset(preset, baseConfig) {
|
|
|
65
89
|
if (packageCache) presetConfig = await packageCache.get(presetCacheNamespace, cacheKey);
|
|
66
90
|
else presetConfig = get(cacheKey);
|
|
67
91
|
if (isNullOrUndefined(presetConfig)) {
|
|
68
|
-
presetConfig = await (await
|
|
92
|
+
presetConfig = await (await presetSources[presetSource].load()).getPreset({
|
|
69
93
|
repo,
|
|
70
94
|
presetPath,
|
|
71
95
|
presetName,
|
|
@@ -89,7 +113,9 @@ async function getPreset(preset, baseConfig) {
|
|
|
89
113
|
const packageListKeys = ["description", "matchPackageNames"];
|
|
90
114
|
if (presetKeys.every((key) => packageListKeys.includes(key))) delete presetConfig.description;
|
|
91
115
|
const { migratedConfig } = migrateConfig(presetConfig);
|
|
92
|
-
|
|
116
|
+
const massagedConfig = massageConfig(migratedConfig);
|
|
117
|
+
if (presetSources[parsedPreset.presetSource]?.repoHosted) canonicalizeRelativePresets(massagedConfig, parsedPreset);
|
|
118
|
+
return massagedConfig;
|
|
93
119
|
}
|
|
94
120
|
/**
|
|
95
121
|
* @param [mergeInternalPresets=true] when resolving the config presets, whether to merge Renovate internal presets into the resulting configuration.
|
|
@@ -184,6 +210,7 @@ async function fetchPreset(preset, baseConfig, inputConfig, existingPresets) {
|
|
|
184
210
|
else if (err.message === "invalid preset") error.validationError = `Preset is invalid (${preset})`;
|
|
185
211
|
else if (err.message === "prohibited sub-preset") error.validationError = `Sub-presets cannot be combined with a custom path (${preset})`;
|
|
186
212
|
else if (err.message === "invalid preset JSON") error.validationError = `Preset is invalid JSON (${preset})`;
|
|
213
|
+
else if (err.message === "relative preset has no parent") error.validationError = `Relative preset reference cannot be resolved (${preset}). Relative presets can only be used within presets from a supported source, must stay inside their repository, and cannot be templated or used outside of a preset (for example in the repository config, inherited config, or globalExtends)`;
|
|
187
214
|
else error.validationError = `Preset caused unexpected error (${preset})`;
|
|
188
215
|
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.";
|
|
189
216
|
logger.info({ validationError: error.validationError }, "Throwing preset error");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["internal.getPreset","memCache.get","migration.migrateConfig","massage.massageConfig","template.compile","internal.isInternal"],"sources":["../../../lib/config/presets/index.ts"],"sourcesContent":["import {\n isArray,\n isNullOrUndefined,\n isObject,\n isString,\n} from '@sindresorhus/is';\nimport {\n CONFIG_VALIDATION,\n PLATFORM_RATE_LIMIT_EXCEEDED,\n} from '../../constants/error-messages.ts';\nimport { logger } from '../../logger/index.ts';\nimport { ExternalHostError } from '../../types/errors/external-host-error.ts';\nimport * as memCache from '../../util/cache/memory/index.ts';\nimport { clone } from '../../util/clone.ts';\nimport { regEx } from '../../util/regex.ts';\nimport * as template from '../../util/template/index.ts';\nimport { GlobalConfig } from '../global.ts';\nimport * as massage from '../massage.ts';\nimport * as migration from '../migration.ts';\nimport type { AllConfig, RenovateConfig } from '../types.ts';\nimport { mergeChildConfig } from '../utils.ts';\nimport { removedPresets } from './common.ts';\nimport * as internal from './internal/index.ts';\nimport { parsePreset } from './parse.ts';\nimport type { Preset, PresetApi } from './types.ts';\nimport {\n PRESET_DEP_NOT_FOUND,\n PRESET_INVALID,\n PRESET_INVALID_JSON,\n PRESET_NOT_FOUND,\n PRESET_PROHIBITED_SUBPRESET,\n PRESET_RENOVATE_CONFIG_NOT_FOUND,\n} from './util.ts';\n\nconst presetSourceLoaders: Record<string, () => Promise<PresetApi>> = {\n forgejo: () => import('./forgejo/index.ts'),\n gitea: () => import('./gitea/index.ts'),\n github: () => import('./github/index.ts'),\n gitlab: () => import('./gitlab/index.ts'),\n http: () => import('./http/index.ts'),\n local: () => import('./local/index.ts'),\n npm: () => import('./npm/index.ts'),\n};\n\nconst presetCacheNamespace = 'preset';\n\nexport function replaceArgs(\n obj: string,\n argMapping: Record<string, any>,\n): string;\nexport function replaceArgs(\n obj: string[],\n argMapping: Record<string, any>,\n): string[];\nexport function replaceArgs(\n obj: Record<string, any>,\n argMapping: Record<string, any>,\n): Record<string, any>;\nexport function replaceArgs(\n obj: Record<string, any>[],\n argMapping: Record<string, any>,\n): Record<string, any>[];\n\n/**\n * TODO: fix me #22198\n * @param obj\n * @param argMapping\n */\nexport function replaceArgs(obj: any, argMapping: Record<string, any>): any;\nexport function replaceArgs(\n obj: string | string[] | Record<string, any> | Record<string, any>[],\n argMapping: Record<string, any>,\n): any {\n if (isString(obj)) {\n let returnStr = obj;\n for (const [arg, argVal] of Object.entries(argMapping)) {\n const re = regEx(`{{${arg}}}`, 'g', false);\n returnStr = returnStr.replace(re, argVal);\n }\n return returnStr;\n }\n if (isArray(obj)) {\n const returnArray = [];\n for (const item of obj) {\n returnArray.push(replaceArgs(item, argMapping));\n }\n return returnArray;\n }\n if (isObject(obj)) {\n const returnObj: Record<string, any> = {};\n for (const [key, val] of Object.entries(obj)) {\n returnObj[key] = replaceArgs(val, argMapping);\n }\n return returnObj;\n }\n return obj;\n}\n\nexport async function getPreset(\n preset: string,\n baseConfig?: RenovateConfig,\n): Promise<RenovateConfig> {\n logger.trace(`getPreset(${preset})`);\n // Check if the preset has been removed or replaced\n const newPreset = removedPresets[preset];\n if (newPreset) {\n return getPreset(newPreset, baseConfig);\n }\n if (newPreset === null) {\n return {};\n }\n const { presetSource, repo, presetPath, presetName, tag, params, rawParams } =\n parsePreset(preset);\n\n let presetConfig: Preset | null | undefined;\n\n if (presetSource === 'internal') {\n presetConfig = internal.getPreset({\n repo,\n presetPath,\n presetName,\n tag,\n });\n } else {\n const cacheKey = `preset:${preset}`;\n const presetCachePersistence = GlobalConfig.get('presetCachePersistence');\n\n const packageCache = presetCachePersistence\n ? await import('../../util/cache/package/index.ts')\n : undefined;\n\n if (packageCache) {\n presetConfig = await packageCache.get(presetCacheNamespace, cacheKey);\n } else {\n presetConfig = memCache.get(cacheKey);\n }\n\n if (isNullOrUndefined(presetConfig)) {\n const source = await presetSourceLoaders[presetSource]();\n presetConfig = await source.getPreset({\n repo,\n presetPath,\n presetName,\n tag,\n });\n if (packageCache) {\n await packageCache.set(\n presetCacheNamespace,\n cacheKey,\n presetConfig,\n 15,\n );\n } else {\n memCache.set(cacheKey, presetConfig);\n }\n }\n }\n\n if (!presetConfig) {\n throw new Error(PRESET_DEP_NOT_FOUND);\n }\n logger.trace({ presetConfig }, `Found preset ${preset}`);\n if (params) {\n const argMapping: Record<string, string> = {};\n for (const [index, value] of params.entries()) {\n argMapping[`arg${index}`] = value;\n }\n if (rawParams) {\n argMapping.args = rawParams;\n }\n presetConfig = replaceArgs(presetConfig, argMapping);\n }\n logger.trace({ presetConfig }, `Applied params to preset ${preset}`);\n const presetKeys = Object.keys(presetConfig);\n if (\n presetKeys.length === 2 &&\n presetKeys.includes('description') &&\n presetKeys.includes('extends')\n ) {\n // preset is just a collection of other presets\n delete presetConfig.description;\n }\n const packageListKeys = ['description', 'matchPackageNames'];\n if (presetKeys.every((key) => packageListKeys.includes(key))) {\n delete presetConfig.description;\n }\n const { migratedConfig } = migration.migrateConfig(presetConfig);\n return massage.massageConfig(migratedConfig);\n}\n\nexport interface ResolveConfigPresetsResult {\n config: AllConfig;\n /** when resolving the given configuration, which internal/shared presets were discovered */\n visitedPresets: {\n /** which internal/shared presets were merged into the final config */\n merged: string[];\n /** which internal/shared presets were not merged into the final config */\n unmerged: string[];\n };\n}\n\n/**\n * @param [mergeInternalPresets=true] when resolving the config presets, whether to merge Renovate internal presets into the resulting configuration.\n * When set to `false`, this will resolve these internal presets (recursively), but not merge them.\n * This is primarily intended to be used by \"shallow config\" resolution (for logging purposes).\n */\nexport async function resolveConfigPresets(\n inputConfig: AllConfig,\n baseConfig?: RenovateConfig,\n _ignorePresets?: string[],\n existingPresets: string[] = [],\n mergeInternalPresets = true,\n): Promise<ResolveConfigPresetsResult> {\n const allVisitedPresets = {\n merged: new Set<string>(),\n unmerged: new Set<string>(),\n };\n\n let ignorePresets = clone(_ignorePresets);\n if (!ignorePresets || ignorePresets.length === 0) {\n ignorePresets = inputConfig.ignorePresets ?? [];\n }\n logger.trace(\n { config: inputConfig, existingPresets, mergeInternalPresets },\n 'resolveConfigPresets',\n );\n\n let config: AllConfig = {};\n // First, merge all the preset configs from left to right\n if (inputConfig.extends?.length) {\n // Compile templates\n inputConfig.extends = inputConfig.extends.map((tmpl) =>\n template.compile(tmpl, {}),\n );\n for (const preset of inputConfig.extends) {\n // don't attempt to merge any internal presets if we're not expecting to\n if (!mergeInternalPresets && internal.isInternal(preset)) {\n logger.once.trace(\n { ignoredPreset: preset, mergeInternalPresets },\n 'Not merging preset',\n );\n // ... but make sure we note that we haven't resolved it\n allVisitedPresets.unmerged.add(preset);\n continue;\n }\n\n if (shouldResolvePreset(preset, existingPresets, ignorePresets)) {\n logger.trace(`Resolving preset \"${preset}\"`);\n const fetchedPreset = await fetchPreset(\n preset,\n baseConfig,\n inputConfig,\n existingPresets,\n );\n const { config: presetConfig, visitedPresets } =\n await resolveConfigPresets(\n fetchedPreset,\n baseConfig ?? inputConfig,\n ignorePresets,\n existingPresets.concat([preset]),\n mergeInternalPresets,\n );\n if (inputConfig?.ignoreDeps?.length === 0) {\n delete presetConfig.description;\n }\n\n config = mergeChildConfig(config, presetConfig);\n allVisitedPresets.merged.add(preset);\n\n // then also make sure we've noted any nested presets we've merged\n for (const mergedPreset of visitedPresets.merged) {\n allVisitedPresets.merged.add(mergedPreset);\n }\n // ... or not merged\n for (const unmergedPreset of visitedPresets.unmerged) {\n allVisitedPresets.unmerged.add(unmergedPreset);\n }\n }\n }\n }\n logger.trace({ config }, `Post-preset resolve config`);\n // Now assign \"regular\" config on top\n config = mergeChildConfig(config, inputConfig);\n delete config.extends;\n delete config.ignorePresets;\n logger.trace({ config }, `Post-merge resolve config`);\n for (const [key, val] of Object.entries(config) as [\n keyof AllConfig,\n unknown,\n ][]) {\n const ignoredKeys = ['content', 'onboardingConfig'];\n if (isArray(val)) {\n // Resolve nested objects inside arrays\n config[key] = [] as never; // type can't be narrowed\n for (const element of val) {\n if (isObject(element)) {\n const { config: presetConfig, visitedPresets: visited } =\n await resolveConfigPresets(\n element,\n baseConfig,\n ignorePresets,\n existingPresets,\n mergeInternalPresets,\n );\n (config[key] as RenovateConfig[]).push(presetConfig);\n\n // then also make sure we've noted any nested presets we've merged\n for (const mergedPreset of visited.merged) {\n allVisitedPresets.merged.add(mergedPreset);\n }\n // ... or not merged\n for (const unmergedPreset of visited.unmerged) {\n allVisitedPresets.unmerged.add(unmergedPreset);\n }\n } else {\n (config[key] as unknown[]).push(element);\n }\n }\n } else if (isObject(val) && !ignoredKeys.includes(key)) {\n // Resolve nested objects\n logger.trace(`Resolving object \"${key}\"`);\n const { config: presetConfig, visitedPresets: visited } =\n await resolveConfigPresets(\n val,\n baseConfig,\n ignorePresets,\n existingPresets,\n mergeInternalPresets,\n );\n config[key] = presetConfig as never; // type can't be narrowed\n\n // then also make sure we've noted any nested presets we've merged\n for (const mergedPreset of visited.merged) {\n allVisitedPresets.merged.add(mergedPreset);\n }\n // ... or not merged\n for (const unmergedPreset of visited.unmerged) {\n allVisitedPresets.unmerged.add(unmergedPreset);\n }\n }\n }\n logger.trace({ config: inputConfig }, 'Input config');\n logger.trace(\n { config, visitedPresets: allVisitedPresets },\n 'Resolved config',\n );\n\n return {\n config,\n visitedPresets: {\n merged: Array.from(allVisitedPresets.merged),\n unmerged: Array.from(allVisitedPresets.unmerged),\n },\n };\n}\n\nasync function fetchPreset(\n preset: string,\n baseConfig: RenovateConfig | undefined,\n inputConfig: AllConfig,\n existingPresets: string[],\n): Promise<AllConfig> {\n try {\n return await getPreset(preset, baseConfig ?? inputConfig);\n } catch (err) {\n logger.debug({ preset, err }, 'Preset fetch error');\n if (err instanceof ExternalHostError) {\n throw err;\n }\n if (err.message === PLATFORM_RATE_LIMIT_EXCEEDED) {\n throw err;\n }\n const error = new Error(CONFIG_VALIDATION);\n if (err.message === PRESET_DEP_NOT_FOUND) {\n error.validationError = `Cannot find preset's package (${preset})`;\n } else if (err.message === PRESET_RENOVATE_CONFIG_NOT_FOUND) {\n error.validationError = `Preset package is missing a renovate-config entry (${preset})`;\n } else if (err.message === PRESET_NOT_FOUND) {\n error.validationError = `Preset name not found within published preset config (${preset})`;\n } else if (err.message === PRESET_INVALID) {\n error.validationError = `Preset is invalid (${preset})`;\n } else if (err.message === PRESET_PROHIBITED_SUBPRESET) {\n error.validationError = `Sub-presets cannot be combined with a custom path (${preset})`;\n } else if (err.message === PRESET_INVALID_JSON) {\n error.validationError = `Preset is invalid JSON (${preset})`;\n } else {\n error.validationError = `Preset caused unexpected error (${preset})`;\n }\n if (existingPresets.length) {\n error.validationError +=\n '. Note: this is a *nested* preset so please contact the preset author if you are unable to fix it yourself.';\n }\n logger.info(\n { validationError: error.validationError },\n 'Throwing preset error',\n );\n throw error;\n }\n}\n\nfunction shouldResolvePreset(\n preset: string,\n existingPresets: string[],\n ignorePresets: string[],\n): boolean {\n if (existingPresets.includes(preset)) {\n logger.debug(\n `Already seen preset ${preset} in [${existingPresets.join(', ')}]`,\n );\n return false;\n }\n if (ignorePresets.includes(preset)) {\n logger.debug(\n `Ignoring preset ${preset} in [${existingPresets.join(', ')}]`,\n );\n return false;\n }\n return true;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["internal.getPreset","memCache.get","migration.migrateConfig","massage.massageConfig","template.compile","internal.isInternal"],"sources":["../../../lib/config/presets/index.ts"],"sourcesContent":["import {\n isArray,\n isNullOrUndefined,\n isObject,\n isString,\n} from '@sindresorhus/is';\nimport {\n CONFIG_VALIDATION,\n PLATFORM_RATE_LIMIT_EXCEEDED,\n} from '../../constants/error-messages.ts';\nimport { logger } from '../../logger/index.ts';\nimport { ExternalHostError } from '../../types/errors/external-host-error.ts';\nimport * as memCache from '../../util/cache/memory/index.ts';\nimport { clone } from '../../util/clone.ts';\nimport { regEx } from '../../util/regex.ts';\nimport * as template from '../../util/template/index.ts';\nimport { GlobalConfig } from '../global.ts';\nimport * as massage from '../massage.ts';\nimport * as migration from '../migration.ts';\nimport type { AllConfig, RenovateConfig } from '../types.ts';\nimport { mergeChildConfig } from '../utils.ts';\nimport { removedPresets } from './common.ts';\nimport * as internal from './internal/index.ts';\nimport { parsePreset } from './parse.ts';\nimport { canonicalizeRelativePresets } from './relative.ts';\nimport type { Preset, PresetApi } from './types.ts';\nimport {\n PRESET_DEP_NOT_FOUND,\n PRESET_INVALID,\n PRESET_INVALID_JSON,\n PRESET_NOT_FOUND,\n PRESET_PROHIBITED_SUBPRESET,\n PRESET_RELATIVE_NO_PARENT,\n PRESET_RENOVATE_CONFIG_NOT_FOUND,\n} from './util.ts';\n\ninterface PresetSource {\n load: () => Promise<PresetApi>;\n\n /**\n * Whether presets from this source are hosted in a repository, which is what\n * allows them to reference other presets relatively.\n */\n repoHosted: boolean;\n}\n\nconst presetSources: Record<string, PresetSource> = {\n forgejo: { load: () => import('./forgejo/index.ts'), repoHosted: true },\n gitea: { load: () => import('./gitea/index.ts'), repoHosted: true },\n github: { load: () => import('./github/index.ts'), repoHosted: true },\n gitlab: { load: () => import('./gitlab/index.ts'), repoHosted: true },\n http: { load: () => import('./http/index.ts'), repoHosted: false },\n local: { load: () => import('./local/index.ts'), repoHosted: true },\n npm: { load: () => import('./npm/index.ts'), repoHosted: false },\n};\n\nconst presetCacheNamespace = 'preset';\n\nexport function replaceArgs(\n obj: string,\n argMapping: Record<string, any>,\n): string;\nexport function replaceArgs(\n obj: string[],\n argMapping: Record<string, any>,\n): string[];\nexport function replaceArgs(\n obj: Record<string, any>,\n argMapping: Record<string, any>,\n): Record<string, any>;\nexport function replaceArgs(\n obj: Record<string, any>[],\n argMapping: Record<string, any>,\n): Record<string, any>[];\n\n/**\n * TODO: fix me #22198\n * @param obj\n * @param argMapping\n */\nexport function replaceArgs(obj: any, argMapping: Record<string, any>): any;\nexport function replaceArgs(\n obj: string | string[] | Record<string, any> | Record<string, any>[],\n argMapping: Record<string, any>,\n): any {\n if (isString(obj)) {\n let returnStr = obj;\n for (const [arg, argVal] of Object.entries(argMapping)) {\n const re = regEx(`{{${arg}}}`, 'g', false);\n returnStr = returnStr.replace(re, argVal);\n }\n return returnStr;\n }\n if (isArray(obj)) {\n const returnArray = [];\n for (const item of obj) {\n returnArray.push(replaceArgs(item, argMapping));\n }\n return returnArray;\n }\n if (isObject(obj)) {\n const returnObj: Record<string, any> = {};\n for (const [key, val] of Object.entries(obj)) {\n returnObj[key] = replaceArgs(val, argMapping);\n }\n return returnObj;\n }\n return obj;\n}\n\nexport async function getPreset(\n preset: string,\n baseConfig?: RenovateConfig,\n): Promise<RenovateConfig> {\n logger.trace(`getPreset(${preset})`);\n // Check if the preset has been removed or replaced\n const newPreset = removedPresets[preset];\n if (newPreset) {\n return getPreset(newPreset, baseConfig);\n }\n if (newPreset === null) {\n return {};\n }\n const parsedPreset = parsePreset(preset);\n const { presetSource, repo, presetPath, presetName, tag, params, rawParams } =\n parsedPreset;\n\n if (presetSource === 'relative') {\n throw new Error(PRESET_RELATIVE_NO_PARENT);\n }\n\n let presetConfig: Preset | null | undefined;\n\n if (presetSource === 'internal') {\n presetConfig = internal.getPreset({\n repo,\n presetPath,\n presetName,\n tag,\n });\n } else {\n const cacheKey = `preset:${preset}`;\n const presetCachePersistence = GlobalConfig.get('presetCachePersistence');\n\n const packageCache = presetCachePersistence\n ? await import('../../util/cache/package/index.ts')\n : undefined;\n\n if (packageCache) {\n presetConfig = await packageCache.get(presetCacheNamespace, cacheKey);\n } else {\n presetConfig = memCache.get(cacheKey);\n }\n\n if (isNullOrUndefined(presetConfig)) {\n const source = await presetSources[presetSource].load();\n presetConfig = await source.getPreset({\n repo,\n presetPath,\n presetName,\n tag,\n });\n if (packageCache) {\n await packageCache.set(\n presetCacheNamespace,\n cacheKey,\n presetConfig,\n 15,\n );\n } else {\n memCache.set(cacheKey, presetConfig);\n }\n }\n }\n\n if (!presetConfig) {\n throw new Error(PRESET_DEP_NOT_FOUND);\n }\n logger.trace({ presetConfig }, `Found preset ${preset}`);\n if (params) {\n const argMapping: Record<string, string> = {};\n for (const [index, value] of params.entries()) {\n argMapping[`arg${index}`] = value;\n }\n if (rawParams) {\n argMapping.args = rawParams;\n }\n presetConfig = replaceArgs(presetConfig, argMapping);\n }\n logger.trace({ presetConfig }, `Applied params to preset ${preset}`);\n const presetKeys = Object.keys(presetConfig);\n if (\n presetKeys.length === 2 &&\n presetKeys.includes('description') &&\n presetKeys.includes('extends')\n ) {\n // preset is just a collection of other presets\n delete presetConfig.description;\n }\n const packageListKeys = ['description', 'matchPackageNames'];\n if (presetKeys.every((key) => packageListKeys.includes(key))) {\n delete presetConfig.description;\n }\n const { migratedConfig } = migration.migrateConfig(presetConfig);\n const massagedConfig = massage.massageConfig(migratedConfig);\n if (presetSources[parsedPreset.presetSource]?.repoHosted) {\n // only presets which are hosted in a repository can contain relative\n // references, in all other presets they are left as they are and fail\n // when they are resolved\n canonicalizeRelativePresets(massagedConfig, parsedPreset);\n }\n return massagedConfig;\n}\n\nexport interface ResolveConfigPresetsResult {\n config: AllConfig;\n /** when resolving the given configuration, which internal/shared presets were discovered */\n visitedPresets: {\n /** which internal/shared presets were merged into the final config */\n merged: string[];\n /** which internal/shared presets were not merged into the final config */\n unmerged: string[];\n };\n}\n\n/**\n * @param [mergeInternalPresets=true] when resolving the config presets, whether to merge Renovate internal presets into the resulting configuration.\n * When set to `false`, this will resolve these internal presets (recursively), but not merge them.\n * This is primarily intended to be used by \"shallow config\" resolution (for logging purposes).\n */\nexport async function resolveConfigPresets(\n inputConfig: AllConfig,\n baseConfig?: RenovateConfig,\n _ignorePresets?: string[],\n existingPresets: string[] = [],\n mergeInternalPresets = true,\n): Promise<ResolveConfigPresetsResult> {\n const allVisitedPresets = {\n merged: new Set<string>(),\n unmerged: new Set<string>(),\n };\n\n let ignorePresets = clone(_ignorePresets);\n if (!ignorePresets || ignorePresets.length === 0) {\n ignorePresets = inputConfig.ignorePresets ?? [];\n }\n logger.trace(\n { config: inputConfig, existingPresets, mergeInternalPresets },\n 'resolveConfigPresets',\n );\n\n let config: AllConfig = {};\n // First, merge all the preset configs from left to right\n if (inputConfig.extends?.length) {\n // Compile templates\n inputConfig.extends = inputConfig.extends.map((tmpl) =>\n template.compile(tmpl, {}),\n );\n for (const preset of inputConfig.extends) {\n // don't attempt to merge any internal presets if we're not expecting to\n if (!mergeInternalPresets && internal.isInternal(preset)) {\n logger.once.trace(\n { ignoredPreset: preset, mergeInternalPresets },\n 'Not merging preset',\n );\n // ... but make sure we note that we haven't resolved it\n allVisitedPresets.unmerged.add(preset);\n continue;\n }\n\n if (shouldResolvePreset(preset, existingPresets, ignorePresets)) {\n logger.trace(`Resolving preset \"${preset}\"`);\n const fetchedPreset = await fetchPreset(\n preset,\n baseConfig,\n inputConfig,\n existingPresets,\n );\n const { config: presetConfig, visitedPresets } =\n await resolveConfigPresets(\n fetchedPreset,\n baseConfig ?? inputConfig,\n ignorePresets,\n existingPresets.concat([preset]),\n mergeInternalPresets,\n );\n if (inputConfig?.ignoreDeps?.length === 0) {\n delete presetConfig.description;\n }\n\n config = mergeChildConfig(config, presetConfig);\n allVisitedPresets.merged.add(preset);\n\n // then also make sure we've noted any nested presets we've merged\n for (const mergedPreset of visitedPresets.merged) {\n allVisitedPresets.merged.add(mergedPreset);\n }\n // ... or not merged\n for (const unmergedPreset of visitedPresets.unmerged) {\n allVisitedPresets.unmerged.add(unmergedPreset);\n }\n }\n }\n }\n logger.trace({ config }, `Post-preset resolve config`);\n // Now assign \"regular\" config on top\n config = mergeChildConfig(config, inputConfig);\n delete config.extends;\n delete config.ignorePresets;\n logger.trace({ config }, `Post-merge resolve config`);\n for (const [key, val] of Object.entries(config) as [\n keyof AllConfig,\n unknown,\n ][]) {\n const ignoredKeys = ['content', 'onboardingConfig'];\n if (isArray(val)) {\n // Resolve nested objects inside arrays\n config[key] = [] as never; // type can't be narrowed\n for (const element of val) {\n if (isObject(element)) {\n const { config: presetConfig, visitedPresets: visited } =\n await resolveConfigPresets(\n element,\n baseConfig,\n ignorePresets,\n existingPresets,\n mergeInternalPresets,\n );\n (config[key] as RenovateConfig[]).push(presetConfig);\n\n // then also make sure we've noted any nested presets we've merged\n for (const mergedPreset of visited.merged) {\n allVisitedPresets.merged.add(mergedPreset);\n }\n // ... or not merged\n for (const unmergedPreset of visited.unmerged) {\n allVisitedPresets.unmerged.add(unmergedPreset);\n }\n } else {\n (config[key] as unknown[]).push(element);\n }\n }\n } else if (isObject(val) && !ignoredKeys.includes(key)) {\n // Resolve nested objects\n logger.trace(`Resolving object \"${key}\"`);\n const { config: presetConfig, visitedPresets: visited } =\n await resolveConfigPresets(\n val,\n baseConfig,\n ignorePresets,\n existingPresets,\n mergeInternalPresets,\n );\n config[key] = presetConfig as never; // type can't be narrowed\n\n // then also make sure we've noted any nested presets we've merged\n for (const mergedPreset of visited.merged) {\n allVisitedPresets.merged.add(mergedPreset);\n }\n // ... or not merged\n for (const unmergedPreset of visited.unmerged) {\n allVisitedPresets.unmerged.add(unmergedPreset);\n }\n }\n }\n logger.trace({ config: inputConfig }, 'Input config');\n logger.trace(\n { config, visitedPresets: allVisitedPresets },\n 'Resolved config',\n );\n\n return {\n config,\n visitedPresets: {\n merged: Array.from(allVisitedPresets.merged),\n unmerged: Array.from(allVisitedPresets.unmerged),\n },\n };\n}\n\nasync function fetchPreset(\n preset: string,\n baseConfig: RenovateConfig | undefined,\n inputConfig: AllConfig,\n existingPresets: string[],\n): Promise<AllConfig> {\n try {\n return await getPreset(preset, baseConfig ?? inputConfig);\n } catch (err) {\n logger.debug({ preset, err }, 'Preset fetch error');\n if (err instanceof ExternalHostError) {\n throw err;\n }\n if (err.message === PLATFORM_RATE_LIMIT_EXCEEDED) {\n throw err;\n }\n const error = new Error(CONFIG_VALIDATION);\n if (err.message === PRESET_DEP_NOT_FOUND) {\n error.validationError = `Cannot find preset's package (${preset})`;\n } else if (err.message === PRESET_RENOVATE_CONFIG_NOT_FOUND) {\n error.validationError = `Preset package is missing a renovate-config entry (${preset})`;\n } else if (err.message === PRESET_NOT_FOUND) {\n error.validationError = `Preset name not found within published preset config (${preset})`;\n } else if (err.message === PRESET_INVALID) {\n error.validationError = `Preset is invalid (${preset})`;\n } else if (err.message === PRESET_PROHIBITED_SUBPRESET) {\n error.validationError = `Sub-presets cannot be combined with a custom path (${preset})`;\n } else if (err.message === PRESET_INVALID_JSON) {\n error.validationError = `Preset is invalid JSON (${preset})`;\n } else if (err.message === PRESET_RELATIVE_NO_PARENT) {\n error.validationError = `Relative preset reference cannot be resolved (${preset}). Relative presets can only be used within presets from a supported source, must stay inside their repository, and cannot be templated or used outside of a preset (for example in the repository config, inherited config, or globalExtends)`;\n } else {\n error.validationError = `Preset caused unexpected error (${preset})`;\n }\n if (existingPresets.length) {\n error.validationError +=\n '. Note: this is a *nested* preset so please contact the preset author if you are unable to fix it yourself.';\n }\n logger.info(\n { validationError: error.validationError },\n 'Throwing preset error',\n );\n throw error;\n }\n}\n\nfunction shouldResolvePreset(\n preset: string,\n existingPresets: string[],\n ignorePresets: string[],\n): boolean {\n if (existingPresets.includes(preset)) {\n logger.debug(\n `Already seen preset ${preset} in [${existingPresets.join(', ')}]`,\n );\n return false;\n }\n if (ignorePresets.includes(preset)) {\n logger.debug(\n `Ignoring preset ${preset} in [${existingPresets.join(', ')}]`,\n );\n return false;\n }\n return true;\n}\n"],"mappings":"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"}
|
|
@@ -1,10 +1,51 @@
|
|
|
1
1
|
import { regEx } from "../../util/regex.js";
|
|
2
2
|
import { isHttpUrl } from "../../util/url.js";
|
|
3
3
|
import { PRESET_INVALID, PRESET_PROHIBITED_SUBPRESET } from "./util.js";
|
|
4
|
-
import { isNonEmptyString } from "@sindresorhus/is";
|
|
4
|
+
import { isNonEmptyString, isString } from "@sindresorhus/is";
|
|
5
5
|
//#region lib/config/presets/parse.ts
|
|
6
6
|
const nonScopedPresetWithSubdirRegex = regEx(/^(?<repo>~?[\w\-. /%]+?)\/\/(?:(?<presetPath>[\w\-./]+)\/)?(?<presetName>[\w\-.]+)(?:#(?<tag>[\w\-./]+?))?$/);
|
|
7
7
|
const gitPresetRegex = regEx(/^(?<repo>~?[\w\-. /%]+)(?::(?<presetName>[\w\-.+/]+))?(?:#(?<tag>[\w\-./]+?))?$/);
|
|
8
|
+
const relativePresetRegex = regEx(/^(?:\/|(?:\.\.?\/)+)[\w\-.]+(?:\/[\w\-.]+)*$/);
|
|
9
|
+
/**
|
|
10
|
+
* Returns true if the given `extends` entry is a relative preset reference,
|
|
11
|
+
* e.g. `./foo`, `../foo` or `/foo`.
|
|
12
|
+
*/
|
|
13
|
+
function isRelativePresetReference(input) {
|
|
14
|
+
return input.startsWith("./") || input.startsWith("../") || input.startsWith("/");
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Splits the trailing `(...)` parameter list off the given preset reference.
|
|
18
|
+
*
|
|
19
|
+
* The parameters are opaque, so they may contain any character and are split
|
|
20
|
+
* off before the reference itself is validated.
|
|
21
|
+
*/
|
|
22
|
+
function splitPresetParams(input) {
|
|
23
|
+
if (!input.includes("(")) return {
|
|
24
|
+
str: input,
|
|
25
|
+
params: void 0,
|
|
26
|
+
rawParams: void 0
|
|
27
|
+
};
|
|
28
|
+
const rawParams = input.slice(input.indexOf("(") + 1, -1);
|
|
29
|
+
return {
|
|
30
|
+
str: input.slice(0, input.indexOf("(")),
|
|
31
|
+
params: rawParams.split(",").map((elem) => elem.trim()),
|
|
32
|
+
rawParams
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Returns true if every parenthesis in the given preset parameters is closed in
|
|
37
|
+
* order, which allows Handlebars sub-expressions like `{{ lower (env.TEAM) }}`
|
|
38
|
+
* while still rejecting malformed parameter lists.
|
|
39
|
+
*/
|
|
40
|
+
function hasBalancedParens(rawParams) {
|
|
41
|
+
let depth = 0;
|
|
42
|
+
for (const char of rawParams) if (char === "(") depth += 1;
|
|
43
|
+
else if (char === ")") {
|
|
44
|
+
depth -= 1;
|
|
45
|
+
if (depth < 0) return false;
|
|
46
|
+
}
|
|
47
|
+
return depth === 0;
|
|
48
|
+
}
|
|
8
49
|
function parsePreset(input) {
|
|
9
50
|
let str = input;
|
|
10
51
|
let presetSource;
|
|
@@ -29,15 +70,31 @@ function parsePreset(input) {
|
|
|
29
70
|
} else if (str.startsWith("local>")) {
|
|
30
71
|
presetSource = "local";
|
|
31
72
|
str = str.substring(6);
|
|
32
|
-
} else if (
|
|
73
|
+
} else if (str.startsWith("npm>@")) {
|
|
74
|
+
presetSource = "npm";
|
|
75
|
+
str = str.substring(4);
|
|
76
|
+
} else if (isRelativePresetReference(str)) presetSource = "relative";
|
|
77
|
+
else if (isHttpUrl(str)) presetSource = "http";
|
|
33
78
|
else if (!str.startsWith("@") && !str.startsWith(":") && str.includes("/")) presetSource = "local";
|
|
34
79
|
str = str.replace(regEx(/^npm>/), "");
|
|
80
|
+
if (presetSource && presetSource !== "relative" && isRelativePresetReference(str)) throw new Error(PRESET_INVALID);
|
|
35
81
|
presetSource = presetSource ?? "npm";
|
|
36
|
-
if (
|
|
37
|
-
|
|
38
|
-
params
|
|
39
|
-
|
|
82
|
+
if (presetSource === "relative") {
|
|
83
|
+
if (str.includes("(") && !str.endsWith(")")) throw new Error(PRESET_INVALID);
|
|
84
|
+
({str, params, rawParams} = splitPresetParams(str));
|
|
85
|
+
if (isString(rawParams) && !hasBalancedParens(rawParams)) throw new Error(PRESET_INVALID);
|
|
86
|
+
if (!relativePresetRegex.test(str)) throw new Error(PRESET_INVALID);
|
|
87
|
+
const finalSegment = str.split("/").pop();
|
|
88
|
+
if (finalSegment === "." || finalSegment === "..") throw new Error(PRESET_INVALID);
|
|
89
|
+
return {
|
|
90
|
+
presetSource,
|
|
91
|
+
repo: "",
|
|
92
|
+
presetName: str,
|
|
93
|
+
params,
|
|
94
|
+
rawParams
|
|
95
|
+
};
|
|
40
96
|
}
|
|
97
|
+
({str, params, rawParams} = splitPresetParams(str));
|
|
41
98
|
if (presetSource === "http") return {
|
|
42
99
|
presetSource,
|
|
43
100
|
repo: str,
|
|
@@ -97,6 +154,6 @@ function parsePreset(input) {
|
|
|
97
154
|
};
|
|
98
155
|
}
|
|
99
156
|
//#endregion
|
|
100
|
-
export { parsePreset };
|
|
157
|
+
export { isRelativePresetReference, parsePreset };
|
|
101
158
|
|
|
102
159
|
//# sourceMappingURL=parse.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parse.js","names":[],"sources":["../../../lib/config/presets/parse.ts"],"sourcesContent":["import { isNonEmptyString } from '@sindresorhus/is';\nimport { regEx } from '../../util/regex.ts';\nimport { isHttpUrl } from '../../util/url.ts';\nimport type { ParsedPreset } from './types.ts';\nimport { PRESET_INVALID, PRESET_PROHIBITED_SUBPRESET } from './util.ts';\n\nconst nonScopedPresetWithSubdirRegex = regEx(\n /^(?<repo>~?[\\w\\-. /%]+?)\\/\\/(?:(?<presetPath>[\\w\\-./]+)\\/)?(?<presetName>[\\w\\-.]+)(?:#(?<tag>[\\w\\-./]+?))?$/,\n);\nconst gitPresetRegex = regEx(\n /^(?<repo>~?[\\w\\-. /%]+)(?::(?<presetName>[\\w\\-.+/]+))?(?:#(?<tag>[\\w\\-./]+?))?$/,\n);\n\nexport function parsePreset(input: string): ParsedPreset {\n let str = input;\n let presetSource: string | undefined;\n let presetPath: string | undefined;\n let repo: string;\n let presetName: string;\n let tag: string | undefined;\n let rawParams: string | undefined;\n let params: string[] | undefined;\n if (str.startsWith('github>')) {\n presetSource = 'github';\n str = str.substring('github>'.length);\n } else if (str.startsWith('gitlab>')) {\n presetSource = 'gitlab';\n str = str.substring('gitlab>'.length);\n } else if (str.startsWith('gitea>')) {\n presetSource = 'gitea';\n str = str.substring('gitea>'.length);\n } else if (str.startsWith('forgejo>')) {\n presetSource = 'forgejo';\n str = str.substring('forgejo>'.length);\n } else if (str.startsWith('local>')) {\n presetSource = 'local';\n str = str.substring('local>'.length);\n } else if (isHttpUrl(str)) {\n presetSource = 'http';\n } else if (\n !str.startsWith('@') &&\n !str.startsWith(':') &&\n str.includes('/')\n ) {\n presetSource = 'local';\n }\n str = str.replace(regEx(/^npm>/), '');\n presetSource = presetSource ?? 'npm';\n if (str.includes('(')) {\n rawParams =
|
|
1
|
+
{"version":3,"file":"parse.js","names":[],"sources":["../../../lib/config/presets/parse.ts"],"sourcesContent":["import { isNonEmptyString, isString } from '@sindresorhus/is';\nimport { regEx } from '../../util/regex.ts';\nimport { isHttpUrl } from '../../util/url.ts';\nimport type { ParsedPreset } from './types.ts';\nimport { PRESET_INVALID, PRESET_PROHIBITED_SUBPRESET } from './util.ts';\n\nconst nonScopedPresetWithSubdirRegex = regEx(\n /^(?<repo>~?[\\w\\-. /%]+?)\\/\\/(?:(?<presetPath>[\\w\\-./]+)\\/)?(?<presetName>[\\w\\-.]+)(?:#(?<tag>[\\w\\-./]+?))?$/,\n);\nconst gitPresetRegex = regEx(\n /^(?<repo>~?[\\w\\-. /%]+)(?::(?<presetName>[\\w\\-.+/]+))?(?:#(?<tag>[\\w\\-./]+?))?$/,\n);\nconst relativePresetRegex = regEx(\n /^(?:\\/|(?:\\.\\.?\\/)+)[\\w\\-.]+(?:\\/[\\w\\-.]+)*$/,\n);\n\n/**\n * Returns true if the given `extends` entry is a relative preset reference,\n * e.g. `./foo`, `../foo` or `/foo`.\n */\nexport function isRelativePresetReference(input: string): boolean {\n return (\n input.startsWith('./') || input.startsWith('../') || input.startsWith('/')\n );\n}\n\n/**\n * Splits the trailing `(...)` parameter list off the given preset reference.\n *\n * The parameters are opaque, so they may contain any character and are split\n * off before the reference itself is validated.\n */\nfunction splitPresetParams(input: string): {\n str: string;\n params: string[] | undefined;\n rawParams: string | undefined;\n} {\n if (!input.includes('(')) {\n return { str: input, params: undefined, rawParams: undefined };\n }\n\n const rawParams = input.slice(input.indexOf('(') + 1, -1);\n return {\n str: input.slice(0, input.indexOf('(')),\n params: rawParams.split(',').map((elem) => elem.trim()),\n rawParams,\n };\n}\n\n/**\n * Returns true if every parenthesis in the given preset parameters is closed in\n * order, which allows Handlebars sub-expressions like `{{ lower (env.TEAM) }}`\n * while still rejecting malformed parameter lists.\n */\nfunction hasBalancedParens(rawParams: string): boolean {\n let depth = 0;\n for (const char of rawParams) {\n if (char === '(') {\n depth += 1;\n } else if (char === ')') {\n depth -= 1;\n if (depth < 0) {\n return false;\n }\n }\n }\n return depth === 0;\n}\n\nexport function parsePreset(input: string): ParsedPreset {\n let str = input;\n let presetSource: string | undefined;\n let presetPath: string | undefined;\n let repo: string;\n let presetName: string;\n let tag: string | undefined;\n let rawParams: string | undefined;\n let params: string[] | undefined;\n if (str.startsWith('github>')) {\n presetSource = 'github';\n str = str.substring('github>'.length);\n } else if (str.startsWith('gitlab>')) {\n presetSource = 'gitlab';\n str = str.substring('gitlab>'.length);\n } else if (str.startsWith('gitea>')) {\n presetSource = 'gitea';\n str = str.substring('gitea>'.length);\n } else if (str.startsWith('forgejo>')) {\n presetSource = 'forgejo';\n str = str.substring('forgejo>'.length);\n } else if (str.startsWith('local>')) {\n presetSource = 'local';\n str = str.substring('local>'.length);\n } else if (str.startsWith('npm>@')) {\n // only scoped packages are unambiguous, all other `npm>` references are\n // handled by the legacy strip below to stay backwards compatible\n presetSource = 'npm';\n str = str.substring('npm>'.length);\n } else if (isRelativePresetReference(str)) {\n presetSource = 'relative';\n } else if (isHttpUrl(str)) {\n presetSource = 'http';\n } else if (\n !str.startsWith('@') &&\n !str.startsWith(':') &&\n str.includes('/')\n ) {\n presetSource = 'local';\n }\n str = str.replace(regEx(/^npm>/), '');\n if (\n presetSource &&\n presetSource !== 'relative' &&\n isRelativePresetReference(str)\n ) {\n // relative references must not carry a source prefix, because they always\n // inherit the source of the preset which references them\n throw new Error(PRESET_INVALID);\n }\n presetSource = presetSource ?? 'npm';\n if (presetSource === 'relative') {\n if (str.includes('(') && !str.endsWith(')')) {\n throw new Error(PRESET_INVALID);\n }\n ({ str, params, rawParams } = splitPresetParams(str));\n if (isString(rawParams) && !hasBalancedParens(rawParams)) {\n throw new Error(PRESET_INVALID);\n }\n if (!relativePresetRegex.test(str)) {\n throw new Error(PRESET_INVALID);\n }\n const finalSegment = str.split('/').pop();\n if (finalSegment === '.' || finalSegment === '..') {\n // references like `./.`, `./..` or `../a/..` name a directory instead of\n // a preset file\n throw new Error(PRESET_INVALID);\n }\n return { presetSource, repo: '', presetName: str, params, rawParams };\n }\n ({ str, params, rawParams } = splitPresetParams(str));\n if (presetSource === 'http') {\n return { presetSource, repo: str, presetName: '', params, rawParams };\n }\n const presetsPackages = [\n 'abandonments',\n 'compatibility',\n 'config',\n 'customManagers',\n 'default',\n 'docker',\n 'global',\n 'group',\n 'helpers',\n 'mergeConfidence',\n 'monorepo',\n 'npm',\n 'packages',\n 'preview',\n 'replacements',\n 'schedule',\n 'security',\n 'workarounds',\n ];\n if (\n presetsPackages.some((presetPackage) => str.startsWith(`${presetPackage}:`))\n ) {\n presetSource = 'internal';\n [repo, presetName] = str.split(':');\n } else if (str.startsWith(':')) {\n // default namespace\n presetSource = 'internal';\n repo = 'default';\n presetName = str.slice(1);\n } else if (str.startsWith('@')) {\n // scoped namespace\n [, repo] = regEx(/(@.*?)(:|$)/).exec(str)!;\n str = str.slice(repo.length);\n if (!repo.includes('/')) {\n repo += '/renovate-config';\n }\n if (str === '') {\n presetName = 'default';\n } else {\n presetName = str.slice(1);\n }\n } else if (str.includes('//')) {\n // non-scoped namespace with a subdirectory preset\n\n // Validation\n if (str.includes(':')) {\n throw new Error(PRESET_PROHIBITED_SUBPRESET);\n }\n if (!nonScopedPresetWithSubdirRegex.test(str)) {\n throw new Error(PRESET_INVALID);\n }\n ({ repo, presetPath, presetName, tag } =\n nonScopedPresetWithSubdirRegex.exec(str)!.groups!);\n } else {\n ({ repo, presetName, tag } = gitPresetRegex.exec(str)!.groups!);\n\n if (presetSource === 'npm' && !repo.startsWith('renovate-config-')) {\n repo = `renovate-config-${repo}`;\n }\n if (!isNonEmptyString(presetName)) {\n presetName = 'default';\n }\n }\n\n return {\n presetSource,\n presetPath,\n repo,\n presetName,\n tag,\n params,\n rawParams,\n };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { coerceString } from "../../util/string.js";
|
|
2
|
+
import { logger } from "../../logger/index.js";
|
|
3
|
+
import { PRESET_RELATIVE_OUTSIDE_REPO } from "./util.js";
|
|
4
|
+
import { isRelativePresetReference, parsePreset } from "./parse.js";
|
|
5
|
+
import { isArray, isPlainObject, isString } from "@sindresorhus/is";
|
|
6
|
+
import upath from "upath";
|
|
7
|
+
//#region lib/config/presets/relative.ts
|
|
8
|
+
/**
|
|
9
|
+
* Keys whose array entries may contain relative preset references.
|
|
10
|
+
*/
|
|
11
|
+
const presetReferenceKeys = ["extends", "ignorePresets"];
|
|
12
|
+
/**
|
|
13
|
+
* Converts a relative preset reference into an absolute preset string, by
|
|
14
|
+
* inheriting the source, repository and tag of the preset which references it.
|
|
15
|
+
*
|
|
16
|
+
* For example `./system/registries` found inside `github>some/repo#v2.0.0`
|
|
17
|
+
* resolves to `github>some/repo//system/registries#v2.0.0`.
|
|
18
|
+
*/
|
|
19
|
+
function resolveRelativePreset(input, parent) {
|
|
20
|
+
const parsed = parsePreset(input);
|
|
21
|
+
let resolved;
|
|
22
|
+
if (parsed.presetName.startsWith("/")) resolved = upath.normalize(parsed.presetName.slice(1));
|
|
23
|
+
else resolved = upath.normalize(upath.join(coerceString(parent.presetPath), parsed.presetName));
|
|
24
|
+
if (resolved === ".." || resolved.startsWith("../")) throw new Error(PRESET_RELATIVE_OUTSIDE_REPO);
|
|
25
|
+
const tag = parent.tag ? `#${parent.tag}` : "";
|
|
26
|
+
const params = isString(parsed.rawParams) ? `(${parsed.rawParams})` : "";
|
|
27
|
+
if (resolved === "default") return `${parent.presetSource}>${parent.repo}${tag}${params}`;
|
|
28
|
+
return `${parent.presetSource}>${parent.repo}//${resolved}${tag}${params}`;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Rewrites every relative preset reference found in any `extends` or
|
|
32
|
+
* `ignorePresets` array of the given value into an absolute preset string.
|
|
33
|
+
* The value is mutated in place.
|
|
34
|
+
*/
|
|
35
|
+
function canonicalizeRelativePresets(value, parent) {
|
|
36
|
+
if (isArray(value)) {
|
|
37
|
+
for (const element of value) canonicalizeRelativePresets(element, parent);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
if (!isPlainObject(value)) return;
|
|
41
|
+
for (const [key, val] of Object.entries(value)) {
|
|
42
|
+
if (presetReferenceKeys.includes(key) && isArray(val)) {
|
|
43
|
+
value[key] = val.map((entry) => rewritePresetEntry(entry, parent));
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
canonicalizeRelativePresets(val, parent);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function rewritePresetEntry(entry, parent) {
|
|
50
|
+
if (!isString(entry) || !isRelativePresetReference(entry)) return entry;
|
|
51
|
+
if ((entry.includes("(") ? entry.slice(0, entry.indexOf("(")) : entry).includes("{{")) return entry;
|
|
52
|
+
try {
|
|
53
|
+
return resolveRelativePreset(entry, parent);
|
|
54
|
+
} catch (err) {
|
|
55
|
+
logger.warn({
|
|
56
|
+
preset: entry,
|
|
57
|
+
parentPreset: parent,
|
|
58
|
+
err
|
|
59
|
+
}, "Could not resolve relative preset reference");
|
|
60
|
+
return entry;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
//#endregion
|
|
64
|
+
export { canonicalizeRelativePresets };
|
|
65
|
+
|
|
66
|
+
//# sourceMappingURL=relative.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"relative.js","names":[],"sources":["../../../lib/config/presets/relative.ts"],"sourcesContent":["import { isArray, isPlainObject, isString } from '@sindresorhus/is';\nimport upath from 'upath';\nimport { logger } from '../../logger/index.ts';\nimport { coerceString } from '../../util/string.ts';\nimport { isRelativePresetReference, parsePreset } from './parse.ts';\nimport type { ParsedPreset } from './types.ts';\nimport { PRESET_RELATIVE_OUTSIDE_REPO } from './util.ts';\n\n/**\n * Keys whose array entries may contain relative preset references.\n */\nconst presetReferenceKeys = ['extends', 'ignorePresets'];\n\n/**\n * Converts a relative preset reference into an absolute preset string, by\n * inheriting the source, repository and tag of the preset which references it.\n *\n * For example `./system/registries` found inside `github>some/repo#v2.0.0`\n * resolves to `github>some/repo//system/registries#v2.0.0`.\n */\nfunction resolveRelativePreset(input: string, parent: ParsedPreset): string {\n const parsed = parsePreset(input);\n\n let resolved: string;\n if (parsed.presetName.startsWith('/')) {\n // relative to the root of the repository\n resolved = upath.normalize(parsed.presetName.slice(1));\n } else {\n // relative to the directory of the preset file which references it\n resolved = upath.normalize(\n upath.join(coerceString(parent.presetPath), parsed.presetName),\n );\n }\n\n if (resolved === '..' || resolved.startsWith('../')) {\n throw new Error(PRESET_RELATIVE_OUTSIDE_REPO);\n }\n\n const tag = parent.tag ? `#${parent.tag}` : '';\n const params = isString(parsed.rawParams) ? `(${parsed.rawParams})` : '';\n\n if (resolved === 'default') {\n // the default preset at the root of the repository is spelled without a\n // path, so emitting `//default` here would break deduplication against the\n // way consumers reference the very same preset\n return `${parent.presetSource}>${parent.repo}${tag}${params}`;\n }\n\n return `${parent.presetSource}>${parent.repo}//${resolved}${tag}${params}`;\n}\n\n/**\n * Rewrites every relative preset reference found in any `extends` or\n * `ignorePresets` array of the given value into an absolute preset string.\n * The value is mutated in place.\n */\nexport function canonicalizeRelativePresets(\n value: unknown,\n parent: ParsedPreset,\n): void {\n if (isArray(value)) {\n for (const element of value) {\n canonicalizeRelativePresets(element, parent);\n }\n return;\n }\n\n if (!isPlainObject(value)) {\n return;\n }\n\n for (const [key, val] of Object.entries(value)) {\n if (presetReferenceKeys.includes(key) && isArray(val)) {\n value[key] = val.map((entry) => rewritePresetEntry(entry, parent));\n continue;\n }\n\n canonicalizeRelativePresets(val, parent);\n }\n}\n\nfunction rewritePresetEntry(entry: unknown, parent: ParsedPreset): unknown {\n if (!isString(entry) || !isRelativePresetReference(entry)) {\n return entry;\n }\n\n // only the path may not be templated, because it has to be resolved here,\n // while the parameters are compiled later on\n const pathPortion = entry.includes('(')\n ? entry.slice(0, entry.indexOf('('))\n : entry;\n if (pathPortion.includes('{{')) {\n return entry;\n }\n\n try {\n return resolveRelativePreset(entry, parent);\n } catch (err) {\n // the unchanged entry is reported when it is resolved as a preset, which\n // allows consumers to neutralize it using `ignorePresets`\n logger.warn(\n { preset: entry, parentPreset: parent, err },\n 'Could not resolve relative preset reference',\n );\n return entry;\n }\n}\n"],"mappings":";;;;;;;;;;AAWA,MAAM,sBAAsB,CAAC,WAAW,eAAe;;;;;;;;AASvD,SAAS,sBAAsB,OAAe,QAA8B;CAC1E,MAAM,SAAS,YAAY,KAAK;CAEhC,IAAI;CACJ,IAAI,OAAO,WAAW,WAAW,GAAG,GAElC,WAAW,MAAM,UAAU,OAAO,WAAW,MAAM,CAAC,CAAC;MAGrD,WAAW,MAAM,UACf,MAAM,KAAK,aAAa,OAAO,UAAU,GAAG,OAAO,UAAU,CAC/D;CAGF,IAAI,aAAa,QAAQ,SAAS,WAAW,KAAK,GAChD,MAAM,IAAI,MAAM,4BAA4B;CAG9C,MAAM,MAAM,OAAO,MAAM,IAAI,OAAO,QAAQ;CAC5C,MAAM,SAAS,SAAS,OAAO,SAAS,IAAI,IAAI,OAAO,UAAU,KAAK;CAEtE,IAAI,aAAa,WAIf,OAAO,GAAG,OAAO,aAAa,GAAG,OAAO,OAAO,MAAM;CAGvD,OAAO,GAAG,OAAO,aAAa,GAAG,OAAO,KAAK,IAAI,WAAW,MAAM;AACpE;;;;;;AAOA,SAAgB,4BACd,OACA,QACM;CACN,IAAI,QAAQ,KAAK,GAAG;EAClB,KAAK,MAAM,WAAW,OACpB,4BAA4B,SAAS,MAAM;EAE7C;CACF;CAEA,IAAI,CAAC,cAAc,KAAK,GACtB;CAGF,KAAK,MAAM,CAAC,KAAK,QAAQ,OAAO,QAAQ,KAAK,GAAG;EAC9C,IAAI,oBAAoB,SAAS,GAAG,KAAK,QAAQ,GAAG,GAAG;GACrD,MAAM,OAAO,IAAI,KAAK,UAAU,mBAAmB,OAAO,MAAM,CAAC;GACjE;EACF;EAEA,4BAA4B,KAAK,MAAM;CACzC;AACF;AAEA,SAAS,mBAAmB,OAAgB,QAA+B;CACzE,IAAI,CAAC,SAAS,KAAK,KAAK,CAAC,0BAA0B,KAAK,GACtD,OAAO;CAQT,KAHoB,MAAM,SAAS,GAAG,IAClC,MAAM,MAAM,GAAG,MAAM,QAAQ,GAAG,CAAC,IACjC,MAAA,CACY,SAAS,IAAI,GAC3B,OAAO;CAGT,IAAI;EACF,OAAO,sBAAsB,OAAO,MAAM;CAC5C,SAAS,KAAK;EAGZ,OAAO,KACL;GAAE,QAAQ;GAAO,cAAc;GAAQ;EAAI,GAC3C,6CACF;EACA,OAAO;CACT;AACF"}
|
|
@@ -8,6 +8,8 @@ const PRESET_INVALID = "invalid preset";
|
|
|
8
8
|
const PRESET_INVALID_JSON = "invalid preset JSON";
|
|
9
9
|
const PRESET_NOT_FOUND = "preset not found";
|
|
10
10
|
const PRESET_PROHIBITED_SUBPRESET = "prohibited sub-preset";
|
|
11
|
+
const PRESET_RELATIVE_NO_PARENT = "relative preset has no parent";
|
|
12
|
+
const PRESET_RELATIVE_OUTSIDE_REPO = "relative preset outside repo";
|
|
11
13
|
const PRESET_RENOVATE_CONFIG_NOT_FOUND = "preset renovate-config not found";
|
|
12
14
|
async function fetchPreset({ repo, filePreset, presetPath, endpoint: _endpoint, tag, fetch }) {
|
|
13
15
|
const endpoint = ensureTrailingSlash(_endpoint);
|
|
@@ -52,6 +54,6 @@ function parsePreset(content, fileName) {
|
|
|
52
54
|
}
|
|
53
55
|
}
|
|
54
56
|
//#endregion
|
|
55
|
-
export { PRESET_DEP_NOT_FOUND, PRESET_INVALID, PRESET_INVALID_JSON, PRESET_NOT_FOUND, PRESET_PROHIBITED_SUBPRESET, PRESET_RENOVATE_CONFIG_NOT_FOUND, fetchPreset, parsePreset };
|
|
57
|
+
export { PRESET_DEP_NOT_FOUND, PRESET_INVALID, PRESET_INVALID_JSON, PRESET_NOT_FOUND, PRESET_PROHIBITED_SUBPRESET, PRESET_RELATIVE_NO_PARENT, PRESET_RELATIVE_OUTSIDE_REPO, PRESET_RENOVATE_CONFIG_NOT_FOUND, fetchPreset, parsePreset };
|
|
56
58
|
|
|
57
59
|
//# sourceMappingURL=util.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"util.js","names":[],"sources":["../../../lib/config/presets/util.ts"],"sourcesContent":["import { logger } from '../../logger/index.ts';\nimport type { Nullish } from '../../types/index.ts';\nimport { parseJson } from '../../util/common.ts';\nimport { regEx } from '../../util/regex.ts';\nimport { ensureTrailingSlash } from '../../util/url.ts';\nimport type { FetchPresetConfig, Preset } from './types.ts';\n\nexport const PRESET_DEP_NOT_FOUND = 'dep not found';\nexport const PRESET_INVALID = 'invalid preset';\nexport const PRESET_INVALID_JSON = 'invalid preset JSON';\nexport const PRESET_NOT_FOUND = 'preset not found';\nexport const PRESET_PROHIBITED_SUBPRESET = 'prohibited sub-preset';\nexport const PRESET_RENOVATE_CONFIG_NOT_FOUND =\n 'preset renovate-config not found';\n\nexport async function fetchPreset({\n repo,\n filePreset,\n presetPath,\n endpoint: _endpoint,\n tag,\n fetch,\n}: FetchPresetConfig): Promise<Nullish<Preset>> {\n // TODO: fix me, can be undefiend #22198\n // oxlint-disable-next-line typescript/no-unnecessary-type-assertion\n const endpoint = ensureTrailingSlash(_endpoint!);\n const [fileName, presetName, subPresetName] = filePreset.split('/');\n const pathPrefix = presetPath ? `${presetPath}/` : '';\n function buildFilePath(name: string): string {\n return `${pathPrefix}${name}`;\n }\n let jsonContent: any;\n if (fileName === 'default') {\n try {\n jsonContent = await fetch(\n repo,\n buildFilePath('default.json'),\n endpoint,\n tag,\n );\n } catch (err) {\n if (err.message !== PRESET_DEP_NOT_FOUND) {\n throw err;\n }\n jsonContent = await fetch(\n repo,\n buildFilePath('renovate.json'),\n endpoint,\n tag,\n );\n logger.warn(\n {\n repo,\n filePreset,\n presetPath,\n endpoint,\n tag,\n },\n 'Fallback to renovate.json file as a preset is deprecated, please use a default.json file instead.',\n );\n }\n } else {\n jsonContent = await fetch(\n repo,\n buildFilePath(\n regEx(/\\.json[5c]?$/).test(fileName) ? fileName : `${fileName}.json`,\n ),\n endpoint,\n tag,\n );\n }\n\n if (!jsonContent) {\n throw new Error(PRESET_DEP_NOT_FOUND);\n }\n if (presetName) {\n const preset = jsonContent[presetName];\n if (!preset) {\n throw new Error(PRESET_NOT_FOUND);\n }\n if (subPresetName) {\n const subPreset = preset[subPresetName];\n if (!subPreset) {\n throw new Error(PRESET_NOT_FOUND);\n }\n return subPreset;\n }\n return preset;\n }\n return jsonContent;\n}\n\nexport function parsePreset(\n content: Nullish<string>,\n fileName: string,\n): Nullish<Preset> {\n try {\n return parseJson(content, fileName) as Nullish<Preset>;\n } catch {\n throw new Error(PRESET_INVALID_JSON);\n }\n}\n"],"mappings":";;;;;AAOA,MAAa,uBAAuB;AACpC,MAAa,iBAAiB;AAC9B,MAAa,sBAAsB;AACnC,MAAa,mBAAmB;AAChC,MAAa,8BAA8B;AAC3C,MAAa,mCACX;AAEF,eAAsB,YAAY,EAChC,MACA,YACA,YACA,UAAU,WACV,KACA,SAC8C;CAG9C,MAAM,WAAW,oBAAoB,SAAU;CAC/C,MAAM,CAAC,UAAU,YAAY,iBAAiB,WAAW,MAAM,GAAG;CAClE,MAAM,aAAa,aAAa,GAAG,WAAW,KAAK;CACnD,SAAS,cAAc,MAAsB;EAC3C,OAAO,GAAG,aAAa;CACzB;CACA,IAAI;CACJ,IAAI,aAAa,WACf,IAAI;EACF,cAAc,MAAM,MAClB,MACA,cAAc,cAAc,GAC5B,UACA,GACF;CACF,SAAS,KAAK;EACZ,IAAI,IAAI,YAAA,iBACN,MAAM;EAER,cAAc,MAAM,MAClB,MACA,cAAc,eAAe,GAC7B,UACA,GACF;EACA,OAAO,KACL;GACE;GACA;GACA;GACA;GACA;EACF,GACA,mGACF;CACF;MAEA,cAAc,MAAM,MAClB,MACA,cACE,MAAM,cAAc,CAAC,CAAC,KAAK,QAAQ,IAAI,WAAW,GAAG,SAAS,MAChE,GACA,UACA,GACF;CAGF,IAAI,CAAC,aACH,MAAM,IAAI,MAAM,oBAAoB;CAEtC,IAAI,YAAY;EACd,MAAM,SAAS,YAAY;EAC3B,IAAI,CAAC,QACH,MAAM,IAAI,MAAM,gBAAgB;EAElC,IAAI,eAAe;GACjB,MAAM,YAAY,OAAO;GACzB,IAAI,CAAC,WACH,MAAM,IAAI,MAAM,gBAAgB;GAElC,OAAO;EACT;EACA,OAAO;CACT;CACA,OAAO;AACT;AAEA,SAAgB,YACd,SACA,UACiB;CACjB,IAAI;EACF,OAAO,UAAU,SAAS,QAAQ;CACpC,QAAQ;EACN,MAAM,IAAI,MAAM,mBAAmB;CACrC;AACF"}
|
|
1
|
+
{"version":3,"file":"util.js","names":[],"sources":["../../../lib/config/presets/util.ts"],"sourcesContent":["import { logger } from '../../logger/index.ts';\nimport type { Nullish } from '../../types/index.ts';\nimport { parseJson } from '../../util/common.ts';\nimport { regEx } from '../../util/regex.ts';\nimport { ensureTrailingSlash } from '../../util/url.ts';\nimport type { FetchPresetConfig, Preset } from './types.ts';\n\nexport const PRESET_DEP_NOT_FOUND = 'dep not found';\nexport const PRESET_INVALID = 'invalid preset';\nexport const PRESET_INVALID_JSON = 'invalid preset JSON';\nexport const PRESET_NOT_FOUND = 'preset not found';\nexport const PRESET_PROHIBITED_SUBPRESET = 'prohibited sub-preset';\nexport const PRESET_RELATIVE_NO_PARENT = 'relative preset has no parent';\nexport const PRESET_RELATIVE_OUTSIDE_REPO = 'relative preset outside repo';\nexport const PRESET_RENOVATE_CONFIG_NOT_FOUND =\n 'preset renovate-config not found';\n\nexport async function fetchPreset({\n repo,\n filePreset,\n presetPath,\n endpoint: _endpoint,\n tag,\n fetch,\n}: FetchPresetConfig): Promise<Nullish<Preset>> {\n // TODO: fix me, can be undefiend #22198\n // oxlint-disable-next-line typescript/no-unnecessary-type-assertion\n const endpoint = ensureTrailingSlash(_endpoint!);\n const [fileName, presetName, subPresetName] = filePreset.split('/');\n const pathPrefix = presetPath ? `${presetPath}/` : '';\n function buildFilePath(name: string): string {\n return `${pathPrefix}${name}`;\n }\n let jsonContent: any;\n if (fileName === 'default') {\n try {\n jsonContent = await fetch(\n repo,\n buildFilePath('default.json'),\n endpoint,\n tag,\n );\n } catch (err) {\n if (err.message !== PRESET_DEP_NOT_FOUND) {\n throw err;\n }\n jsonContent = await fetch(\n repo,\n buildFilePath('renovate.json'),\n endpoint,\n tag,\n );\n logger.warn(\n {\n repo,\n filePreset,\n presetPath,\n endpoint,\n tag,\n },\n 'Fallback to renovate.json file as a preset is deprecated, please use a default.json file instead.',\n );\n }\n } else {\n jsonContent = await fetch(\n repo,\n buildFilePath(\n regEx(/\\.json[5c]?$/).test(fileName) ? fileName : `${fileName}.json`,\n ),\n endpoint,\n tag,\n );\n }\n\n if (!jsonContent) {\n throw new Error(PRESET_DEP_NOT_FOUND);\n }\n if (presetName) {\n const preset = jsonContent[presetName];\n if (!preset) {\n throw new Error(PRESET_NOT_FOUND);\n }\n if (subPresetName) {\n const subPreset = preset[subPresetName];\n if (!subPreset) {\n throw new Error(PRESET_NOT_FOUND);\n }\n return subPreset;\n }\n return preset;\n }\n return jsonContent;\n}\n\nexport function parsePreset(\n content: Nullish<string>,\n fileName: string,\n): Nullish<Preset> {\n try {\n return parseJson(content, fileName) as Nullish<Preset>;\n } catch {\n throw new Error(PRESET_INVALID_JSON);\n }\n}\n"],"mappings":";;;;;AAOA,MAAa,uBAAuB;AACpC,MAAa,iBAAiB;AAC9B,MAAa,sBAAsB;AACnC,MAAa,mBAAmB;AAChC,MAAa,8BAA8B;AAC3C,MAAa,4BAA4B;AACzC,MAAa,+BAA+B;AAC5C,MAAa,mCACX;AAEF,eAAsB,YAAY,EAChC,MACA,YACA,YACA,UAAU,WACV,KACA,SAC8C;CAG9C,MAAM,WAAW,oBAAoB,SAAU;CAC/C,MAAM,CAAC,UAAU,YAAY,iBAAiB,WAAW,MAAM,GAAG;CAClE,MAAM,aAAa,aAAa,GAAG,WAAW,KAAK;CACnD,SAAS,cAAc,MAAsB;EAC3C,OAAO,GAAG,aAAa;CACzB;CACA,IAAI;CACJ,IAAI,aAAa,WACf,IAAI;EACF,cAAc,MAAM,MAClB,MACA,cAAc,cAAc,GAC5B,UACA,GACF;CACF,SAAS,KAAK;EACZ,IAAI,IAAI,YAAA,iBACN,MAAM;EAER,cAAc,MAAM,MAClB,MACA,cAAc,eAAe,GAC7B,UACA,GACF;EACA,OAAO,KACL;GACE;GACA;GACA;GACA;GACA;EACF,GACA,mGACF;CACF;MAEA,cAAc,MAAM,MAClB,MACA,cACE,MAAM,cAAc,CAAC,CAAC,KAAK,QAAQ,IAAI,WAAW,GAAG,SAAS,MAChE,GACA,UACA,GACF;CAGF,IAAI,CAAC,aACH,MAAM,IAAI,MAAM,oBAAoB;CAEtC,IAAI,YAAY;EACd,MAAM,SAAS,YAAY;EAC3B,IAAI,CAAC,QACH,MAAM,IAAI,MAAM,gBAAgB;EAElC,IAAI,eAAe;GACjB,MAAM,YAAY,OAAO;GACzB,IAAI,CAAC,WACH,MAAM,IAAI,MAAM,gBAAgB;GAElC,OAAO;EACT;EACA,OAAO;CACT;CACA,OAAO;AACT;AAEA,SAAgB,YACd,SACA,UACiB;CACjB,IAAI;EACF,OAAO,UAAU,SAAS,QAAQ;CACpC,QAAQ;EACN,MAAM,IAAI,MAAM,mBAAmB;CACrC;AACF"}
|
|
@@ -3,6 +3,7 @@ import { getConfigFileNames } from "./app-strings.js";
|
|
|
3
3
|
import { GlobalConfig } from "./global.js";
|
|
4
4
|
import { anyMatchRegexOrGlobList, getRegexPredicate, isRegexMatch, matchRegexOrGlobList } from "../util/string-match.js";
|
|
5
5
|
import { logger } from "../logger/index.js";
|
|
6
|
+
import { clone } from "../util/clone.js";
|
|
6
7
|
import { AllManagersListLiteral, CustomManagersListLiteral } from "../manager-list.generated.js";
|
|
7
8
|
import { AllVersioningsListLiteral } from "../versioning-list.generated.js";
|
|
8
9
|
import { supportedDatasources } from "./presets/internal/merge-confidence.preset.js";
|
|
@@ -19,7 +20,7 @@ import { isConstraintName, isToolName } from "../util/exec/types.js";
|
|
|
19
20
|
import { isValidCommitTrailer } from "../util/git/commit-trailers.js";
|
|
20
21
|
import { getExpression } from "../util/jsonata.js";
|
|
21
22
|
import { hasValidSchedule, hasValidTimezone } from "../workers/repository/update/branch/schedule.js";
|
|
22
|
-
import { parsePreset } from "./presets/parse.js";
|
|
23
|
+
import { isRelativePresetReference, parsePreset } from "./presets/parse.js";
|
|
23
24
|
import { resolveConfigPresets } from "./presets/index.js";
|
|
24
25
|
import { check } from "./validation-helpers/match-base-branches.js";
|
|
25
26
|
import { check as check$1 } from "./validation-helpers/regex-glob-matchers.js";
|
|
@@ -104,6 +105,42 @@ function initOptions() {
|
|
|
104
105
|
}
|
|
105
106
|
optionsInitialized = true;
|
|
106
107
|
}
|
|
108
|
+
/**
|
|
109
|
+
* Removes every relative preset reference from a deep copy of the given
|
|
110
|
+
* `packageRules` entry, at any nesting depth.
|
|
111
|
+
*
|
|
112
|
+
* Relative references are only resolvable while the preset which contains them
|
|
113
|
+
* is fetched, so they must not be passed to `resolveConfigPresets()` during
|
|
114
|
+
* validation. They are still syntax checked by the `extends` validation.
|
|
115
|
+
*/
|
|
116
|
+
function stripRelativePresets(packageRule) {
|
|
117
|
+
const rule = clone(packageRule);
|
|
118
|
+
return {
|
|
119
|
+
rule,
|
|
120
|
+
hasRelativePresets: stripRelativePresetsFromValue(rule)
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
function stripRelativePresetsFromValue(value) {
|
|
124
|
+
if (isArray(value)) {
|
|
125
|
+
let stripped = false;
|
|
126
|
+
for (const element of value) stripped = stripRelativePresetsFromValue(element) || stripped;
|
|
127
|
+
return stripped;
|
|
128
|
+
}
|
|
129
|
+
if (!isPlainObject(value)) return false;
|
|
130
|
+
let stripped = false;
|
|
131
|
+
for (const [key, val] of Object.entries(value)) {
|
|
132
|
+
if (key === "extends" && isArray(val)) {
|
|
133
|
+
const remaining = val.filter((preset) => !(isString(preset) && isRelativePresetReference(preset)));
|
|
134
|
+
if (remaining.length !== val.length) {
|
|
135
|
+
value[key] = remaining;
|
|
136
|
+
stripped = true;
|
|
137
|
+
}
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
stripped = stripRelativePresetsFromValue(val) || stripped;
|
|
141
|
+
}
|
|
142
|
+
return stripped;
|
|
143
|
+
}
|
|
107
144
|
async function validateConfig(configType, config, isPreset, parentPath) {
|
|
108
145
|
return instrument(`validateConfig(${configType}, ${JSON.stringify(parentPath)})`, async () => {
|
|
109
146
|
initOptions();
|
|
@@ -275,7 +312,8 @@ async function validateConfig(configType, config, isPreset, parentPath) {
|
|
|
275
312
|
"matchJsonata"
|
|
276
313
|
];
|
|
277
314
|
if (key === "packageRules") for (const [subIndex, packageRule] of val.entries()) if (isObject(packageRule)) {
|
|
278
|
-
const {
|
|
315
|
+
const { rule, hasRelativePresets } = stripRelativePresets(packageRule);
|
|
316
|
+
const { config: resolved } = await resolveConfigPresets(rule, config);
|
|
279
317
|
const resolvedRule = migrateConfig({ packageRules: [resolved] }).migratedConfig.packageRules[0];
|
|
280
318
|
warnings.push(...check({
|
|
281
319
|
resolvedRule,
|
|
@@ -283,14 +321,20 @@ async function validateConfig(configType, config, isPreset, parentPath) {
|
|
|
283
321
|
baseBranchPatterns: config.baseBranchPatterns
|
|
284
322
|
}));
|
|
285
323
|
const selectorLength = Object.keys(resolvedRule).filter((ruleKey) => selectors.includes(ruleKey)).length;
|
|
286
|
-
if (!selectorLength) {
|
|
324
|
+
if (!selectorLength) if (hasRelativePresets) {
|
|
325
|
+
const message = `${currentPath}[${subIndex}]: this rule extends a relative preset that cannot be resolved during validation, so its selectors could not be checked. Rule: ${JSON.stringify(packageRule)}`;
|
|
326
|
+
warnings.push({
|
|
327
|
+
topic: "Configuration Error",
|
|
328
|
+
message
|
|
329
|
+
});
|
|
330
|
+
} else {
|
|
287
331
|
const message = `${currentPath}[${subIndex}]: Each packageRule must contain at least one match* or exclude* selector. Rule: ${JSON.stringify(packageRule)}`;
|
|
288
332
|
errors.push({
|
|
289
333
|
topic: "Configuration Error",
|
|
290
334
|
message
|
|
291
335
|
});
|
|
292
336
|
}
|
|
293
|
-
if (selectorLength === Object.keys(resolvedRule).length) {
|
|
337
|
+
if (!hasRelativePresets && selectorLength === Object.keys(resolvedRule).length) {
|
|
294
338
|
const message = `${currentPath}[${subIndex}]: Each packageRule must contain at least one non-match* or non-exclude* field. Rule: ${JSON.stringify(packageRule)}`;
|
|
295
339
|
warnings.push({
|
|
296
340
|
topic: "Configuration Error",
|