renovate 44.95.0 → 44.96.0
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 +6 -0
- package/dist/config/options/index.js.map +1 -1
- package/dist/config/types.d.ts +1 -0
- package/dist/config/types.js.map +1 -1
- package/dist/modules/manager/dockerfile/apk.js +176 -0
- package/dist/modules/manager/dockerfile/apk.js.map +1 -0
- package/dist/modules/manager/dockerfile/dep-types.js +4 -0
- package/dist/modules/manager/dockerfile/dep-types.js.map +1 -1
- package/dist/modules/manager/dockerfile/extract.js +5 -0
- package/dist/modules/manager/dockerfile/extract.js.map +1 -1
- package/dist/modules/manager/dockerfile/index.js +2 -1
- package/dist/modules/manager/dockerfile/index.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/platform/github/index.js +4 -0
- package/dist/modules/platform/github/index.js.map +1 -1
- package/dist/modules/versioning/conda/index.js +3 -1
- package/dist/modules/versioning/conda/index.js.map +1 -1
- package/dist/modules/versioning/index.js +2 -1
- package/dist/modules/versioning/index.js.map +1 -1
- package/dist/modules/versioning/ruby/version.js +1 -0
- package/dist/modules/versioning/ruby/version.js.map +1 -1
- package/dist/util/minimum-release-age.js +14 -3
- package/dist/util/minimum-release-age.js.map +1 -1
- package/dist/workers/repository/config-migration/branch/rebase.js +1 -0
- package/dist/workers/repository/config-migration/branch/rebase.js.map +1 -1
- package/dist/workers/repository/index.js +1 -0
- package/dist/workers/repository/index.js.map +1 -1
- package/dist/workers/repository/init/merge.js +1 -0
- package/dist/workers/repository/init/merge.js.map +1 -1
- package/dist/workers/repository/onboarding/pr/pr-list.js +2 -3
- package/dist/workers/repository/onboarding/pr/pr-list.js.map +1 -1
- package/dist/workers/repository/reconfigure/index.js +1 -3
- package/dist/workers/repository/reconfigure/index.js.map +1 -1
- package/dist/workers/repository/update/branch/index.js +2 -3
- package/dist/workers/repository/update/branch/index.js.map +1 -1
- package/dist/workers/repository/update/pr/changelog/release-notes.js +3 -1
- package/dist/workers/repository/update/pr/changelog/release-notes.js.map +1 -1
- package/dist/workers/repository/update/pr/changelog/source.js +1 -0
- package/dist/workers/repository/update/pr/changelog/source.js.map +1 -1
- package/dist/workers/repository/updates/flatten.js +1 -1
- package/dist/workers/repository/updates/flatten.js.map +1 -1
- package/package.json +1 -1
- package/renovate-schema.json +11 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../../lib/modules/versioning/conda/index.ts"],"sourcesContent":["import { Version, VersionSpec } from '@baszalmstra/rattler';\nimport type { SemVer } from 'semver';\n\nimport type { RangeStrategy } from '../../../types/versioning.ts';\nimport { regEx } from '../../../util/regex.ts';\nimport * as pep440 from '../pep440/index.ts';\nimport type { NewValueConfig, VersioningApi } from '../types.ts';\n\nfunction parse(v: string): Version | null {\n try {\n return new Version(v);\n } catch {\n return null;\n }\n}\n\nexport const id = 'conda';\nexport const displayName = 'conda';\nexport const urls = [\n '[Conda package match specifications](https://docs.conda.io/projects/conda-build/en/stable/resources/package-spec.html#package-match-specifications)',\n];\nexport const supportsRanges = true;\nexport const supportedRangeStrategies: RangeStrategy[] = [\n 'bump',\n 'widen',\n 'replace',\n];\n\nfunction isValidVersion(s: string): boolean {\n try {\n new Version(s);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction isValidVersionSpec(s: string): boolean {\n try {\n new VersionSpec(s);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction isValid(input: string): boolean {\n return isValidVersion(input) || isValidVersionSpec(input);\n}\n\nfunction matches(version: string, range: string): boolean {\n try {\n return new VersionSpec(range).matches(new Version(version));\n } catch {\n return false;\n }\n}\n\nfunction isSingleVersion(input: string): boolean {\n if (!input.startsWith('=')) {\n return false;\n }\n\n return isValidVersion(input.replace(regEx(/^==/), '').trimStart());\n}\n\nfunction getPinnedValue(newVersion: string): string {\n return `==${newVersion}`;\n}\n\nfunction getNewValue({\n currentValue,\n rangeStrategy,\n currentVersion,\n newVersion,\n isReplacement,\n}: NewValueConfig): string | null {\n if (currentValue === '*') {\n if (rangeStrategy === 'bump') {\n return `>=${newVersion}`;\n }\n\n // don't think you can widen or replace `*`\n return null;\n }\n\n const normalizedCurrentValue = new VersionSpec(currentValue).toString();\n\n // it's valid range spec in conda to write `3.12.*`, translate to pep440 `==3.12.*`\n if (regEx(/^(?:\\d+\\.)+\\*$/).test(normalizedCurrentValue)) {\n const newValue = pep440.api.getNewValue({\n currentValue: `==${normalizedCurrentValue}`,\n rangeStrategy,\n currentVersion,\n newVersion,\n isReplacement,\n });\n\n return newValue?.replace(regEx(/^==/), '') ?? null;\n }\n\n return pep440.api.getNewValue({\n currentValue: normalizedCurrentValue,\n rangeStrategy,\n currentVersion,\n newVersion,\n isReplacement,\n });\n}\n\nfunction sortVersions(version: string, other: string): number {\n return new Version(version).compare(new Version(other));\n}\n\nfunction equals(version: string, other: string): boolean {\n const v2 = parse(other);\n if (!v2) {\n return false;\n }\n\n return parse(version)?.equals(v2) ?? false;\n}\n\nfunction isStable(version: string): boolean {\n return !(parse(version)?.isDev ?? true);\n}\n\nfunction isCompatible(_version: string, _current?: string): boolean {\n return true;\n}\n\nfunction getMajor(version: string | SemVer): null | number {\n return parse(version as string)?.asMajorMinor?.()?.[0] ?? null;\n}\nfunction getMinor(version: string | SemVer): null | number {\n return parse(version as string)?.asMajorMinor?.()?.[1] ?? null;\n}\n\nfunction getPatch(version: string | SemVer): null | number {\n try {\n return pep440.api.getPatch(version);\n } catch {\n return null;\n }\n}\n\nfunction isGreaterThan(version: string, other: string): boolean {\n return sortVersions(version, other) > 0;\n}\nfunction getSatisfyingVersion(\n versions: string[],\n range: string,\n): string | null {\n const spec = new VersionSpec(range);\n\n const satisfiedVersions = versions\n .map((v) => {\n return [new Version(v), v] as const;\n })\n .filter(([v, _raw]) => spec.matches(v))\n .sort((a, b) => {\n return a[0].compare(b[0]);\n });\n\n if (satisfiedVersions.length === 0) {\n return null;\n }\n\n return satisfiedVersions.at(-1)![1];\n}\n\nfunction minSatisfyingVersion(\n versions: string[],\n range: string,\n): string | null {\n const spec = new VersionSpec(range);\n\n const satisfiedVersions = versions\n .map((v) => {\n return [new Version(v), v] as const;\n })\n .filter(([v, _raw]) => spec.matches(v))\n .sort((a, b) => {\n return a[0].compare(b[0]);\n });\n\n if (satisfiedVersions.length === 0) {\n return null;\n }\n\n return satisfiedVersions[0][1];\n}\n\nexport const api = {\n equals,\n isValid,\n isVersion: isValidVersion,\n isSingleVersion,\n\n // conda doesn't have stable version and non-stable version\n // for example, tzdata has version 2024a but it's stable\n isStable,\n\n // conda use version are always compatible with each other.\n isCompatible,\n\n getMajor,\n getMinor,\n // sadly conda version doesn't have a concept of patch version\n // so we try to use pep440 get a patch version.\n getPatch,\n\n isGreaterThan,\n getSatisfyingVersion,\n\n minSatisfyingVersion,\n getNewValue,\n getPinnedValue,\n matches,\n sortVersions,\n} satisfies VersioningApi;\n"],"mappings":";;;;AAQA,SAAS,MAAM,GAA2B;CACxC,IAAI;EACF,OAAO,IAAI,QAAQ,CAAC;CACtB,QAAQ;EACN,OAAO;CACT;AACF;AAEA,MAAa,KAAK;AAYlB,SAAS,eAAe,GAAoB;CAC1C,IAAI;EACF,IAAI,QAAQ,CAAC;EACb,OAAO;CACT,QAAQ;EACN,OAAO;CACT;AACF;AAEA,SAAS,mBAAmB,GAAoB;CAC9C,IAAI;EACF,IAAI,YAAY,CAAC;EACjB,OAAO;CACT,QAAQ;EACN,OAAO;CACT;AACF;AAEA,SAAS,QAAQ,OAAwB;CACvC,OAAO,eAAe,KAAK,KAAK,mBAAmB,KAAK;AAC1D;AAEA,SAAS,QAAQ,SAAiB,OAAwB;CACxD,IAAI;EACF,OAAO,IAAI,YAAY,KAAK,CAAC,CAAC,QAAQ,IAAI,QAAQ,OAAO,CAAC;CAC5D,QAAQ;EACN,OAAO;CACT;AACF;AAEA,SAAS,gBAAgB,OAAwB;CAC/C,IAAI,CAAC,MAAM,WAAW,GAAG,GACvB,OAAO;CAGT,OAAO,eAAe,MAAM,QAAQ,MAAM,KAAK,GAAG,EAAE,CAAC,CAAC,UAAU,CAAC;AACnE;AAEA,SAAS,eAAe,YAA4B;CAClD,OAAO,KAAK;AACd;AAEA,SAAS,YAAY,EACnB,cACA,eACA,gBACA,YACA,iBACgC;CAChC,IAAI,iBAAiB,KAAK;EACxB,IAAI,kBAAkB,QACpB,OAAO,KAAK;EAId,OAAO;CACT;CAEA,MAAM,yBAAyB,IAAI,YAAY,YAAY,CAAC,CAAC,SAAS;CAGtE,IAAI,MAAM,gBAAgB,CAAC,CAAC,KAAK,sBAAsB,
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../../lib/modules/versioning/conda/index.ts"],"sourcesContent":["import { Version, VersionSpec } from '@baszalmstra/rattler';\nimport type { SemVer } from 'semver';\n\nimport type { RangeStrategy } from '../../../types/versioning.ts';\nimport { regEx } from '../../../util/regex.ts';\nimport * as pep440 from '../pep440/index.ts';\nimport type { NewValueConfig, VersioningApi } from '../types.ts';\n\nfunction parse(v: string): Version | null {\n try {\n return new Version(v);\n } catch {\n return null;\n }\n}\n\nexport const id = 'conda';\nexport const displayName = 'conda';\nexport const urls = [\n '[Conda package match specifications](https://docs.conda.io/projects/conda-build/en/stable/resources/package-spec.html#package-match-specifications)',\n];\nexport const supportsRanges = true;\nexport const supportedRangeStrategies: RangeStrategy[] = [\n 'bump',\n 'widen',\n 'replace',\n];\n\nfunction isValidVersion(s: string): boolean {\n try {\n new Version(s);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction isValidVersionSpec(s: string): boolean {\n try {\n new VersionSpec(s);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction isValid(input: string): boolean {\n return isValidVersion(input) || isValidVersionSpec(input);\n}\n\nfunction matches(version: string, range: string): boolean {\n try {\n return new VersionSpec(range).matches(new Version(version));\n } catch {\n return false;\n }\n}\n\nfunction isSingleVersion(input: string): boolean {\n if (!input.startsWith('=')) {\n return false;\n }\n\n return isValidVersion(input.replace(regEx(/^==/), '').trimStart());\n}\n\nfunction getPinnedValue(newVersion: string): string {\n return `==${newVersion}`;\n}\n\nfunction getNewValue({\n currentValue,\n rangeStrategy,\n currentVersion,\n newVersion,\n isReplacement,\n}: NewValueConfig): string | null {\n if (currentValue === '*') {\n if (rangeStrategy === 'bump') {\n return `>=${newVersion}`;\n }\n\n // don't think you can widen or replace `*`\n return null;\n }\n\n const normalizedCurrentValue = new VersionSpec(currentValue).toString();\n\n // it's valid range spec in conda to write `3.12.*`, translate to pep440 `==3.12.*`\n if (regEx(/^(?:\\d+\\.)+\\*$/).test(normalizedCurrentValue)) {\n const newValue = pep440.api.getNewValue({\n currentValue: `==${normalizedCurrentValue}`,\n rangeStrategy,\n currentVersion,\n newVersion,\n isReplacement,\n });\n\n // v8 ignore next -- pep440 always answers for a well-formed `==X.Y.*`\n return newValue?.replace(regEx(/^==/), '') ?? null;\n }\n\n return pep440.api.getNewValue({\n currentValue: normalizedCurrentValue,\n rangeStrategy,\n currentVersion,\n newVersion,\n isReplacement,\n });\n}\n\nfunction sortVersions(version: string, other: string): number {\n return new Version(version).compare(new Version(other));\n}\n\nfunction equals(version: string, other: string): boolean {\n const v2 = parse(other);\n if (!v2) {\n return false;\n }\n\n return parse(version)?.equals(v2) ?? false;\n}\n\nfunction isStable(version: string): boolean {\n return !(parse(version)?.isDev ?? true);\n}\n\nfunction isCompatible(_version: string, _current?: string): boolean {\n return true;\n}\n\nfunction getMajor(version: string | SemVer): null | number {\n return parse(version as string)?.asMajorMinor?.()?.[0] ?? null;\n}\nfunction getMinor(version: string | SemVer): null | number {\n return parse(version as string)?.asMajorMinor?.()?.[1] ?? null;\n}\n\nfunction getPatch(version: string | SemVer): null | number {\n try {\n return pep440.api.getPatch(version);\n } catch {\n return null;\n }\n}\n\nfunction isGreaterThan(version: string, other: string): boolean {\n return sortVersions(version, other) > 0;\n}\nfunction getSatisfyingVersion(\n versions: string[],\n range: string,\n): string | null {\n const spec = new VersionSpec(range);\n\n const satisfiedVersions = versions\n .map((v) => {\n return [new Version(v), v] as const;\n })\n .filter(([v, _raw]) => spec.matches(v))\n .sort((a, b) => {\n return a[0].compare(b[0]);\n });\n\n if (satisfiedVersions.length === 0) {\n return null;\n }\n\n return satisfiedVersions.at(-1)![1];\n}\n\nfunction minSatisfyingVersion(\n versions: string[],\n range: string,\n): string | null {\n const spec = new VersionSpec(range);\n\n const satisfiedVersions = versions\n .map((v) => {\n return [new Version(v), v] as const;\n })\n .filter(([v, _raw]) => spec.matches(v))\n .sort((a, b) => {\n return a[0].compare(b[0]);\n });\n\n if (satisfiedVersions.length === 0) {\n return null;\n }\n\n return satisfiedVersions[0][1];\n}\n\nexport const api = {\n equals,\n isValid,\n isVersion: isValidVersion,\n isSingleVersion,\n\n // conda doesn't have stable version and non-stable version\n // for example, tzdata has version 2024a but it's stable\n isStable,\n\n // conda use version are always compatible with each other.\n isCompatible,\n\n getMajor,\n getMinor,\n // sadly conda version doesn't have a concept of patch version\n // so we try to use pep440 get a patch version.\n getPatch,\n\n isGreaterThan,\n getSatisfyingVersion,\n\n minSatisfyingVersion,\n getNewValue,\n getPinnedValue,\n matches,\n sortVersions,\n} satisfies VersioningApi;\n"],"mappings":"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"}
|
|
@@ -16,7 +16,8 @@ function get(versioning) {
|
|
|
16
16
|
const res = Versioning.safeParse(versioning ?? defaultVersioning.id);
|
|
17
17
|
if (!res.success) {
|
|
18
18
|
const [issue] = res.error.issues;
|
|
19
|
-
|
|
19
|
+
// v8 ignore else -- a string input can only fail with the custom issue
|
|
20
|
+
if (issue?.code === "custom" && issue.params?.error) throw issue.params.error;
|
|
20
21
|
// istanbul ignore next: should never happen
|
|
21
22
|
throw res.error;
|
|
22
23
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["semverCoerced","versionings"],"sources":["../../../lib/modules/versioning/index.ts"],"sourcesContent":["import versionings from './api.ts';\nimport { Versioning } from './schema.ts';\nimport * as semverCoerced from './semver-coerced/index.ts';\nimport type { VersioningApi, VersioningApiConstructor } from './types.ts';\n\nexport * from './types.ts';\n\nexport const defaultVersioning = semverCoerced;\n\nexport function getVersioningList(): string[] {\n return Array.from(versionings.keys());\n}\n\n/**\n * Get versioning map. Can be used to dynamically add new versioning type\n */\nexport function getVersionings(): Map<\n string,\n VersioningApi | VersioningApiConstructor\n> {\n return versionings;\n}\n\nexport function get(versioning: string | null | undefined): VersioningApi {\n const res = Versioning.safeParse(versioning ?? defaultVersioning.id);\n\n if (!res.success) {\n const [issue] = res.error.issues;\n //
|
|
1
|
+
{"version":3,"file":"index.js","names":["semverCoerced","versionings"],"sources":["../../../lib/modules/versioning/index.ts"],"sourcesContent":["import versionings from './api.ts';\nimport { Versioning } from './schema.ts';\nimport * as semverCoerced from './semver-coerced/index.ts';\nimport type { VersioningApi, VersioningApiConstructor } from './types.ts';\n\nexport * from './types.ts';\n\nexport const defaultVersioning = semverCoerced;\n\nexport function getVersioningList(): string[] {\n return Array.from(versionings.keys());\n}\n\n/**\n * Get versioning map. Can be used to dynamically add new versioning type\n */\nexport function getVersionings(): Map<\n string,\n VersioningApi | VersioningApiConstructor\n> {\n return versionings;\n}\n\nexport function get(versioning: string | null | undefined): VersioningApi {\n const res = Versioning.safeParse(versioning ?? defaultVersioning.id);\n\n if (!res.success) {\n const [issue] = res.error.issues;\n // v8 ignore else -- a string input can only fail with the custom issue\n if (issue?.code === 'custom' && issue.params?.error) {\n throw issue.params.error;\n }\n\n // istanbul ignore next: should never happen\n throw res.error;\n }\n\n return res.data;\n}\n"],"mappings":";;;;AAOA,MAAa,oBAAoBA;AAEjC,SAAgB,oBAA8B;CAC5C,OAAO,MAAM,KAAKC,IAAY,KAAK,CAAC;AACtC;;;;AAKA,SAAgB,iBAGd;CACA,OAAOA;AACT;AAEA,SAAgB,IAAI,YAAsD;CACxE,MAAM,MAAM,WAAW,UAAU,cAAc,kBAAkB,EAAE;CAEnE,IAAI,CAAC,IAAI,SAAS;EAChB,MAAM,CAAC,SAAS,IAAI,MAAM;;EAE1B,IAAI,OAAO,SAAS,YAAY,MAAM,QAAQ,OAC5C,MAAM,MAAM,OAAO;;EAIrB,MAAM,IAAI;CACZ;CAEA,OAAO,IAAI;AACb"}
|
|
@@ -5,6 +5,7 @@ import { create } from "@renovatebot/ruby-semver/dist/ruby/version.js";
|
|
|
5
5
|
//#region lib/modules/versioning/ruby/version.ts
|
|
6
6
|
function releaseSegments(version) {
|
|
7
7
|
const v = create(version);
|
|
8
|
+
// v8 ignore else -- callers only pass versions that have already parsed
|
|
8
9
|
if (v) return v.release().getSegments();
|
|
9
10
|
/* istanbul ignore next */
|
|
10
11
|
return [];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version.js","names":[],"sources":["../../../../lib/modules/versioning/ruby/version.ts"],"sourcesContent":["import { eq, major, minor, patch, prerelease } from '@renovatebot/ruby-semver';\nimport type { SegmentElement } from '@renovatebot/ruby-semver/dist/ruby/version.js';\nimport { create } from '@renovatebot/ruby-semver/dist/ruby/version.js';\nimport { coerceArray } from '../../../util/array.ts';\nimport { regEx } from '../../../util/regex.ts';\n\ninterface RubyVersion {\n major: number;\n minor: number;\n patch: number;\n prerelease: string[] | null;\n}\n\nfunction releaseSegments(version: string): SegmentElement[] {\n const v = create(version);\n if (v) {\n return v.release().getSegments();\n }\n /* istanbul ignore next */\n return [];\n}\n\nfunction parse(version: string): RubyVersion {\n return {\n major: major(version),\n minor: minor(version),\n patch: patch(version),\n prerelease: prerelease(version),\n };\n}\n\nfunction floor(version: string): string {\n const segments = releaseSegments(version);\n if (segments.length <= 1) {\n // '~> 2' is equivalent to '~> 2.0', thus no need to floor\n return segments.join('.');\n }\n return [...segments.slice(0, -1), 0].join('.');\n}\n\nfunction adapt(left: string, right: string): string {\n return left.split('.').slice(0, right.split('.').length).join('.');\n}\n\nfunction trimZeroes(version: string): string {\n const segments = version.split('.');\n while (segments.length > 0 && segments.at(-1) === '0') {\n segments.pop();\n }\n return segments.join('.');\n}\n\n// Returns the upper bound of `~>` operator.\nfunction pgteUpperBound(version: string): string {\n const segments = releaseSegments(version);\n if (segments.length > 1) {\n segments.pop();\n }\n return incrementLastSegment(segments.join('.'));\n}\n\n// istanbul ignore next\nfunction incrementLastSegment(version: string): string {\n const segments = releaseSegments(version);\n const nextLast = parseInt(segments.pop() as string, 10) + 1;\n\n return [...segments, nextLast].join('.');\n}\n\n// istanbul ignore next\nfunction incrementMajor(\n maj: number,\n min: number,\n ptch: number,\n pre: string[],\n): number {\n return min === 0 || ptch === 0 || pre.length === 0 ? maj + 1 : maj;\n}\n\n// istanbul ignore next\nfunction incrementMinor(min: number, ptch: number, pre: string[]): number {\n return ptch === 0 || pre.length === 0 ? min + 1 : min;\n}\n\n// istanbul ignore next\nfunction incrementPatch(ptch: number, pre: string[]): number {\n return pre.length === 0 ? ptch + 1 : ptch;\n}\n\n// istanbul ignore next\nfunction increment(from: string, to: string): string {\n const parsed = parse(from);\n const { major: maj, prerelease: pre } = parsed;\n let { minor: min, patch: ptch } = parsed;\n min = min || 0;\n ptch = ptch || 0;\n\n let nextVersion: string;\n const adapted = adapt(to, from);\n if (eq(from, adapted)) {\n return incrementLastSegment(from);\n }\n\n function isStable(x: string): boolean {\n return regEx(/^[0-9.-/]+$/).test(x);\n }\n if (major(from) !== major(adapted)) {\n nextVersion = [incrementMajor(maj, min, ptch, coerceArray(pre)), 0, 0].join(\n '.',\n );\n } else if (minor(from) !== minor(adapted)) {\n nextVersion = [maj, incrementMinor(min, ptch, coerceArray(pre)), 0].join(\n '.',\n );\n } else if (patch(from) !== patch(adapted)) {\n nextVersion = [maj, min, incrementPatch(ptch, coerceArray(pre))].join('.');\n } else if (isStable(from) && isStable(adapted)) {\n nextVersion = [maj, min, incrementPatch(ptch, coerceArray(pre))].join('.');\n } else {\n nextVersion = [maj, min, ptch].join('.');\n }\n\n return increment(nextVersion, to);\n}\n\n// istanbul ignore next\nfunction decrement(version: string): string {\n const segments = releaseSegments(version);\n const nextSegments = segments\n .reverse()\n .reduce(\n (\n accumulator: number[],\n segment: SegmentElement,\n index: number,\n ): number[] => {\n if (index === 0) {\n return [(segment as number) - 1];\n }\n\n if (accumulator[index - 1] === -1) {\n return [\n ...accumulator.slice(0, index - 1),\n 0,\n (segment as number) - 1,\n ];\n }\n\n return [...accumulator, segment as number];\n },\n [],\n );\n\n return nextSegments.reverse().join('.');\n}\n\nexport {\n adapt,\n decrement,\n floor,\n increment,\n parse,\n pgteUpperBound,\n trimZeroes,\n};\n"],"mappings":";;;;;AAaA,SAAS,gBAAgB,SAAmC;CAC1D,MAAM,IAAI,OAAO,OAAO
|
|
1
|
+
{"version":3,"file":"version.js","names":[],"sources":["../../../../lib/modules/versioning/ruby/version.ts"],"sourcesContent":["import { eq, major, minor, patch, prerelease } from '@renovatebot/ruby-semver';\nimport type { SegmentElement } from '@renovatebot/ruby-semver/dist/ruby/version.js';\nimport { create } from '@renovatebot/ruby-semver/dist/ruby/version.js';\nimport { coerceArray } from '../../../util/array.ts';\nimport { regEx } from '../../../util/regex.ts';\n\ninterface RubyVersion {\n major: number;\n minor: number;\n patch: number;\n prerelease: string[] | null;\n}\n\nfunction releaseSegments(version: string): SegmentElement[] {\n const v = create(version);\n // v8 ignore else -- callers only pass versions that have already parsed\n if (v) {\n return v.release().getSegments();\n }\n /* istanbul ignore next */\n return [];\n}\n\nfunction parse(version: string): RubyVersion {\n return {\n major: major(version),\n minor: minor(version),\n patch: patch(version),\n prerelease: prerelease(version),\n };\n}\n\nfunction floor(version: string): string {\n const segments = releaseSegments(version);\n if (segments.length <= 1) {\n // '~> 2' is equivalent to '~> 2.0', thus no need to floor\n return segments.join('.');\n }\n return [...segments.slice(0, -1), 0].join('.');\n}\n\nfunction adapt(left: string, right: string): string {\n return left.split('.').slice(0, right.split('.').length).join('.');\n}\n\nfunction trimZeroes(version: string): string {\n const segments = version.split('.');\n while (segments.length > 0 && segments.at(-1) === '0') {\n segments.pop();\n }\n return segments.join('.');\n}\n\n// Returns the upper bound of `~>` operator.\nfunction pgteUpperBound(version: string): string {\n const segments = releaseSegments(version);\n if (segments.length > 1) {\n segments.pop();\n }\n return incrementLastSegment(segments.join('.'));\n}\n\n// istanbul ignore next\nfunction incrementLastSegment(version: string): string {\n const segments = releaseSegments(version);\n const nextLast = parseInt(segments.pop() as string, 10) + 1;\n\n return [...segments, nextLast].join('.');\n}\n\n// istanbul ignore next\nfunction incrementMajor(\n maj: number,\n min: number,\n ptch: number,\n pre: string[],\n): number {\n return min === 0 || ptch === 0 || pre.length === 0 ? maj + 1 : maj;\n}\n\n// istanbul ignore next\nfunction incrementMinor(min: number, ptch: number, pre: string[]): number {\n return ptch === 0 || pre.length === 0 ? min + 1 : min;\n}\n\n// istanbul ignore next\nfunction incrementPatch(ptch: number, pre: string[]): number {\n return pre.length === 0 ? ptch + 1 : ptch;\n}\n\n// istanbul ignore next\nfunction increment(from: string, to: string): string {\n const parsed = parse(from);\n const { major: maj, prerelease: pre } = parsed;\n let { minor: min, patch: ptch } = parsed;\n min = min || 0;\n ptch = ptch || 0;\n\n let nextVersion: string;\n const adapted = adapt(to, from);\n if (eq(from, adapted)) {\n return incrementLastSegment(from);\n }\n\n function isStable(x: string): boolean {\n return regEx(/^[0-9.-/]+$/).test(x);\n }\n if (major(from) !== major(adapted)) {\n nextVersion = [incrementMajor(maj, min, ptch, coerceArray(pre)), 0, 0].join(\n '.',\n );\n } else if (minor(from) !== minor(adapted)) {\n nextVersion = [maj, incrementMinor(min, ptch, coerceArray(pre)), 0].join(\n '.',\n );\n } else if (patch(from) !== patch(adapted)) {\n nextVersion = [maj, min, incrementPatch(ptch, coerceArray(pre))].join('.');\n } else if (isStable(from) && isStable(adapted)) {\n nextVersion = [maj, min, incrementPatch(ptch, coerceArray(pre))].join('.');\n } else {\n nextVersion = [maj, min, ptch].join('.');\n }\n\n return increment(nextVersion, to);\n}\n\n// istanbul ignore next\nfunction decrement(version: string): string {\n const segments = releaseSegments(version);\n const nextSegments = segments\n .reverse()\n .reduce(\n (\n accumulator: number[],\n segment: SegmentElement,\n index: number,\n ): number[] => {\n if (index === 0) {\n return [(segment as number) - 1];\n }\n\n if (accumulator[index - 1] === -1) {\n return [\n ...accumulator.slice(0, index - 1),\n 0,\n (segment as number) - 1,\n ];\n }\n\n return [...accumulator, segment as number];\n },\n [],\n );\n\n return nextSegments.reverse().join('.');\n}\n\nexport {\n adapt,\n decrement,\n floor,\n increment,\n parse,\n pgteUpperBound,\n trimZeroes,\n};\n"],"mappings":"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"}
|
|
@@ -4,13 +4,24 @@ import { getElapsedMs } from "./date.js";
|
|
|
4
4
|
import { isNonEmptyString } from "@sindresorhus/is";
|
|
5
5
|
//#region lib/util/minimum-release-age.ts
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
7
|
+
* Calculates the effective minimum release age in milliseconds, extended by
|
|
8
|
+
* the `minimumReleaseAgeBuffer` duration if configured.
|
|
9
|
+
*/
|
|
10
|
+
function calculateMinimumReleaseAgeMs(config) {
|
|
11
|
+
const minimumReleaseAgeMs = isNonEmptyString(config.minimumReleaseAge) ? coerceNumber(toMs(config.minimumReleaseAge), 0) : 0;
|
|
12
|
+
if (!minimumReleaseAgeMs) return 0;
|
|
13
|
+
const bufferMs = isNonEmptyString(config.minimumReleaseAgeBuffer) ? coerceNumber(toMs(config.minimumReleaseAgeBuffer), 0) : 0;
|
|
14
|
+
return minimumReleaseAgeMs + Math.max(bufferMs, 0);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Checks whether a release satisfies `minimumReleaseAge`, extended by
|
|
18
|
+
* `minimumReleaseAgeBuffer` if configured.
|
|
8
19
|
*
|
|
9
20
|
* Separate from `internalChecksFilter` to allow reuse, and lives here so that
|
|
10
21
|
* managers can import it without an import cycle.
|
|
11
22
|
*/
|
|
12
23
|
function checkMinimumReleaseAge(config, releaseTimestamp) {
|
|
13
|
-
const minimumReleaseAgeMs =
|
|
24
|
+
const minimumReleaseAgeMs = calculateMinimumReleaseAgeMs(config);
|
|
14
25
|
if (!minimumReleaseAgeMs) return {
|
|
15
26
|
isPending: false,
|
|
16
27
|
minimumReleaseAgeMs,
|
|
@@ -28,6 +39,6 @@ function checkMinimumReleaseAge(config, releaseTimestamp) {
|
|
|
28
39
|
};
|
|
29
40
|
}
|
|
30
41
|
//#endregion
|
|
31
|
-
export { checkMinimumReleaseAge };
|
|
42
|
+
export { calculateMinimumReleaseAgeMs, checkMinimumReleaseAge };
|
|
32
43
|
|
|
33
44
|
//# sourceMappingURL=minimum-release-age.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"minimum-release-age.js","names":[],"sources":["../../lib/util/minimum-release-age.ts"],"sourcesContent":["import { isNonEmptyString } from '@sindresorhus/is';\nimport type { MinimumReleaseAgeBehaviour } from '../config/types.ts';\nimport { getElapsedMs } from './date.ts';\nimport { coerceNumber } from './number.ts';\nimport { toMs } from './pretty-time.ts';\nimport type { Timestamp } from './timestamp.ts';\n\nexport interface MinimumReleaseAgeCheckResult {\n isPending: boolean;\n minimumReleaseAgeMs: number;\n hasTimestamp: boolean;\n}\n\n/**\n * Checks whether a release satisfies `minimumReleaseAge
|
|
1
|
+
{"version":3,"file":"minimum-release-age.js","names":[],"sources":["../../lib/util/minimum-release-age.ts"],"sourcesContent":["import { isNonEmptyString } from '@sindresorhus/is';\nimport type { MinimumReleaseAgeBehaviour } from '../config/types.ts';\nimport { getElapsedMs } from './date.ts';\nimport { coerceNumber } from './number.ts';\nimport { toMs } from './pretty-time.ts';\nimport type { Timestamp } from './timestamp.ts';\n\nexport interface MinimumReleaseAgeCheckResult {\n isPending: boolean;\n /** Effective minimum release age, including `minimumReleaseAgeBuffer`. */\n minimumReleaseAgeMs: number;\n hasTimestamp: boolean;\n}\n\n/**\n * Calculates the effective minimum release age in milliseconds, extended by\n * the `minimumReleaseAgeBuffer` duration if configured.\n */\nexport function calculateMinimumReleaseAgeMs(config: {\n minimumReleaseAge?: string | null;\n minimumReleaseAgeBuffer?: string | null;\n}): number {\n const minimumReleaseAgeMs = isNonEmptyString(config.minimumReleaseAge)\n ? coerceNumber(toMs(config.minimumReleaseAge), 0)\n : 0;\n\n if (!minimumReleaseAgeMs) {\n return 0;\n }\n\n const bufferMs = isNonEmptyString(config.minimumReleaseAgeBuffer)\n ? coerceNumber(toMs(config.minimumReleaseAgeBuffer), 0)\n : 0;\n\n return minimumReleaseAgeMs + Math.max(bufferMs, 0);\n}\n\n/**\n * Checks whether a release satisfies `minimumReleaseAge`, extended by\n * `minimumReleaseAgeBuffer` if configured.\n *\n * Separate from `internalChecksFilter` to allow reuse, and lives here so that\n * managers can import it without an import cycle.\n */\nexport function checkMinimumReleaseAge(\n config: {\n minimumReleaseAge?: string | null;\n minimumReleaseAgeBuffer?: string | null;\n minimumReleaseAgeBehaviour?: MinimumReleaseAgeBehaviour | null;\n },\n releaseTimestamp: Timestamp | null | undefined,\n): MinimumReleaseAgeCheckResult {\n const minimumReleaseAgeMs = calculateMinimumReleaseAgeMs(config);\n\n if (!minimumReleaseAgeMs) {\n return {\n isPending: false,\n minimumReleaseAgeMs,\n hasTimestamp: !!releaseTimestamp,\n };\n }\n\n if (releaseTimestamp) {\n return {\n isPending: getElapsedMs(releaseTimestamp) < minimumReleaseAgeMs,\n minimumReleaseAgeMs,\n hasTimestamp: true,\n };\n }\n\n return {\n isPending: config.minimumReleaseAgeBehaviour === 'timestamp-required',\n minimumReleaseAgeMs,\n hasTimestamp: false,\n };\n}\n"],"mappings":";;;;;;;;;AAkBA,SAAgB,6BAA6B,QAGlC;CACT,MAAM,sBAAsB,iBAAiB,OAAO,iBAAiB,IACjE,aAAa,KAAK,OAAO,iBAAiB,GAAG,CAAC,IAC9C;CAEJ,IAAI,CAAC,qBACH,OAAO;CAGT,MAAM,WAAW,iBAAiB,OAAO,uBAAuB,IAC5D,aAAa,KAAK,OAAO,uBAAuB,GAAG,CAAC,IACpD;CAEJ,OAAO,sBAAsB,KAAK,IAAI,UAAU,CAAC;AACnD;;;;;;;;AASA,SAAgB,uBACd,QAKA,kBAC8B;CAC9B,MAAM,sBAAsB,6BAA6B,MAAM;CAE/D,IAAI,CAAC,qBACH,OAAO;EACL,WAAW;EACX;EACA,cAAc,CAAC,CAAC;CAClB;CAGF,IAAI,kBACF,OAAO;EACL,WAAW,aAAa,gBAAgB,IAAI;EAC5C;EACA,cAAc;CAChB;CAGF,OAAO;EACL,WAAW,OAAO,+BAA+B;EACjD;EACA,cAAc;CAChB;AACF"}
|
|
@@ -54,6 +54,7 @@ function jsonStripWhitespaces(json) {
|
|
|
54
54
|
*
|
|
55
55
|
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#parameters
|
|
56
56
|
*/
|
|
57
|
+
// v8 ignore next -- JSON5 output is always serializable back to JSON
|
|
57
58
|
return quickStringify(JSON5.parse(json)) ??
|
|
58
59
|
/* istanbul ignore next: should never happen */ null;
|
|
59
60
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rebase.js","names":[],"sources":["../../../../../lib/workers/repository/config-migration/branch/rebase.ts"],"sourcesContent":["import JSON5 from 'json5';\nimport { GlobalConfig } from '../../../../config/global.ts';\nimport type { RenovateConfig } from '../../../../config/types.ts';\nimport { logger } from '../../../../logger/index.ts';\nimport { scm } from '../../../../modules/platform/scm.ts';\nimport { getFile } from '../../../../util/git/index.ts';\nimport { quickStringify } from '../../../../util/stringify.ts';\nimport { getMigrationBranchName } from '../common.ts';\nimport { ConfigMigrationCommitMessageFactory } from './commit-message.ts';\nimport type { MigratedData } from './migrated-data.ts';\nimport { MigratedDataFactory } from './migrated-data.ts';\n\nexport async function rebaseMigrationBranch(\n config: RenovateConfig,\n migratedConfigData: MigratedData,\n): Promise<string | null> {\n logger.debug('Checking if migration branch needs rebasing');\n const baseBranch = config.defaultBranch!;\n const branchName = getMigrationBranchName(config);\n const configFileName = migratedConfigData.filename;\n let contents = migratedConfigData.content;\n const existingContents = await getFile(configFileName, branchName);\n if (\n jsonStripWhitespaces(contents) === jsonStripWhitespaces(existingContents)\n ) {\n logger.debug('Migration branch is up to date');\n return null;\n }\n logger.debug('Rebasing migration branch');\n\n if (GlobalConfig.get('dryRun')) {\n logger.info('DRY-RUN: Would rebase files in migration branch');\n return null;\n }\n\n const commitMessageFactory = new ConfigMigrationCommitMessageFactory(\n config,\n configFileName,\n );\n const commitMessage = commitMessageFactory.getCommitMessage();\n\n await scm.checkoutBranch(baseBranch);\n contents =\n await MigratedDataFactory.applyPrettierFormatting(migratedConfigData);\n return scm.commitAndPush({\n baseBranch: config.baseBranch,\n branchName,\n files: [\n {\n type: 'addition',\n path: configFileName,\n contents,\n },\n ],\n message: commitMessage.toString(),\n platformCommit: config.platformCommit,\n // Only needed by Gerrit platform\n prTitle: commitMessageFactory.getPrTitle(),\n });\n}\n\n/**\n * @param json a JSON string\n * @return a minimal json string. i.e. does not contain any formatting/whitespaces\n */\nexport function jsonStripWhitespaces(json: string | null): string | null {\n if (!json) {\n return null;\n }\n /**\n * JSON.stringify(value, replacer, space):\n * If \"space\" is anything other than a string or number —\n * for example, is null or not provided — no white space is used.\n *\n * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#parameters\n */\n return (\n quickStringify(JSON5.parse(json)) ??\n /* istanbul ignore next: should never happen */ null\n );\n}\n"],"mappings":";;;;;;;;;;AAYA,eAAsB,sBACpB,QACA,oBACwB;CACxB,OAAO,MAAM,6CAA6C;CAC1D,MAAM,aAAa,OAAO;CAC1B,MAAM,aAAa,uBAAuB,MAAM;CAChD,MAAM,iBAAiB,mBAAmB;CAC1C,IAAI,WAAW,mBAAmB;CAClC,MAAM,mBAAmB,MAAM,QAAQ,gBAAgB,UAAU;CACjE,IACE,qBAAqB,QAAQ,MAAM,qBAAqB,gBAAgB,GACxE;EACA,OAAO,MAAM,gCAAgC;EAC7C,OAAO;CACT;CACA,OAAO,MAAM,2BAA2B;CAExC,IAAI,aAAa,IAAI,QAAQ,GAAG;EAC9B,OAAO,KAAK,iDAAiD;EAC7D,OAAO;CACT;CAEA,MAAM,uBAAuB,IAAI,oCAC/B,QACA,cACF;CACA,MAAM,gBAAgB,qBAAqB,iBAAiB;CAE5D,MAAM,IAAI,eAAe,UAAU;CACnC,WACE,MAAM,oBAAoB,wBAAwB,kBAAkB;CACtE,OAAO,IAAI,cAAc;EACvB,YAAY,OAAO;EACnB;EACA,OAAO,CACL;GACE,MAAM;GACN,MAAM;GACN;EACF,CACF;EACA,SAAS,cAAc,SAAS;EAChC,gBAAgB,OAAO;EAEvB,SAAS,qBAAqB,WAAW;CAC3C,CAAC;AACH;;;;;AAMA,SAAgB,qBAAqB,MAAoC;CACvE,IAAI,CAAC,MACH,OAAO
|
|
1
|
+
{"version":3,"file":"rebase.js","names":[],"sources":["../../../../../lib/workers/repository/config-migration/branch/rebase.ts"],"sourcesContent":["import JSON5 from 'json5';\nimport { GlobalConfig } from '../../../../config/global.ts';\nimport type { RenovateConfig } from '../../../../config/types.ts';\nimport { logger } from '../../../../logger/index.ts';\nimport { scm } from '../../../../modules/platform/scm.ts';\nimport { getFile } from '../../../../util/git/index.ts';\nimport { quickStringify } from '../../../../util/stringify.ts';\nimport { getMigrationBranchName } from '../common.ts';\nimport { ConfigMigrationCommitMessageFactory } from './commit-message.ts';\nimport type { MigratedData } from './migrated-data.ts';\nimport { MigratedDataFactory } from './migrated-data.ts';\n\nexport async function rebaseMigrationBranch(\n config: RenovateConfig,\n migratedConfigData: MigratedData,\n): Promise<string | null> {\n logger.debug('Checking if migration branch needs rebasing');\n const baseBranch = config.defaultBranch!;\n const branchName = getMigrationBranchName(config);\n const configFileName = migratedConfigData.filename;\n let contents = migratedConfigData.content;\n const existingContents = await getFile(configFileName, branchName);\n if (\n jsonStripWhitespaces(contents) === jsonStripWhitespaces(existingContents)\n ) {\n logger.debug('Migration branch is up to date');\n return null;\n }\n logger.debug('Rebasing migration branch');\n\n if (GlobalConfig.get('dryRun')) {\n logger.info('DRY-RUN: Would rebase files in migration branch');\n return null;\n }\n\n const commitMessageFactory = new ConfigMigrationCommitMessageFactory(\n config,\n configFileName,\n );\n const commitMessage = commitMessageFactory.getCommitMessage();\n\n await scm.checkoutBranch(baseBranch);\n contents =\n await MigratedDataFactory.applyPrettierFormatting(migratedConfigData);\n return scm.commitAndPush({\n baseBranch: config.baseBranch,\n branchName,\n files: [\n {\n type: 'addition',\n path: configFileName,\n contents,\n },\n ],\n message: commitMessage.toString(),\n platformCommit: config.platformCommit,\n // Only needed by Gerrit platform\n prTitle: commitMessageFactory.getPrTitle(),\n });\n}\n\n/**\n * @param json a JSON string\n * @return a minimal json string. i.e. does not contain any formatting/whitespaces\n */\nexport function jsonStripWhitespaces(json: string | null): string | null {\n if (!json) {\n return null;\n }\n /**\n * JSON.stringify(value, replacer, space):\n * If \"space\" is anything other than a string or number —\n * for example, is null or not provided — no white space is used.\n *\n * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#parameters\n */\n // v8 ignore next -- JSON5 output is always serializable back to JSON\n return (\n quickStringify(JSON5.parse(json)) ??\n /* istanbul ignore next: should never happen */ null\n );\n}\n"],"mappings":";;;;;;;;;;AAYA,eAAsB,sBACpB,QACA,oBACwB;CACxB,OAAO,MAAM,6CAA6C;CAC1D,MAAM,aAAa,OAAO;CAC1B,MAAM,aAAa,uBAAuB,MAAM;CAChD,MAAM,iBAAiB,mBAAmB;CAC1C,IAAI,WAAW,mBAAmB;CAClC,MAAM,mBAAmB,MAAM,QAAQ,gBAAgB,UAAU;CACjE,IACE,qBAAqB,QAAQ,MAAM,qBAAqB,gBAAgB,GACxE;EACA,OAAO,MAAM,gCAAgC;EAC7C,OAAO;CACT;CACA,OAAO,MAAM,2BAA2B;CAExC,IAAI,aAAa,IAAI,QAAQ,GAAG;EAC9B,OAAO,KAAK,iDAAiD;EAC7D,OAAO;CACT;CAEA,MAAM,uBAAuB,IAAI,oCAC/B,QACA,cACF;CACA,MAAM,gBAAgB,qBAAqB,iBAAiB;CAE5D,MAAM,IAAI,eAAe,UAAU;CACnC,WACE,MAAM,oBAAoB,wBAAwB,kBAAkB;CACtE,OAAO,IAAI,cAAc;EACvB,YAAY,OAAO;EACnB;EACA,OAAO,CACL;GACE,MAAM;GACN,MAAM;GACN;EACF,CACF;EACA,SAAS,cAAc,SAAS;EAChC,gBAAgB,OAAO;EAEvB,SAAS,qBAAqB,WAAW;CAC3C,CAAC;AACH;;;;;AAMA,SAAgB,qBAAqB,MAAoC;CACvE,IAAI,CAAC,MACH,OAAO;;;;;;;;;CAUT,OACE,eAAe,MAAM,MAAM,IAAI,CAAC;iDACgB;AAEpD"}
|
|
@@ -163,6 +163,7 @@ function emptyExtract() {
|
|
|
163
163
|
}
|
|
164
164
|
function printRepositoryProblems(repository) {
|
|
165
165
|
const repoProblems = extractRepoProblems(repository);
|
|
166
|
+
// v8 ignore else -- only called when the repository logged a problem
|
|
166
167
|
if (repoProblems.size) logger.debug({ repoProblems: Array.from(repoProblems) }, "repository problems");
|
|
167
168
|
}
|
|
168
169
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../lib/workers/repository/index.ts"],"sourcesContent":["import { GlobalConfig } from '../../config/global.ts';\nimport { applySecretsAndVariablesToConfig } from '../../config/secrets.ts';\nimport type { RenovateConfig } from '../../config/types.ts';\nimport {\n REPOSITORY_DISABLED_BY_CONFIG,\n REPOSITORY_FORKED,\n REPOSITORY_NO_CONFIG,\n} from '../../constants/error-messages.ts';\nimport { pkg } from '../../expose.ts';\nimport { instrument } from '../../instrumentation/index.ts';\nimport { addExtractionStats } from '../../instrumentation/reporting.ts';\nimport { ATTR_RENOVATE_SPLIT } from '../../instrumentation/types.ts';\nimport { logger, setMeta } from '../../logger/index.ts';\nimport { resetRepositoryLogLevelRemaps } from '../../logger/remap.ts';\nimport { getInheritedOrGlobal } from '../../util/common.ts';\nimport { removeDanglingContainers } from '../../util/exec/docker/index.ts';\nimport {\n deleteLocalFile,\n ensureDir,\n privateCacheDir,\n rmCache,\n} from '../../util/fs/index.ts';\nimport { isCloned } from '../../util/git/index.ts';\nimport { detectSemanticCommits } from '../../util/git/semantic.ts';\nimport * as queue from '../../util/http/queue.ts';\nimport * as throttle from '../../util/http/throttle.ts';\nimport { addSplit, getSplits, splitInit } from '../../util/split.ts';\nimport {\n AbandonedPackageStats,\n DatasourceCacheStats,\n GetDatasourceReleasesStats,\n GitOperationStats,\n HttpCacheStats,\n HttpStats,\n LookupStats,\n ObsoleteCacheHitLogger,\n PackageCacheStats,\n} from '../../util/stats.ts';\nimport { setBranchCache } from './cache.ts';\nimport { extractRepoProblems } from './common.ts';\nimport { configMigration } from './config-migration/index.ts';\nimport { ensureDependencyDashboard } from './dependency-dashboard.ts';\nimport handleError from './error.ts';\nimport { finalizeRepo } from './finalize/index.ts';\nimport { pruneStaleBranches } from './finalize/prune.ts';\nimport { initRepo } from './init/index.ts';\nimport { OnboardingState } from './onboarding/common.ts';\nimport { ensureOnboardingPr } from './onboarding/pr/index.ts';\nimport type { ExtractResult } from './process/extract-update.ts';\nimport { extractDependencies, updateRepo } from './process/index.ts';\nimport type { ProcessResult, RepositoryResult } from './result.ts';\nimport { processResult } from './result.ts';\n\n// istanbul ignore next\nexport async function renovateRepository(\n repoConfig: RenovateConfig,\n canRetry = true,\n): Promise<ProcessResult | undefined> {\n splitInit();\n\n let repoResult: ProcessResult | undefined;\n const { config, localDir, error } = await instrument(\n 'init',\n async (): Promise<{\n config: RenovateConfig;\n localDir: string;\n error?: Error;\n }> => {\n let config = GlobalConfig.set(\n applySecretsAndVariablesToConfig({\n config: repoConfig,\n deleteVariables: false,\n deleteSecrets: false,\n }),\n );\n await removeDanglingContainers();\n setMeta({ repository: config.repository });\n logger.info({ renovateVersion: pkg.version }, 'Repository started');\n logger.trace({ config });\n queue.clear();\n throttle.clear();\n const localDir = GlobalConfig.get('localDir');\n\n try {\n await ensureDir(localDir);\n logger.debug(`Using localDir: ${localDir}`);\n config = await initRepo(config);\n addSplit('init');\n } catch (err) /* istanbul ignore next */ {\n setMeta({ repository: config.repository });\n const errorRes = await handleError(config, err);\n const pruneWhenErrors = [\n REPOSITORY_DISABLED_BY_CONFIG,\n REPOSITORY_FORKED,\n REPOSITORY_NO_CONFIG,\n ];\n if (pruneWhenErrors.includes(errorRes)) {\n await pruneStaleBranches(config, []);\n }\n repoResult = processResult(config, errorRes);\n\n return { config, localDir, error: err };\n }\n\n return { config, localDir };\n },\n {\n attributes: {\n [ATTR_RENOVATE_SPLIT]: 'init',\n },\n },\n );\n\n // only continue if init stage was successful\n if (error === undefined) {\n try {\n const performExtract =\n config.repoIsOnboarded! ||\n !OnboardingState.onboardingCacheValid ||\n OnboardingState.prUpdateRequested;\n const extractResult = performExtract\n ? await extractDependencies(config)\n : emptyExtract();\n addExtractionStats(config, extractResult);\n\n const { branches, branchList, packageFiles } = extractResult;\n\n if (config.semanticCommits === 'auto') {\n config.semanticCommits = await detectSemanticCommits();\n }\n\n if (\n GlobalConfig.get('dryRun') !== 'lookup' &&\n GlobalConfig.get('dryRun') !== 'extract'\n ) {\n let res: RepositoryResult;\n if (config.repoIsOnboarded) {\n addSplit('onboarding'); // no onboarding work was needed\n res = await instrument('update', () => updateRepo(config, branches), {\n attributes: {\n [ATTR_RENOVATE_SPLIT]: 'update',\n },\n });\n setMeta({ repository: config.repository });\n } else {\n res = await instrument(\n 'onboarding',\n () => ensureOnboardingPr(config, packageFiles, branches),\n {\n attributes: {\n [ATTR_RENOVATE_SPLIT]: 'onboarding',\n },\n },\n );\n addSplit('onboarding');\n }\n addSplit('update');\n if (performExtract) {\n await setBranchCache(branches); // update branch cache if performed extraction\n }\n if (res === 'automerged') {\n if (canRetry) {\n logger.info('Restarting repository job after automerge result');\n const recursiveRes = await renovateRepository(repoConfig, false);\n return recursiveRes;\n }\n logger.debug(`Automerged but already retried once`);\n } else {\n const configMigrationRes = await configMigration(config, branchList);\n await ensureDependencyDashboard(\n config,\n branches,\n packageFiles,\n configMigrationRes,\n );\n }\n await finalizeRepo(config, branchList, repoConfig);\n repoResult = processResult(config, res);\n }\n printRepositoryProblems(config.repository);\n } catch (err) /* istanbul ignore next */ {\n setMeta({ repository: config.repository });\n const errorRes = await handleError(config, err);\n const pruneWhenErrors = [\n REPOSITORY_DISABLED_BY_CONFIG,\n REPOSITORY_FORKED,\n REPOSITORY_NO_CONFIG,\n ];\n if (pruneWhenErrors.includes(errorRes)) {\n await pruneStaleBranches(config, []);\n }\n repoResult = processResult(config, errorRes);\n }\n } else {\n logger.debug(\n { err: error },\n 'Skipping the rest to the Renovate run due to error in `init` phase',\n );\n }\n\n if (localDir && !repoConfig.persistRepoData) {\n try {\n await deleteLocalFile('.');\n } catch (err) /* istanbul ignore if */ {\n logger.warn({ err }, 'localDir deletion error');\n }\n }\n try {\n await rmCache(privateCacheDir());\n } catch (err) /* istanbul ignore if */ {\n logger.warn({ err }, 'privateCacheDir deletion error');\n }\n const splits = getSplits();\n logger.debug(splits, 'Repository timing splits (milliseconds)');\n PackageCacheStats.report();\n DatasourceCacheStats.report();\n HttpStats.report();\n HttpCacheStats.report();\n LookupStats.report();\n GetDatasourceReleasesStats.report();\n ObsoleteCacheHitLogger.report();\n AbandonedPackageStats.report();\n GitOperationStats.report();\n const cloned = isCloned();\n /* v8 ignore next -- coverage not required of these `undefined` checks, as we're happy receiving an `undefined` in the logs */\n logger.info(\n {\n cloned,\n durationMs: splits.total,\n result: repoResult?.res,\n status: repoResult?.status,\n enabled: repoResult?.enabled,\n onboarded: repoResult?.onboarded,\n exitCode: repoResult?.exitCode,\n },\n 'Repository finished',\n );\n resetRepositoryLogLevelRemaps();\n return repoResult;\n}\n\n// istanbul ignore next: renovateRepository is ignored\nfunction emptyExtract(): ExtractResult {\n return instrument(\n 'extract',\n () => {\n addSplit('extract');\n addSplit('lookup');\n return {\n branches: [],\n branchList: [getInheritedOrGlobal('onboardingBranch')!], // to prevent auto closing\n packageFiles: {},\n };\n },\n {\n attributes: {\n [ATTR_RENOVATE_SPLIT]: 'extract',\n },\n },\n );\n}\n\nexport function printRepositoryProblems(repository: string | undefined): void {\n const repoProblems = extractRepoProblems(repository);\n if (repoProblems.size) {\n logger.debug(\n { repoProblems: Array.from(repoProblems) },\n 'repository problems',\n );\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../lib/workers/repository/index.ts"],"sourcesContent":["import { GlobalConfig } from '../../config/global.ts';\nimport { applySecretsAndVariablesToConfig } from '../../config/secrets.ts';\nimport type { RenovateConfig } from '../../config/types.ts';\nimport {\n REPOSITORY_DISABLED_BY_CONFIG,\n REPOSITORY_FORKED,\n REPOSITORY_NO_CONFIG,\n} from '../../constants/error-messages.ts';\nimport { pkg } from '../../expose.ts';\nimport { instrument } from '../../instrumentation/index.ts';\nimport { addExtractionStats } from '../../instrumentation/reporting.ts';\nimport { ATTR_RENOVATE_SPLIT } from '../../instrumentation/types.ts';\nimport { logger, setMeta } from '../../logger/index.ts';\nimport { resetRepositoryLogLevelRemaps } from '../../logger/remap.ts';\nimport { getInheritedOrGlobal } from '../../util/common.ts';\nimport { removeDanglingContainers } from '../../util/exec/docker/index.ts';\nimport {\n deleteLocalFile,\n ensureDir,\n privateCacheDir,\n rmCache,\n} from '../../util/fs/index.ts';\nimport { isCloned } from '../../util/git/index.ts';\nimport { detectSemanticCommits } from '../../util/git/semantic.ts';\nimport * as queue from '../../util/http/queue.ts';\nimport * as throttle from '../../util/http/throttle.ts';\nimport { addSplit, getSplits, splitInit } from '../../util/split.ts';\nimport {\n AbandonedPackageStats,\n DatasourceCacheStats,\n GetDatasourceReleasesStats,\n GitOperationStats,\n HttpCacheStats,\n HttpStats,\n LookupStats,\n ObsoleteCacheHitLogger,\n PackageCacheStats,\n} from '../../util/stats.ts';\nimport { setBranchCache } from './cache.ts';\nimport { extractRepoProblems } from './common.ts';\nimport { configMigration } from './config-migration/index.ts';\nimport { ensureDependencyDashboard } from './dependency-dashboard.ts';\nimport handleError from './error.ts';\nimport { finalizeRepo } from './finalize/index.ts';\nimport { pruneStaleBranches } from './finalize/prune.ts';\nimport { initRepo } from './init/index.ts';\nimport { OnboardingState } from './onboarding/common.ts';\nimport { ensureOnboardingPr } from './onboarding/pr/index.ts';\nimport type { ExtractResult } from './process/extract-update.ts';\nimport { extractDependencies, updateRepo } from './process/index.ts';\nimport type { ProcessResult, RepositoryResult } from './result.ts';\nimport { processResult } from './result.ts';\n\n// istanbul ignore next\nexport async function renovateRepository(\n repoConfig: RenovateConfig,\n canRetry = true,\n): Promise<ProcessResult | undefined> {\n splitInit();\n\n let repoResult: ProcessResult | undefined;\n const { config, localDir, error } = await instrument(\n 'init',\n async (): Promise<{\n config: RenovateConfig;\n localDir: string;\n error?: Error;\n }> => {\n let config = GlobalConfig.set(\n applySecretsAndVariablesToConfig({\n config: repoConfig,\n deleteVariables: false,\n deleteSecrets: false,\n }),\n );\n await removeDanglingContainers();\n setMeta({ repository: config.repository });\n logger.info({ renovateVersion: pkg.version }, 'Repository started');\n logger.trace({ config });\n queue.clear();\n throttle.clear();\n const localDir = GlobalConfig.get('localDir');\n\n try {\n await ensureDir(localDir);\n logger.debug(`Using localDir: ${localDir}`);\n config = await initRepo(config);\n addSplit('init');\n } catch (err) /* istanbul ignore next */ {\n setMeta({ repository: config.repository });\n const errorRes = await handleError(config, err);\n const pruneWhenErrors = [\n REPOSITORY_DISABLED_BY_CONFIG,\n REPOSITORY_FORKED,\n REPOSITORY_NO_CONFIG,\n ];\n if (pruneWhenErrors.includes(errorRes)) {\n await pruneStaleBranches(config, []);\n }\n repoResult = processResult(config, errorRes);\n\n return { config, localDir, error: err };\n }\n\n return { config, localDir };\n },\n {\n attributes: {\n [ATTR_RENOVATE_SPLIT]: 'init',\n },\n },\n );\n\n // only continue if init stage was successful\n if (error === undefined) {\n try {\n const performExtract =\n config.repoIsOnboarded! ||\n !OnboardingState.onboardingCacheValid ||\n OnboardingState.prUpdateRequested;\n const extractResult = performExtract\n ? await extractDependencies(config)\n : emptyExtract();\n addExtractionStats(config, extractResult);\n\n const { branches, branchList, packageFiles } = extractResult;\n\n if (config.semanticCommits === 'auto') {\n config.semanticCommits = await detectSemanticCommits();\n }\n\n if (\n GlobalConfig.get('dryRun') !== 'lookup' &&\n GlobalConfig.get('dryRun') !== 'extract'\n ) {\n let res: RepositoryResult;\n if (config.repoIsOnboarded) {\n addSplit('onboarding'); // no onboarding work was needed\n res = await instrument('update', () => updateRepo(config, branches), {\n attributes: {\n [ATTR_RENOVATE_SPLIT]: 'update',\n },\n });\n setMeta({ repository: config.repository });\n } else {\n res = await instrument(\n 'onboarding',\n () => ensureOnboardingPr(config, packageFiles, branches),\n {\n attributes: {\n [ATTR_RENOVATE_SPLIT]: 'onboarding',\n },\n },\n );\n addSplit('onboarding');\n }\n addSplit('update');\n if (performExtract) {\n await setBranchCache(branches); // update branch cache if performed extraction\n }\n if (res === 'automerged') {\n if (canRetry) {\n logger.info('Restarting repository job after automerge result');\n const recursiveRes = await renovateRepository(repoConfig, false);\n return recursiveRes;\n }\n logger.debug(`Automerged but already retried once`);\n } else {\n const configMigrationRes = await configMigration(config, branchList);\n await ensureDependencyDashboard(\n config,\n branches,\n packageFiles,\n configMigrationRes,\n );\n }\n await finalizeRepo(config, branchList, repoConfig);\n repoResult = processResult(config, res);\n }\n printRepositoryProblems(config.repository);\n } catch (err) /* istanbul ignore next */ {\n setMeta({ repository: config.repository });\n const errorRes = await handleError(config, err);\n const pruneWhenErrors = [\n REPOSITORY_DISABLED_BY_CONFIG,\n REPOSITORY_FORKED,\n REPOSITORY_NO_CONFIG,\n ];\n if (pruneWhenErrors.includes(errorRes)) {\n await pruneStaleBranches(config, []);\n }\n repoResult = processResult(config, errorRes);\n }\n } else {\n logger.debug(\n { err: error },\n 'Skipping the rest to the Renovate run due to error in `init` phase',\n );\n }\n\n if (localDir && !repoConfig.persistRepoData) {\n try {\n await deleteLocalFile('.');\n } catch (err) /* istanbul ignore if */ {\n logger.warn({ err }, 'localDir deletion error');\n }\n }\n try {\n await rmCache(privateCacheDir());\n } catch (err) /* istanbul ignore if */ {\n logger.warn({ err }, 'privateCacheDir deletion error');\n }\n const splits = getSplits();\n logger.debug(splits, 'Repository timing splits (milliseconds)');\n PackageCacheStats.report();\n DatasourceCacheStats.report();\n HttpStats.report();\n HttpCacheStats.report();\n LookupStats.report();\n GetDatasourceReleasesStats.report();\n ObsoleteCacheHitLogger.report();\n AbandonedPackageStats.report();\n GitOperationStats.report();\n const cloned = isCloned();\n /* v8 ignore next -- coverage not required of these `undefined` checks, as we're happy receiving an `undefined` in the logs */\n logger.info(\n {\n cloned,\n durationMs: splits.total,\n result: repoResult?.res,\n status: repoResult?.status,\n enabled: repoResult?.enabled,\n onboarded: repoResult?.onboarded,\n exitCode: repoResult?.exitCode,\n },\n 'Repository finished',\n );\n resetRepositoryLogLevelRemaps();\n return repoResult;\n}\n\n// istanbul ignore next: renovateRepository is ignored\nfunction emptyExtract(): ExtractResult {\n return instrument(\n 'extract',\n () => {\n addSplit('extract');\n addSplit('lookup');\n return {\n branches: [],\n branchList: [getInheritedOrGlobal('onboardingBranch')!], // to prevent auto closing\n packageFiles: {},\n };\n },\n {\n attributes: {\n [ATTR_RENOVATE_SPLIT]: 'extract',\n },\n },\n );\n}\n\nexport function printRepositoryProblems(repository: string | undefined): void {\n const repoProblems = extractRepoProblems(repository);\n // v8 ignore else -- only called when the repository logged a problem\n if (repoProblems.size) {\n logger.debug(\n { repoProblems: Array.from(repoProblems) },\n 'repository problems',\n );\n }\n}\n"],"mappings":"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"}
|
|
@@ -354,6 +354,7 @@ async function mergeRenovateConfig(config, branchName) {
|
|
|
354
354
|
checkForRepoConfigError(repoConfig);
|
|
355
355
|
const migratedConfig = await migrateAndValidate(config, resolvedRepoConfig);
|
|
356
356
|
if (migratedConfig.errors?.length) throwConfigValidationError(repoConfig.configFileName, migratedConfig.errors);
|
|
357
|
+
// v8 ignore else -- migration always leaves a warnings array behind
|
|
357
358
|
if (migratedConfig.warnings) returnConfig.warnings = [...coerceArray(returnConfig.warnings), ...migratedConfig.warnings];
|
|
358
359
|
delete migratedConfig.errors;
|
|
359
360
|
delete migratedConfig.warnings;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"merge.js","names":["configValidation.validateConfig","hostRules.matchesHost","presets.resolveConfigPresets"],"sources":["../../../../lib/workers/repository/init/merge.ts"],"sourcesContent":["import {\n isNonEmptyArray,\n isNonEmptyObject,\n isNonEmptyString,\n isString,\n isUndefined,\n} from '@sindresorhus/is';\nimport { dequal } from 'dequal';\nimport { getConfigFileNames } from '../../../config/app-strings.ts';\nimport { decryptConfig } from '../../../config/decrypt.ts';\nimport { mergeChildConfig } from '../../../config/index.ts';\nimport { massageConfig } from '../../../config/massage.ts';\nimport { migrateAndValidate } from '../../../config/migrate-validate.ts';\nimport { migrateConfig } from '../../../config/migration.ts';\nimport { parseFileConfig } from '../../../config/parse.ts';\nimport * as presets from '../../../config/presets/index.ts';\nimport { applySecretsAndVariablesToConfig } from '../../../config/secrets.ts';\nimport type {\n AllConfig,\n MigratedConfig,\n RenovateConfig,\n ValidationMessage,\n} from '../../../config/types.ts';\nimport * as configValidation from '../../../config/validation.ts';\nimport { ConfigValidationTopic } from '../../../config/validation-helpers/types.ts';\nimport {\n CONFIG_VALIDATION,\n REPOSITORY_CHANGED,\n} from '../../../constants/error-messages.ts';\nimport { pkg } from '../../../expose.ts';\nimport { logger } from '../../../logger/index.ts';\nimport * as npmApi from '../../../modules/datasource/npm/index.ts';\nimport { platform } from '../../../modules/platform/index.ts';\nimport { scm } from '../../../modules/platform/scm.ts';\nimport { ExternalHostError } from '../../../types/errors/external-host-error.ts';\nimport type { HostRule } from '../../../types/index.ts';\nimport { coerceArray } from '../../../util/array.ts';\nimport { getCache } from '../../../util/cache/repository/index.ts';\nimport { clone } from '../../../util/clone.ts';\nimport { getInheritedOrGlobal, parseJson } from '../../../util/common.ts';\nimport { setUserEnv } from '../../../util/env.ts';\nimport { readLocalFile, readSystemFile } from '../../../util/fs/index.ts';\nimport * as hostRules from '../../../util/host-rules.ts';\nimport * as queue from '../../../util/http/queue.ts';\nimport * as throttle from '../../../util/http/throttle.ts';\nimport { maskToken } from '../../../util/mask.ts';\nimport { coerceObject } from '../../../util/object.ts';\nimport { regEx } from '../../../util/regex.ts';\nimport { coerceString } from '../../../util/string.ts';\nimport { safeStringify } from '../../../util/stringify.ts';\nimport { parseUrl } from '../../../util/url.ts';\nimport { getOnboardingConfig } from '../onboarding/branch/config.ts';\nimport {\n getOnboardingConfigFromCache,\n getOnboardingFileNameFromCache,\n setOnboardingConfigDetails,\n} from '../onboarding/branch/onboarding-branch-cache.ts';\nimport {\n OnboardingState,\n getDefaultConfigFileName,\n} from '../onboarding/common.ts';\nimport { filterAllowedEnv } from './filter-allowed-env.ts';\nimport type { RepoFileConfig, RepositoryWorkerConfig } from './types.ts';\n\nexport async function detectConfigFile(): Promise<string | null> {\n const fileList = await scm.getFileList();\n for (const fileName of getConfigFileNames()) {\n if (fileName === 'package.json') {\n try {\n const pJson = JSON.parse(\n (await readLocalFile('package.json', 'utf8'))!,\n );\n if (pJson.renovate) {\n logger.warn(\n 'Using package.json for Renovate config is deprecated - please use a dedicated configuration file instead',\n );\n return 'package.json';\n }\n } catch {\n // Do nothing\n }\n } else if (fileList.includes(fileName)) {\n return fileName;\n }\n }\n return null;\n}\n\nexport async function detectRepoFileConfig(\n branchName?: string,\n): Promise<RepoFileConfig> {\n const cache = getCache();\n let { configFileName } = cache;\n if (isNonEmptyString(configFileName)) {\n let configFileRaw: string | null;\n try {\n configFileRaw = await platform.getRawFile(\n configFileName,\n undefined,\n branchName,\n );\n } catch (err) {\n // istanbul ignore if\n if (err instanceof ExternalHostError) {\n throw err;\n }\n configFileRaw = null;\n }\n if (configFileRaw) {\n let configFileParsed = parseJson(configFileRaw, configFileName) as any;\n if (configFileName === 'package.json') {\n configFileParsed = configFileParsed.renovate;\n }\n return { configFileName, configFileParsed };\n }\n logger.debug('Existing config file no longer exists');\n delete cache.configFileName;\n }\n\n if (OnboardingState.onboardingCacheValid) {\n configFileName = getOnboardingFileNameFromCache();\n } else {\n configFileName = coerceString(await detectConfigFile());\n }\n\n if (!configFileName) {\n logger.debug('No renovate config file found');\n cache.configFileName = '';\n return {};\n }\n cache.configFileName = configFileName;\n logger.debug(`Found ${configFileName} config file`);\n // TODO #22198\n let configFileParsed: any;\n let configFileRaw: string | undefined | null;\n\n if (OnboardingState.onboardingCacheValid) {\n const cachedConfig = getOnboardingConfigFromCache();\n const parsedConfig = cachedConfig ? JSON.parse(cachedConfig) : undefined;\n if (parsedConfig) {\n setOnboardingConfigDetails(configFileName, JSON.stringify(parsedConfig));\n return { configFileName, configFileParsed: parsedConfig };\n }\n }\n\n if (configFileName === 'package.json') {\n // We already know it parses\n configFileParsed = JSON.parse(\n // TODO #22198\n (await readLocalFile('package.json', 'utf8'))!,\n ).renovate;\n if (isString(configFileParsed)) {\n logger.debug('Massaging string renovate config to extends array');\n configFileParsed = { extends: [configFileParsed] };\n }\n logger.debug({ config: configFileParsed }, 'package.json>renovate config');\n } else {\n configFileRaw = await readLocalFile(configFileName, 'utf8');\n // istanbul ignore if\n if (!isString(configFileRaw)) {\n logger.warn({ configFileName }, 'Null contents when reading config file');\n throw new Error(REPOSITORY_CHANGED);\n }\n // istanbul ignore if\n if (!configFileRaw.length) {\n configFileRaw = '{}';\n }\n\n const parseResult = parseFileConfig(configFileName, configFileRaw);\n\n if (!parseResult.success) {\n return {\n configFileName,\n configFileParseError: {\n validationError: parseResult.validationError,\n validationMessage: parseResult.validationMessage,\n },\n };\n }\n configFileParsed = parseResult.parsedContents;\n logger.debug(\n { fileName: configFileName, config: configFileParsed },\n 'Repository config',\n );\n }\n\n setOnboardingConfigDetails(configFileName, JSON.stringify(configFileParsed));\n return { configFileName, configFileParsed };\n}\n\nexport function checkForRepoConfigError(repoConfig: RepoFileConfig): void {\n if (!repoConfig.configFileParseError) {\n return;\n }\n const error = new Error(CONFIG_VALIDATION);\n error.validationSource = repoConfig.configFileName;\n error.validationError = repoConfig.configFileParseError.validationError;\n error.validationMessage = repoConfig.configFileParseError.validationMessage;\n throw error;\n}\n\n/**\n * Validation source for `repositories[]` object-entry config.\n *\n * As these are managed by the self-hosted admin's global config (`config.js`, or through environment variables, CLI options) we shouldn't report this as an issue the repo owner has introduced.\n */\nconst repositoriesEntrySource = 'Self-hosted config (`repositories[]`)';\n\nconst repoFileValidationError =\n 'The Renovate configuration file contains some invalid settings';\n\nconst repositoriesEntryValidationError =\n 'The self-hosted `repositories[]` config contains some invalid settings';\n\nfunction throwConfigValidationError(\n validationSource: string | undefined,\n errors: ValidationMessage[],\n validationError = repoFileValidationError,\n): never {\n const error = new Error(CONFIG_VALIDATION);\n error.validationSource = validationSource;\n error.validationError = validationError;\n error.validationMessage = errors.map((e) => e.message).join(', ');\n throw error;\n}\n\n/**\n * Validate a fully-resolved config (i.e. after `resolveConfigPresets`).\n *\n * If there are top-level `allowedEnv`/`allowedHeaders` violations, these are reported with `ConfigValidationTopic.Security` and always fail a validation, as they are sensitive config options that need to be blocked.\n *\n * All other issues will be a WARN, unless `configValidationError=true`, because these are resolved config options and may not be in control of the repository owner.\n *\n * `validationSource` is reported to the user; use `repositoriesEntrySource` and `repositoriesEntryValidationError` for admin-controlled object entries so a fault is not blamed on the repo owner.\n */\nasync function validateResolvedConfig(\n resolved: RenovateConfig,\n validationSource: string | undefined,\n strict: boolean,\n validationError?: string,\n): Promise<void> {\n const { errors, warnings } = await configValidation.validateConfig(\n 'repo',\n // `validateConfig` expects massaged input\n massageConfig(resolved),\n );\n\n // Security findings are collected from the warnings too: `validateConfig` folds the results of the sub-validations it runs (notably `onboardingConfig`) into its warnings, and a finding is no less real for having been reported from within one\n const securityErrors = [...errors, ...warnings].filter(\n (err) => err.topic === ConfigValidationTopic.Security,\n );\n const otherErrors = errors.filter(\n (err) => err.topic !== ConfigValidationTopic.Security,\n );\n const otherWarnings = warnings.filter(\n (err) => err.topic !== ConfigValidationTopic.Security,\n );\n\n // before throwing, make sure that any other errors or warnings are logged, as there may be important findings\n if (otherErrors.length || otherWarnings.length) {\n logger.debug(\n { errors: otherErrors, warnings: otherWarnings },\n 'Config validation failed on resolved config, for non-security-sensitive reasons',\n );\n }\n\n if (securityErrors.length) {\n throwConfigValidationError(\n validationSource,\n securityErrors,\n validationError,\n );\n }\n if (strict && otherErrors.length) {\n throwConfigValidationError(validationSource, otherErrors, validationError);\n }\n}\n\n/**\n * Identify a single `env` variable, or a single header of a host rule, by name and value.\n *\n * As `env` is replaced wholesale and `hostRules` is `mergeable`, self-hosted config and repo config end up indistinguishable in the resolved config, so we need a stable way to look a given name and value up.\n */\nfunction nameValueIdentity(name: string, value: string): string {\n // use safeStringify to avoid any potential for an attacker-controlled value to attempt to try and fake the separator and inject in their value as priority\n return safeStringify([name, value]);\n}\n\n/**\n * Index a set of host rules' headers by {@link nameValueIdentity}, recording the `matchHost` values each is set for (`null` for a host-less rule, which matches every host).\n */\nfunction headersByIdentity(\n rules: HostRule[] | undefined,\n): Map<string, Set<string | null>> {\n const result = new Map<string, Set<string | null>>();\n for (const rule of coerceArray(rules)) {\n for (const [name, value] of Object.entries(coerceObject(rule.headers))) {\n const identity = nameValueIdentity(name, value);\n const hosts = result.get(identity) ?? new Set<string | null>();\n hosts.add(rule.matchHost ?? null);\n result.set(identity, hosts);\n }\n }\n return result;\n}\n\n/**\n * Whether every request matched by `matchHost` is also matched by `adminMatchHost` - i.e. a rule scoped to `matchHost` cannot reach any host the admin's own rule does not already reach.\n *\n * A bare hostname is compared as its `https://` URL. `matchesHost` treats a bare `adminMatchHost` as also covering its subdomains, which errs on the admin-friendly side: those hosts sit within the admin's own domain.\n */\nfunction isWithinHost(matchHost: string, adminMatchHost: string): boolean {\n const url = parseUrl(matchHost) ? matchHost : `https://${matchHost}`;\n return hostRules.matchesHost(url, adminMatchHost);\n}\n\n/**\n * Migrate a config, tolerating a migration which throws.\n *\n * `hostRules` migration throws when a rule carries more than one host-matching field. That is per-rule invalid config which {@link applyHostRules} logs and skips over, keeping the rest of the run going, so migrating a whole config here must not escalate it into an error which aborts the repository.\n */\nfunction migrateConfigOrWarn(config: RenovateConfig): MigratedConfig {\n try {\n return migrateConfig(config);\n } catch (err) {\n logger.warn({ err }, 'Error migrating config');\n return { isMigrated: false, migratedConfig: config };\n }\n}\n\n/**\n * The security-sensitive values (`env`, and `hostRules[].headers`) the self-hosted admin supplied, indexed by {@link nameValueIdentity}; the headers additionally record the `matchHost` values each was set for.\n *\n * `mergeChildConfig` promotes `force` values to the top level, so each config contributes its `force` alongside its top-level values.\n */\ninterface AdminSuppliedValues {\n env: Set<string>;\n headers: Map<string, Set<string | null>>;\n /** the `allowInternal` values ('true'/'false') the admin set, recording the `matchHost` values each is set for (`null` for a host-less rule) */\n internalGrants: Map<string, Set<string | null>>;\n}\n\n/**\n * Migrate a set of host rules, so that their `matchHost` compares like for like against the resolved config's own: migration rewrites them (e.g. a legacy `hostName` becoming a `matchHost`, or a bare `matchHost` gaining a scheme), and the resolved config only ever contains the migrated spellings.\n */\nfunction migratedHostRules(rules: HostRule[] | undefined): HostRule[] {\n if (!isNonEmptyArray(rules)) {\n return [];\n }\n return coerceArray(\n migrateConfigOrWarn({ hostRules: rules }).migratedConfig.hostRules,\n );\n}\n\n/**\n * Collect the {@link AdminSuppliedValues} of every config the self-hosted admin supplied.\n *\n * A preset is only ever resolved into the config which extends it, so a config here is the *resolved* form of an admin config: whatever the presets the admin chose to extend contribute is as much theirs as a value they wrote inline.\n */\nfunction adminSuppliedValues(\n adminConfigs: RenovateConfig[],\n): AdminSuppliedValues {\n const env = new Set<string>();\n const headers = new Map<string, Set<string | null>>();\n const internalGrants = new Map<string, Set<string | null>>();\n\n for (const adminConfig of adminConfigs) {\n for (const source of [adminConfig, adminConfig.force]) {\n for (const [name, value] of Object.entries(coerceObject(source?.env))) {\n env.add(nameValueIdentity(name, value));\n }\n const rules = migratedHostRules(source?.hostRules);\n for (const [identity, matchHosts] of headersByIdentity(rules)) {\n const hosts = headers.get(identity) ?? new Set<string | null>();\n for (const matchHost of matchHosts) {\n hosts.add(matchHost);\n }\n headers.set(identity, hosts);\n }\n for (const rule of rules) {\n if (!isUndefined(rule.allowInternal)) {\n const key = rule.allowInternal.toString();\n const hosts = internalGrants.get(key) ?? new Set<string | null>();\n hosts.add(rule.matchHost ?? null);\n internalGrants.set(key, hosts);\n }\n }\n }\n }\n\n return { env, headers, internalGrants };\n}\n\n/**\n * Return `resolved` without the security-sensitive (`env` and `hostRules[].headers`) values the self-hosted admin supplied themselves.\n *\n * `allowedEnv`/`allowedHeaders` exist to constrain what repository config, and the presets it extends, may inject; the self-hosted admin is who sets those allowlists, so their own values are not violations of them.\n *\n * Reporting them would abort the repository and file a \"Fix Renovate Configuration\" issue whose cause the repository's owners can neither see nor fix.\n */\nfunction withoutAdminSuppliedValues(\n resolved: RenovateConfig,\n admin: AdminSuppliedValues,\n): RenovateConfig {\n const result = { ...resolved };\n\n if (result.env) {\n result.env = Object.fromEntries(\n Object.entries(result.env).filter(\n ([name, value]) => !admin.env.has(nameValueIdentity(name, value)),\n ),\n );\n }\n\n // A header is the admin's own when its name and value match one the admin set for hosts that already cover this rule's hosts - the exact `matchHost` spelling must not matter, as migration and presets can re-spell (e.g. add a scheme) or narrow (e.g. a subpath) it\n if (result.hostRules) {\n result.hostRules = result.hostRules.map((rule) => {\n const filtered: HostRule = {\n ...rule,\n headers: Object.fromEntries(\n Object.entries(coerceObject(rule.headers)).filter(([name, value]) => {\n const adminHosts = admin.headers.get(\n nameValueIdentity(name, value),\n );\n if (!adminHosts) {\n // not a header the admin set - report it\n return true;\n }\n if (adminHosts.has(null)) {\n // the admin already sends it to every host\n return false;\n }\n // a host-less rule reaches every host, so only a host-less admin header (above) can exempt it\n return !(\n rule.matchHost &&\n [...adminHosts].some(\n (adminHost) =>\n adminHost !== null &&\n isWithinHost(rule.matchHost!, adminHost),\n )\n );\n }),\n ),\n };\n\n // same principle for `allowInternal`: the admin's own value, for hosts their own rules already cover, is not a violation\n if (!isUndefined(filtered.allowInternal)) {\n const adminHosts = admin.internalGrants.get(\n filtered.allowInternal.toString(),\n );\n const covered =\n adminHosts &&\n (adminHosts.has(null) ||\n (!!filtered.matchHost &&\n [...adminHosts].some(\n (adminHost) =>\n adminHost !== null &&\n isWithinHost(filtered.matchHost!, adminHost),\n )));\n if (covered) {\n delete filtered.allowInternal;\n }\n }\n\n return filtered;\n });\n }\n\n // `mergeChildConfig` promotes `force` values into the config it returns, so the admin's own `force.env`/`force.hostRules[].headers` are applied - and exempted - the same way their top-level equivalents are\n if (result.force) {\n result.force = withoutAdminSuppliedValues(result.force, admin);\n }\n\n return result;\n}\n\n// Check for repository config\nexport async function mergeRenovateConfig(\n config: RepositoryWorkerConfig,\n branchName?: string,\n): Promise<RenovateConfig> {\n let returnConfig: RepositoryWorkerConfig = { ...config };\n let repoConfig: RepoFileConfig = {};\n if (getInheritedOrGlobal('requireConfig') !== 'ignored') {\n repoConfig = await detectRepoFileConfig(branchName);\n }\n if (!repoConfig.configFileParsed && config.mode === 'silent') {\n logger.debug(\n 'When mode=silent and repo has no config file, we use the onboarding config as repo config',\n );\n const configFileName = getDefaultConfigFileName();\n repoConfig = {\n configFileName,\n configFileParsed: await getOnboardingConfig(config),\n };\n }\n const configFileParsed = coerceObject(repoConfig?.configFileParsed);\n const resolvedRepoConfig = await resolveStaticRepoConfig(\n configFileParsed,\n process.env.RENOVATE_X_STATIC_REPO_CONFIG_FILE,\n );\n\n // Apply the repositories[] object-entry config between global config and\n // repository file config.\n // Must run after repository file config is loaded so its `ignorePresets` can\n // be included when resolving object-entry presets.\n const repoEntryConfig = returnConfig.repositoryEntryConfig;\n delete returnConfig.repositoryEntryConfig;\n\n // The presets the self-hosted admin's own config extends are their config too - a repository which merely inherits them must neither be blamed for what they contribute, nor have it filtered out from under it.\n // They are resolved separately because below they are resolved together with the repository's own presets, leaving no way to tell one from the other; a failure here is left to that resolution to report, as it is the one whose result is used.\n let adminPresetConfig: AllConfig = {};\n if (isNonEmptyArray(returnConfig.extends)) {\n try {\n ({ config: adminPresetConfig } = await presets.resolveConfigPresets(\n { extends: returnConfig.extends },\n config,\n config.ignorePresets,\n ));\n } catch (err) {\n logger.debug(\n { err },\n 'Error resolving the self-hosted config presets - continuing without their exemption',\n );\n }\n }\n\n // self-hosted configuration is always allowed\n // `force.env` is included because `mergeChildConfig` promotes `force` values to the top level as configs are merged\n const adminSuppliedEnv = {\n // presets the admin extends: as much theirs as anything they set inline, which is why they are listed first - the values they set themselves win\n ...coerceObject(adminPresetConfig.env),\n ...coerceObject(adminPresetConfig.force?.env),\n // `env` settings the self-hosted admin supplied (via `config.js`, etc), `env`, etc\n ...coerceObject(config.env),\n ...coerceObject(config.force?.env),\n // `repositories[]` entry for this repo - refreshed with the resolved values below, once its own presets, secrets and variables have been applied\n ...coerceObject(repoEntryConfig?.env),\n ...coerceObject(repoEntryConfig?.force?.env),\n };\n\n // every config the self-hosted admin supplied, in resolved form, for {@link adminSuppliedValues}\n const adminConfigs: RenovateConfig[] = [config, adminPresetConfig];\n\n if (isNonEmptyObject(repoEntryConfig)) {\n const repoEntry = repoEntryConfig as RenovateConfig;\n const toResolve: RenovateConfig = {\n ...repoEntry,\n extends: [\n ...coerceArray(returnConfig.extends),\n ...coerceArray(repoEntry.extends),\n ],\n ignorePresets: [\n ...coerceArray(returnConfig.ignorePresets),\n ...coerceArray(repoEntry.ignorePresets),\n ...coerceArray(resolvedRepoConfig.ignorePresets),\n ],\n };\n delete returnConfig.extends;\n\n let { config: resolvedRepoEntry } = await presets.resolveConfigPresets(\n toResolve,\n config,\n );\n\n // Migrate before validating so legacy option names contributed by the entry or its presets are migrated rather than reported as invalid options.\n const entryMigration = migrateConfigOrWarn(resolvedRepoEntry);\n if (entryMigration.isMigrated) {\n resolvedRepoEntry = entryMigration.migratedConfig;\n }\n\n // Migrate the entry's own config the same way, so its values compare like for like below: migration can rewrite them (e.g. a legacy `hostName` becoming a `matchHost`, or a bare `matchHost` gaining a scheme), and the resolved config only ever contains the migrated spellings\n const { migratedConfig: migratedEntry } = migrateConfigOrWarn(toResolve);\n // `resolveConfigPresets` removes both of these from its result\n delete migratedEntry.extends;\n delete migratedEntry.ignorePresets;\n\n // The entry, and every preset it extends, is the self-hosted admin's own config, so its `env`/`headers` are exempt from the allowlists the admin set - but the rest of the resolved result is still worth validating before any of it is applied (npmrc, hostRules, env).\n // When resolution and migration changed nothing, the presets contributed nothing and the entry itself was already validated as part of the admin's global config, so skip the (costly) validation walk entirely.\n adminConfigs.push(resolvedRepoEntry);\n if (!dequal(resolvedRepoEntry, migratedEntry)) {\n await validateResolvedConfig(\n withoutAdminSuppliedValues(\n resolvedRepoEntry,\n adminSuppliedValues(adminConfigs),\n ),\n repositoriesEntrySource,\n config.configValidationError === true,\n repositoriesEntryValidationError,\n );\n }\n\n applyNpmrc(resolvedRepoEntry, 'resolvedRepoEntry');\n\n const resolvedRepoEntryWithSecrets = applySecretsAndVariablesToConfig({\n config: resolvedRepoEntry,\n // like the repository config below, the entry can carry its own `secrets`/`variables` - `validateConfigSecretsAndVariables` validates them at startup\n secrets: mergeChildConfig(\n coerceObject(config.secrets),\n coerceObject(resolvedRepoEntry.secrets),\n ),\n variables: mergeChildConfig(\n coerceObject(config.variables),\n coerceObject(resolvedRepoEntry.variables),\n ),\n });\n\n // Refresh the admin-supplied snapshot from the resolved entry: it also carries whatever the presets the entry extends contributed, and its `env` values may contain `{{ secrets.* }}`/`{{ variables.* }}` templates only interpolated here - e.g. when the secrets are defined on the entry itself rather than globally.\n // Interpolation is recursive, so the interpolated `force.env` values stay nested under `force`.\n Object.assign(\n adminSuppliedEnv,\n coerceObject(resolvedRepoEntryWithSecrets.env),\n coerceObject(resolvedRepoEntryWithSecrets.force?.env),\n );\n\n // the `repositories[]` entry is the self-hosted admin's own config - as its `env` is already treated as admin-supplied, its rules are `trusted` too, so that an admin can still override a header they set globally for just this repository\n applyHostRules(resolvedRepoEntryWithSecrets, { trusted: true });\n returnConfig = mergeChildConfig(returnConfig, resolvedRepoEntryWithSecrets);\n }\n\n if (isNonEmptyArray(returnConfig.extends)) {\n resolvedRepoConfig.extends = [\n ...coerceArray(returnConfig.extends),\n ...coerceArray(resolvedRepoConfig.extends),\n ];\n delete returnConfig.extends;\n }\n checkForRepoConfigError(repoConfig);\n const migratedConfig = await migrateAndValidate(config, resolvedRepoConfig);\n if (migratedConfig.errors?.length) {\n throwConfigValidationError(\n repoConfig.configFileName,\n migratedConfig.errors,\n );\n }\n if (migratedConfig.warnings) {\n returnConfig.warnings = [\n ...coerceArray(returnConfig.warnings),\n ...migratedConfig.warnings,\n ];\n }\n delete migratedConfig.errors;\n delete migratedConfig.warnings;\n // TODO #22198\n const repository = config.repository!;\n // Decrypt before resolving in case we need npm authentication for any presets\n const decryptedConfig = await decryptConfig(migratedConfig, repository);\n applyNpmrc(decryptedConfig, 'decrypted');\n\n // NOTE that this should not be used with any other configuration (`resolvedConfig`, etc) below, as they will include addditionally merged configuration\n // Decrypted secrets are sanitised, so should be safe to log\n await logShallowConfig(decryptedConfig, config);\n\n // Decrypt after resolving in case the preset contains npm authentication instead\n const { config: configToDecrypt } = await presets.resolveConfigPresets(\n decryptedConfig,\n config,\n config.ignorePresets,\n );\n let resolvedConfig = await decryptConfig(configToDecrypt, repository);\n logger.trace({ config: resolvedConfig }, 'resolved config');\n const migrationResult = migrateConfig(resolvedConfig);\n if (migrationResult.isMigrated) {\n logger.debug('Resolved config needs migrating');\n logger.trace({ config: resolvedConfig }, 'resolved config after migrating');\n resolvedConfig = migrationResult.migratedConfig;\n }\n\n // Validate the fully-resolved repository config, enforcing validation is applied against all stages of the preset, and providing defence-in-depth for any sensitive config options\n // note that we do not need to re-run `migrateAndValidate` if we're already at the same configuration that we've previously resolved, decrypted and migrated, so we can avoid a costly re-validation\n if (!dequal(resolvedConfig, migratedConfig)) {\n await validateResolvedConfig(\n // the admin's own `extends` are resolved into this config alongside the repository's, so exempt what they contributed: the repository can neither see nor fix it\n withoutAdminSuppliedValues(\n resolvedConfig,\n adminSuppliedValues(adminConfigs),\n ),\n // a repository that is not yet onboarded has no config file to blame; 'config' mirrors other unattributable validation errors (e.g. `decryptConfig`)\n repoConfig.configFileName ?? 'config',\n config.configValidationError === true,\n );\n }\n if (isString(resolvedConfig.npmrc)) {\n logger.debug(\n 'Ignoring any .npmrc files in repository due to configured npmrc',\n );\n }\n applyNpmrc(resolvedConfig, 'resolved');\n resolvedConfig = applySecretsAndVariablesToConfig({\n config: resolvedConfig,\n secrets: mergeChildConfig(\n coerceObject(config.secrets),\n coerceObject(resolvedConfig.secrets),\n ),\n variables: mergeChildConfig(\n coerceObject(config.variables),\n coerceObject(resolvedConfig.variables),\n ),\n });\n\n applyHostRules(resolvedConfig);\n returnConfig = mergeChildConfig(returnConfig, resolvedConfig);\n ({ config: returnConfig } = await presets.resolveConfigPresets(\n returnConfig,\n config,\n ));\n returnConfig.renovateJsonPresent = true;\n // istanbul ignore if\n if (returnConfig.ignorePaths?.length) {\n logger.debug(\n { ignorePaths: returnConfig.ignorePaths },\n `Found repo ignorePaths`,\n );\n }\n\n setUserEnv(filterAllowedEnv(returnConfig.env, adminSuppliedEnv));\n delete returnConfig.env;\n\n return returnConfig;\n}\n\nexport function applyNpmrc(\n config: RenovateConfig,\n configType?: 'resolved' | 'resolvedRepoEntry' | 'decrypted',\n): void {\n setNpmTokenInNpmrc(config);\n if (!isString(config.npmrc)) {\n return;\n }\n logger.debug(\n `Setting npmrc from ${configType ? `${configType} ` : ''}config`,\n );\n npmApi.setNpmrc(config.npmrc);\n}\n\nexport function applyHostRules(\n config: RenovateConfig,\n options?: hostRules.AddHostRuleOptions,\n): void {\n if (!config.hostRules) {\n return;\n }\n\n logger.debug('Setting hostRules from config');\n // `hostRules.add` enforces `allowedHeaders` on every rule it registers\n for (const rule of config.hostRules) {\n try {\n hostRules.add(rule, options);\n } catch (err) {\n logger.warn({ err, config: rule }, 'Error setting hostRule from config');\n }\n }\n // host rules can change concurrency\n queue.clear();\n throttle.clear();\n delete config.hostRules;\n}\n\n/** needed when using portal secrets for npmToken */\nexport function setNpmTokenInNpmrc(config: RenovateConfig): void {\n if (!isString(config.npmToken)) {\n return;\n }\n\n const token = config.npmToken;\n logger.debug({ npmToken: maskToken(token) }, 'Migrating npmToken to npmrc');\n\n if (!isString(config.npmrc)) {\n logger.debug('Adding npmrc to config');\n config.npmrc = `//registry.npmjs.org/:_authToken=${token}\\n`;\n delete config.npmToken;\n return;\n }\n\n if (config.npmrc.includes(`\\${NPM_TOKEN}`)) {\n logger.debug(`Replacing \\${NPM_TOKEN} with npmToken`);\n config.npmrc = config.npmrc.replace(regEx(/\\${NPM_TOKEN}/g), token);\n } else {\n logger.debug('Appending _authToken= to end of existing npmrc');\n config.npmrc = config.npmrc.replace(\n regEx(/\\n?$/),\n `\\n_authToken=${token}\\n`,\n );\n }\n\n delete config.npmToken;\n}\n\nexport async function resolveStaticRepoConfig(\n config: AllConfig,\n filename: string | undefined,\n): Promise<AllConfig> {\n if (!isNonEmptyString(filename)) {\n return config;\n }\n\n let staticRepoConfig: AllConfig;\n\n try {\n staticRepoConfig = await tryReadStaticRepoFileConfig(filename);\n } catch (err) {\n logger.fatal({ err }, 'Failed to load static repository config file');\n process.exit(1);\n }\n\n if (!isNonEmptyObject(staticRepoConfig)) {\n return config;\n }\n\n return mergeStaticConfig(config, staticRepoConfig);\n}\n\nexport async function tryReadStaticRepoFileConfig(\n staticRepoConfigFile: string,\n): Promise<AllConfig> {\n logger.debug(`Reading static repo config file from ${staticRepoConfigFile}`);\n\n let staticRepoConfigRaw: string;\n try {\n staticRepoConfigRaw = await readSystemFile(staticRepoConfigFile, 'utf8');\n } catch (err) {\n throw new Error(\n `Failed to read static repo config file: \"${staticRepoConfigFile}\"`,\n { cause: err },\n );\n }\n\n const staticRepoConfig = parseJson(\n staticRepoConfigRaw,\n staticRepoConfigFile,\n ) as AllConfig;\n\n // validate and log issues here to preserve context, caller handles migration and full validation.\n const { errors, warnings } = await configValidation.validateConfig(\n 'repo',\n staticRepoConfig,\n );\n\n if (isNonEmptyArray(errors) || isNonEmptyArray(warnings)) {\n logger.info(\n { errors, warnings },\n 'Static repo config validation issues detected',\n );\n } else {\n logger.debug(\n { staticRepoConfig },\n 'Static repository config file successfully parsed and validated',\n );\n }\n\n return staticRepoConfig;\n}\n\nexport function mergeStaticConfig(\n config: AllConfig,\n staticRepoConfig: AllConfig,\n): AllConfig {\n // merge extends\n if (isNonEmptyArray(staticRepoConfig.extends)) {\n config.extends = [\n ...staticRepoConfig.extends,\n ...coerceArray(config.extends),\n ];\n delete staticRepoConfig.extends;\n }\n\n // renovate repo config overrides RENOVATE_STATIC_REPO_CONFIG[_FILE]\n return mergeChildConfig(staticRepoConfig, config);\n}\n\n/**\n * Resolve everything but internal Renovate presets and log it out.\n *\n* This allows users to understand the fully resolved configuration, including any `github>`, `local>`, etc presets, but excluding anything that's internal to Renovate (which can be verbose and/or less relevant), and provides useful output for debugging purposes.\n\n* This is also known as the \"shallow\" config.\n\n* Due to caching, this doesn't add any additional requests.\n */\nasync function logShallowConfig(\n _decryptedConfig: RenovateConfig,\n _config: RepositoryWorkerConfig,\n): Promise<void> {\n // make sure we clone the existing config, so we don't modify the existing settings when resolving this in a shallow fashion\n const decryptedConfig = clone(_decryptedConfig);\n const config = clone(_config);\n\n const { config: resolvedConfig, visitedPresets } =\n await presets.resolveConfigPresets(\n clone(decryptedConfig),\n clone(config),\n [],\n [],\n false,\n );\n logger.debug(\n {\n renovateVersion: pkg.version,\n config: resolvedConfig,\n visitedPresets,\n },\n 'Resolved shallow config, without merging internal presets',\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"merge.js","names":["configValidation.validateConfig","hostRules.matchesHost","presets.resolveConfigPresets"],"sources":["../../../../lib/workers/repository/init/merge.ts"],"sourcesContent":["import {\n isNonEmptyArray,\n isNonEmptyObject,\n isNonEmptyString,\n isString,\n isUndefined,\n} from '@sindresorhus/is';\nimport { dequal } from 'dequal';\nimport { getConfigFileNames } from '../../../config/app-strings.ts';\nimport { decryptConfig } from '../../../config/decrypt.ts';\nimport { mergeChildConfig } from '../../../config/index.ts';\nimport { massageConfig } from '../../../config/massage.ts';\nimport { migrateAndValidate } from '../../../config/migrate-validate.ts';\nimport { migrateConfig } from '../../../config/migration.ts';\nimport { parseFileConfig } from '../../../config/parse.ts';\nimport * as presets from '../../../config/presets/index.ts';\nimport { applySecretsAndVariablesToConfig } from '../../../config/secrets.ts';\nimport type {\n AllConfig,\n MigratedConfig,\n RenovateConfig,\n ValidationMessage,\n} from '../../../config/types.ts';\nimport * as configValidation from '../../../config/validation.ts';\nimport { ConfigValidationTopic } from '../../../config/validation-helpers/types.ts';\nimport {\n CONFIG_VALIDATION,\n REPOSITORY_CHANGED,\n} from '../../../constants/error-messages.ts';\nimport { pkg } from '../../../expose.ts';\nimport { logger } from '../../../logger/index.ts';\nimport * as npmApi from '../../../modules/datasource/npm/index.ts';\nimport { platform } from '../../../modules/platform/index.ts';\nimport { scm } from '../../../modules/platform/scm.ts';\nimport { ExternalHostError } from '../../../types/errors/external-host-error.ts';\nimport type { HostRule } from '../../../types/index.ts';\nimport { coerceArray } from '../../../util/array.ts';\nimport { getCache } from '../../../util/cache/repository/index.ts';\nimport { clone } from '../../../util/clone.ts';\nimport { getInheritedOrGlobal, parseJson } from '../../../util/common.ts';\nimport { setUserEnv } from '../../../util/env.ts';\nimport { readLocalFile, readSystemFile } from '../../../util/fs/index.ts';\nimport * as hostRules from '../../../util/host-rules.ts';\nimport * as queue from '../../../util/http/queue.ts';\nimport * as throttle from '../../../util/http/throttle.ts';\nimport { maskToken } from '../../../util/mask.ts';\nimport { coerceObject } from '../../../util/object.ts';\nimport { regEx } from '../../../util/regex.ts';\nimport { coerceString } from '../../../util/string.ts';\nimport { safeStringify } from '../../../util/stringify.ts';\nimport { parseUrl } from '../../../util/url.ts';\nimport { getOnboardingConfig } from '../onboarding/branch/config.ts';\nimport {\n getOnboardingConfigFromCache,\n getOnboardingFileNameFromCache,\n setOnboardingConfigDetails,\n} from '../onboarding/branch/onboarding-branch-cache.ts';\nimport {\n OnboardingState,\n getDefaultConfigFileName,\n} from '../onboarding/common.ts';\nimport { filterAllowedEnv } from './filter-allowed-env.ts';\nimport type { RepoFileConfig, RepositoryWorkerConfig } from './types.ts';\n\nexport async function detectConfigFile(): Promise<string | null> {\n const fileList = await scm.getFileList();\n for (const fileName of getConfigFileNames()) {\n if (fileName === 'package.json') {\n try {\n const pJson = JSON.parse(\n (await readLocalFile('package.json', 'utf8'))!,\n );\n if (pJson.renovate) {\n logger.warn(\n 'Using package.json for Renovate config is deprecated - please use a dedicated configuration file instead',\n );\n return 'package.json';\n }\n } catch {\n // Do nothing\n }\n } else if (fileList.includes(fileName)) {\n return fileName;\n }\n }\n return null;\n}\n\nexport async function detectRepoFileConfig(\n branchName?: string,\n): Promise<RepoFileConfig> {\n const cache = getCache();\n let { configFileName } = cache;\n if (isNonEmptyString(configFileName)) {\n let configFileRaw: string | null;\n try {\n configFileRaw = await platform.getRawFile(\n configFileName,\n undefined,\n branchName,\n );\n } catch (err) {\n // istanbul ignore if\n if (err instanceof ExternalHostError) {\n throw err;\n }\n configFileRaw = null;\n }\n if (configFileRaw) {\n let configFileParsed = parseJson(configFileRaw, configFileName) as any;\n if (configFileName === 'package.json') {\n configFileParsed = configFileParsed.renovate;\n }\n return { configFileName, configFileParsed };\n }\n logger.debug('Existing config file no longer exists');\n delete cache.configFileName;\n }\n\n if (OnboardingState.onboardingCacheValid) {\n configFileName = getOnboardingFileNameFromCache();\n } else {\n configFileName = coerceString(await detectConfigFile());\n }\n\n if (!configFileName) {\n logger.debug('No renovate config file found');\n cache.configFileName = '';\n return {};\n }\n cache.configFileName = configFileName;\n logger.debug(`Found ${configFileName} config file`);\n // TODO #22198\n let configFileParsed: any;\n let configFileRaw: string | undefined | null;\n\n if (OnboardingState.onboardingCacheValid) {\n const cachedConfig = getOnboardingConfigFromCache();\n const parsedConfig = cachedConfig ? JSON.parse(cachedConfig) : undefined;\n if (parsedConfig) {\n setOnboardingConfigDetails(configFileName, JSON.stringify(parsedConfig));\n return { configFileName, configFileParsed: parsedConfig };\n }\n }\n\n if (configFileName === 'package.json') {\n // We already know it parses\n configFileParsed = JSON.parse(\n // TODO #22198\n (await readLocalFile('package.json', 'utf8'))!,\n ).renovate;\n if (isString(configFileParsed)) {\n logger.debug('Massaging string renovate config to extends array');\n configFileParsed = { extends: [configFileParsed] };\n }\n logger.debug({ config: configFileParsed }, 'package.json>renovate config');\n } else {\n configFileRaw = await readLocalFile(configFileName, 'utf8');\n // istanbul ignore if\n if (!isString(configFileRaw)) {\n logger.warn({ configFileName }, 'Null contents when reading config file');\n throw new Error(REPOSITORY_CHANGED);\n }\n // istanbul ignore if\n if (!configFileRaw.length) {\n configFileRaw = '{}';\n }\n\n const parseResult = parseFileConfig(configFileName, configFileRaw);\n\n if (!parseResult.success) {\n return {\n configFileName,\n configFileParseError: {\n validationError: parseResult.validationError,\n validationMessage: parseResult.validationMessage,\n },\n };\n }\n configFileParsed = parseResult.parsedContents;\n logger.debug(\n { fileName: configFileName, config: configFileParsed },\n 'Repository config',\n );\n }\n\n setOnboardingConfigDetails(configFileName, JSON.stringify(configFileParsed));\n return { configFileName, configFileParsed };\n}\n\nexport function checkForRepoConfigError(repoConfig: RepoFileConfig): void {\n if (!repoConfig.configFileParseError) {\n return;\n }\n const error = new Error(CONFIG_VALIDATION);\n error.validationSource = repoConfig.configFileName;\n error.validationError = repoConfig.configFileParseError.validationError;\n error.validationMessage = repoConfig.configFileParseError.validationMessage;\n throw error;\n}\n\n/**\n * Validation source for `repositories[]` object-entry config.\n *\n * As these are managed by the self-hosted admin's global config (`config.js`, or through environment variables, CLI options) we shouldn't report this as an issue the repo owner has introduced.\n */\nconst repositoriesEntrySource = 'Self-hosted config (`repositories[]`)';\n\nconst repoFileValidationError =\n 'The Renovate configuration file contains some invalid settings';\n\nconst repositoriesEntryValidationError =\n 'The self-hosted `repositories[]` config contains some invalid settings';\n\nfunction throwConfigValidationError(\n validationSource: string | undefined,\n errors: ValidationMessage[],\n validationError = repoFileValidationError,\n): never {\n const error = new Error(CONFIG_VALIDATION);\n error.validationSource = validationSource;\n error.validationError = validationError;\n error.validationMessage = errors.map((e) => e.message).join(', ');\n throw error;\n}\n\n/**\n * Validate a fully-resolved config (i.e. after `resolveConfigPresets`).\n *\n * If there are top-level `allowedEnv`/`allowedHeaders` violations, these are reported with `ConfigValidationTopic.Security` and always fail a validation, as they are sensitive config options that need to be blocked.\n *\n * All other issues will be a WARN, unless `configValidationError=true`, because these are resolved config options and may not be in control of the repository owner.\n *\n * `validationSource` is reported to the user; use `repositoriesEntrySource` and `repositoriesEntryValidationError` for admin-controlled object entries so a fault is not blamed on the repo owner.\n */\nasync function validateResolvedConfig(\n resolved: RenovateConfig,\n validationSource: string | undefined,\n strict: boolean,\n validationError?: string,\n): Promise<void> {\n const { errors, warnings } = await configValidation.validateConfig(\n 'repo',\n // `validateConfig` expects massaged input\n massageConfig(resolved),\n );\n\n // Security findings are collected from the warnings too: `validateConfig` folds the results of the sub-validations it runs (notably `onboardingConfig`) into its warnings, and a finding is no less real for having been reported from within one\n const securityErrors = [...errors, ...warnings].filter(\n (err) => err.topic === ConfigValidationTopic.Security,\n );\n const otherErrors = errors.filter(\n (err) => err.topic !== ConfigValidationTopic.Security,\n );\n const otherWarnings = warnings.filter(\n (err) => err.topic !== ConfigValidationTopic.Security,\n );\n\n // before throwing, make sure that any other errors or warnings are logged, as there may be important findings\n if (otherErrors.length || otherWarnings.length) {\n logger.debug(\n { errors: otherErrors, warnings: otherWarnings },\n 'Config validation failed on resolved config, for non-security-sensitive reasons',\n );\n }\n\n if (securityErrors.length) {\n throwConfigValidationError(\n validationSource,\n securityErrors,\n validationError,\n );\n }\n if (strict && otherErrors.length) {\n throwConfigValidationError(validationSource, otherErrors, validationError);\n }\n}\n\n/**\n * Identify a single `env` variable, or a single header of a host rule, by name and value.\n *\n * As `env` is replaced wholesale and `hostRules` is `mergeable`, self-hosted config and repo config end up indistinguishable in the resolved config, so we need a stable way to look a given name and value up.\n */\nfunction nameValueIdentity(name: string, value: string): string {\n // use safeStringify to avoid any potential for an attacker-controlled value to attempt to try and fake the separator and inject in their value as priority\n return safeStringify([name, value]);\n}\n\n/**\n * Index a set of host rules' headers by {@link nameValueIdentity}, recording the `matchHost` values each is set for (`null` for a host-less rule, which matches every host).\n */\nfunction headersByIdentity(\n rules: HostRule[] | undefined,\n): Map<string, Set<string | null>> {\n const result = new Map<string, Set<string | null>>();\n for (const rule of coerceArray(rules)) {\n for (const [name, value] of Object.entries(coerceObject(rule.headers))) {\n const identity = nameValueIdentity(name, value);\n const hosts = result.get(identity) ?? new Set<string | null>();\n hosts.add(rule.matchHost ?? null);\n result.set(identity, hosts);\n }\n }\n return result;\n}\n\n/**\n * Whether every request matched by `matchHost` is also matched by `adminMatchHost` - i.e. a rule scoped to `matchHost` cannot reach any host the admin's own rule does not already reach.\n *\n * A bare hostname is compared as its `https://` URL. `matchesHost` treats a bare `adminMatchHost` as also covering its subdomains, which errs on the admin-friendly side: those hosts sit within the admin's own domain.\n */\nfunction isWithinHost(matchHost: string, adminMatchHost: string): boolean {\n const url = parseUrl(matchHost) ? matchHost : `https://${matchHost}`;\n return hostRules.matchesHost(url, adminMatchHost);\n}\n\n/**\n * Migrate a config, tolerating a migration which throws.\n *\n * `hostRules` migration throws when a rule carries more than one host-matching field. That is per-rule invalid config which {@link applyHostRules} logs and skips over, keeping the rest of the run going, so migrating a whole config here must not escalate it into an error which aborts the repository.\n */\nfunction migrateConfigOrWarn(config: RenovateConfig): MigratedConfig {\n try {\n return migrateConfig(config);\n } catch (err) {\n logger.warn({ err }, 'Error migrating config');\n return { isMigrated: false, migratedConfig: config };\n }\n}\n\n/**\n * The security-sensitive values (`env`, and `hostRules[].headers`) the self-hosted admin supplied, indexed by {@link nameValueIdentity}; the headers additionally record the `matchHost` values each was set for.\n *\n * `mergeChildConfig` promotes `force` values to the top level, so each config contributes its `force` alongside its top-level values.\n */\ninterface AdminSuppliedValues {\n env: Set<string>;\n headers: Map<string, Set<string | null>>;\n /** the `allowInternal` values ('true'/'false') the admin set, recording the `matchHost` values each is set for (`null` for a host-less rule) */\n internalGrants: Map<string, Set<string | null>>;\n}\n\n/**\n * Migrate a set of host rules, so that their `matchHost` compares like for like against the resolved config's own: migration rewrites them (e.g. a legacy `hostName` becoming a `matchHost`, or a bare `matchHost` gaining a scheme), and the resolved config only ever contains the migrated spellings.\n */\nfunction migratedHostRules(rules: HostRule[] | undefined): HostRule[] {\n if (!isNonEmptyArray(rules)) {\n return [];\n }\n return coerceArray(\n migrateConfigOrWarn({ hostRules: rules }).migratedConfig.hostRules,\n );\n}\n\n/**\n * Collect the {@link AdminSuppliedValues} of every config the self-hosted admin supplied.\n *\n * A preset is only ever resolved into the config which extends it, so a config here is the *resolved* form of an admin config: whatever the presets the admin chose to extend contribute is as much theirs as a value they wrote inline.\n */\nfunction adminSuppliedValues(\n adminConfigs: RenovateConfig[],\n): AdminSuppliedValues {\n const env = new Set<string>();\n const headers = new Map<string, Set<string | null>>();\n const internalGrants = new Map<string, Set<string | null>>();\n\n for (const adminConfig of adminConfigs) {\n for (const source of [adminConfig, adminConfig.force]) {\n for (const [name, value] of Object.entries(coerceObject(source?.env))) {\n env.add(nameValueIdentity(name, value));\n }\n const rules = migratedHostRules(source?.hostRules);\n for (const [identity, matchHosts] of headersByIdentity(rules)) {\n const hosts = headers.get(identity) ?? new Set<string | null>();\n for (const matchHost of matchHosts) {\n hosts.add(matchHost);\n }\n headers.set(identity, hosts);\n }\n for (const rule of rules) {\n if (!isUndefined(rule.allowInternal)) {\n const key = rule.allowInternal.toString();\n const hosts = internalGrants.get(key) ?? new Set<string | null>();\n hosts.add(rule.matchHost ?? null);\n internalGrants.set(key, hosts);\n }\n }\n }\n }\n\n return { env, headers, internalGrants };\n}\n\n/**\n * Return `resolved` without the security-sensitive (`env` and `hostRules[].headers`) values the self-hosted admin supplied themselves.\n *\n * `allowedEnv`/`allowedHeaders` exist to constrain what repository config, and the presets it extends, may inject; the self-hosted admin is who sets those allowlists, so their own values are not violations of them.\n *\n * Reporting them would abort the repository and file a \"Fix Renovate Configuration\" issue whose cause the repository's owners can neither see nor fix.\n */\nfunction withoutAdminSuppliedValues(\n resolved: RenovateConfig,\n admin: AdminSuppliedValues,\n): RenovateConfig {\n const result = { ...resolved };\n\n if (result.env) {\n result.env = Object.fromEntries(\n Object.entries(result.env).filter(\n ([name, value]) => !admin.env.has(nameValueIdentity(name, value)),\n ),\n );\n }\n\n // A header is the admin's own when its name and value match one the admin set for hosts that already cover this rule's hosts - the exact `matchHost` spelling must not matter, as migration and presets can re-spell (e.g. add a scheme) or narrow (e.g. a subpath) it\n if (result.hostRules) {\n result.hostRules = result.hostRules.map((rule) => {\n const filtered: HostRule = {\n ...rule,\n headers: Object.fromEntries(\n Object.entries(coerceObject(rule.headers)).filter(([name, value]) => {\n const adminHosts = admin.headers.get(\n nameValueIdentity(name, value),\n );\n if (!adminHosts) {\n // not a header the admin set - report it\n return true;\n }\n if (adminHosts.has(null)) {\n // the admin already sends it to every host\n return false;\n }\n // a host-less rule reaches every host, so only a host-less admin header (above) can exempt it\n return !(\n rule.matchHost &&\n [...adminHosts].some(\n (adminHost) =>\n adminHost !== null &&\n isWithinHost(rule.matchHost!, adminHost),\n )\n );\n }),\n ),\n };\n\n // same principle for `allowInternal`: the admin's own value, for hosts their own rules already cover, is not a violation\n if (!isUndefined(filtered.allowInternal)) {\n const adminHosts = admin.internalGrants.get(\n filtered.allowInternal.toString(),\n );\n const covered =\n adminHosts &&\n (adminHosts.has(null) ||\n (!!filtered.matchHost &&\n [...adminHosts].some(\n (adminHost) =>\n adminHost !== null &&\n isWithinHost(filtered.matchHost!, adminHost),\n )));\n if (covered) {\n delete filtered.allowInternal;\n }\n }\n\n return filtered;\n });\n }\n\n // `mergeChildConfig` promotes `force` values into the config it returns, so the admin's own `force.env`/`force.hostRules[].headers` are applied - and exempted - the same way their top-level equivalents are\n if (result.force) {\n result.force = withoutAdminSuppliedValues(result.force, admin);\n }\n\n return result;\n}\n\n// Check for repository config\nexport async function mergeRenovateConfig(\n config: RepositoryWorkerConfig,\n branchName?: string,\n): Promise<RenovateConfig> {\n let returnConfig: RepositoryWorkerConfig = { ...config };\n let repoConfig: RepoFileConfig = {};\n if (getInheritedOrGlobal('requireConfig') !== 'ignored') {\n repoConfig = await detectRepoFileConfig(branchName);\n }\n if (!repoConfig.configFileParsed && config.mode === 'silent') {\n logger.debug(\n 'When mode=silent and repo has no config file, we use the onboarding config as repo config',\n );\n const configFileName = getDefaultConfigFileName();\n repoConfig = {\n configFileName,\n configFileParsed: await getOnboardingConfig(config),\n };\n }\n const configFileParsed = coerceObject(repoConfig?.configFileParsed);\n const resolvedRepoConfig = await resolveStaticRepoConfig(\n configFileParsed,\n process.env.RENOVATE_X_STATIC_REPO_CONFIG_FILE,\n );\n\n // Apply the repositories[] object-entry config between global config and\n // repository file config.\n // Must run after repository file config is loaded so its `ignorePresets` can\n // be included when resolving object-entry presets.\n const repoEntryConfig = returnConfig.repositoryEntryConfig;\n delete returnConfig.repositoryEntryConfig;\n\n // The presets the self-hosted admin's own config extends are their config too - a repository which merely inherits them must neither be blamed for what they contribute, nor have it filtered out from under it.\n // They are resolved separately because below they are resolved together with the repository's own presets, leaving no way to tell one from the other; a failure here is left to that resolution to report, as it is the one whose result is used.\n let adminPresetConfig: AllConfig = {};\n if (isNonEmptyArray(returnConfig.extends)) {\n try {\n ({ config: adminPresetConfig } = await presets.resolveConfigPresets(\n { extends: returnConfig.extends },\n config,\n config.ignorePresets,\n ));\n } catch (err) {\n logger.debug(\n { err },\n 'Error resolving the self-hosted config presets - continuing without their exemption',\n );\n }\n }\n\n // self-hosted configuration is always allowed\n // `force.env` is included because `mergeChildConfig` promotes `force` values to the top level as configs are merged\n const adminSuppliedEnv = {\n // presets the admin extends: as much theirs as anything they set inline, which is why they are listed first - the values they set themselves win\n ...coerceObject(adminPresetConfig.env),\n ...coerceObject(adminPresetConfig.force?.env),\n // `env` settings the self-hosted admin supplied (via `config.js`, etc), `env`, etc\n ...coerceObject(config.env),\n ...coerceObject(config.force?.env),\n // `repositories[]` entry for this repo - refreshed with the resolved values below, once its own presets, secrets and variables have been applied\n ...coerceObject(repoEntryConfig?.env),\n ...coerceObject(repoEntryConfig?.force?.env),\n };\n\n // every config the self-hosted admin supplied, in resolved form, for {@link adminSuppliedValues}\n const adminConfigs: RenovateConfig[] = [config, adminPresetConfig];\n\n if (isNonEmptyObject(repoEntryConfig)) {\n const repoEntry = repoEntryConfig as RenovateConfig;\n const toResolve: RenovateConfig = {\n ...repoEntry,\n extends: [\n ...coerceArray(returnConfig.extends),\n ...coerceArray(repoEntry.extends),\n ],\n ignorePresets: [\n ...coerceArray(returnConfig.ignorePresets),\n ...coerceArray(repoEntry.ignorePresets),\n ...coerceArray(resolvedRepoConfig.ignorePresets),\n ],\n };\n delete returnConfig.extends;\n\n let { config: resolvedRepoEntry } = await presets.resolveConfigPresets(\n toResolve,\n config,\n );\n\n // Migrate before validating so legacy option names contributed by the entry or its presets are migrated rather than reported as invalid options.\n const entryMigration = migrateConfigOrWarn(resolvedRepoEntry);\n if (entryMigration.isMigrated) {\n resolvedRepoEntry = entryMigration.migratedConfig;\n }\n\n // Migrate the entry's own config the same way, so its values compare like for like below: migration can rewrite them (e.g. a legacy `hostName` becoming a `matchHost`, or a bare `matchHost` gaining a scheme), and the resolved config only ever contains the migrated spellings\n const { migratedConfig: migratedEntry } = migrateConfigOrWarn(toResolve);\n // `resolveConfigPresets` removes both of these from its result\n delete migratedEntry.extends;\n delete migratedEntry.ignorePresets;\n\n // The entry, and every preset it extends, is the self-hosted admin's own config, so its `env`/`headers` are exempt from the allowlists the admin set - but the rest of the resolved result is still worth validating before any of it is applied (npmrc, hostRules, env).\n // When resolution and migration changed nothing, the presets contributed nothing and the entry itself was already validated as part of the admin's global config, so skip the (costly) validation walk entirely.\n adminConfigs.push(resolvedRepoEntry);\n if (!dequal(resolvedRepoEntry, migratedEntry)) {\n await validateResolvedConfig(\n withoutAdminSuppliedValues(\n resolvedRepoEntry,\n adminSuppliedValues(adminConfigs),\n ),\n repositoriesEntrySource,\n config.configValidationError === true,\n repositoriesEntryValidationError,\n );\n }\n\n applyNpmrc(resolvedRepoEntry, 'resolvedRepoEntry');\n\n const resolvedRepoEntryWithSecrets = applySecretsAndVariablesToConfig({\n config: resolvedRepoEntry,\n // like the repository config below, the entry can carry its own `secrets`/`variables` - `validateConfigSecretsAndVariables` validates them at startup\n secrets: mergeChildConfig(\n coerceObject(config.secrets),\n coerceObject(resolvedRepoEntry.secrets),\n ),\n variables: mergeChildConfig(\n coerceObject(config.variables),\n coerceObject(resolvedRepoEntry.variables),\n ),\n });\n\n // Refresh the admin-supplied snapshot from the resolved entry: it also carries whatever the presets the entry extends contributed, and its `env` values may contain `{{ secrets.* }}`/`{{ variables.* }}` templates only interpolated here - e.g. when the secrets are defined on the entry itself rather than globally.\n // Interpolation is recursive, so the interpolated `force.env` values stay nested under `force`.\n Object.assign(\n adminSuppliedEnv,\n coerceObject(resolvedRepoEntryWithSecrets.env),\n coerceObject(resolvedRepoEntryWithSecrets.force?.env),\n );\n\n // the `repositories[]` entry is the self-hosted admin's own config - as its `env` is already treated as admin-supplied, its rules are `trusted` too, so that an admin can still override a header they set globally for just this repository\n applyHostRules(resolvedRepoEntryWithSecrets, { trusted: true });\n returnConfig = mergeChildConfig(returnConfig, resolvedRepoEntryWithSecrets);\n }\n\n if (isNonEmptyArray(returnConfig.extends)) {\n resolvedRepoConfig.extends = [\n ...coerceArray(returnConfig.extends),\n ...coerceArray(resolvedRepoConfig.extends),\n ];\n delete returnConfig.extends;\n }\n checkForRepoConfigError(repoConfig);\n const migratedConfig = await migrateAndValidate(config, resolvedRepoConfig);\n if (migratedConfig.errors?.length) {\n throwConfigValidationError(\n repoConfig.configFileName,\n migratedConfig.errors,\n );\n }\n // v8 ignore else -- migration always leaves a warnings array behind\n if (migratedConfig.warnings) {\n returnConfig.warnings = [\n ...coerceArray(returnConfig.warnings),\n ...migratedConfig.warnings,\n ];\n }\n delete migratedConfig.errors;\n delete migratedConfig.warnings;\n // TODO #22198\n const repository = config.repository!;\n // Decrypt before resolving in case we need npm authentication for any presets\n const decryptedConfig = await decryptConfig(migratedConfig, repository);\n applyNpmrc(decryptedConfig, 'decrypted');\n\n // NOTE that this should not be used with any other configuration (`resolvedConfig`, etc) below, as they will include addditionally merged configuration\n // Decrypted secrets are sanitised, so should be safe to log\n await logShallowConfig(decryptedConfig, config);\n\n // Decrypt after resolving in case the preset contains npm authentication instead\n const { config: configToDecrypt } = await presets.resolveConfigPresets(\n decryptedConfig,\n config,\n config.ignorePresets,\n );\n let resolvedConfig = await decryptConfig(configToDecrypt, repository);\n logger.trace({ config: resolvedConfig }, 'resolved config');\n const migrationResult = migrateConfig(resolvedConfig);\n if (migrationResult.isMigrated) {\n logger.debug('Resolved config needs migrating');\n logger.trace({ config: resolvedConfig }, 'resolved config after migrating');\n resolvedConfig = migrationResult.migratedConfig;\n }\n\n // Validate the fully-resolved repository config, enforcing validation is applied against all stages of the preset, and providing defence-in-depth for any sensitive config options\n // note that we do not need to re-run `migrateAndValidate` if we're already at the same configuration that we've previously resolved, decrypted and migrated, so we can avoid a costly re-validation\n if (!dequal(resolvedConfig, migratedConfig)) {\n await validateResolvedConfig(\n // the admin's own `extends` are resolved into this config alongside the repository's, so exempt what they contributed: the repository can neither see nor fix it\n withoutAdminSuppliedValues(\n resolvedConfig,\n adminSuppliedValues(adminConfigs),\n ),\n // a repository that is not yet onboarded has no config file to blame; 'config' mirrors other unattributable validation errors (e.g. `decryptConfig`)\n repoConfig.configFileName ?? 'config',\n config.configValidationError === true,\n );\n }\n if (isString(resolvedConfig.npmrc)) {\n logger.debug(\n 'Ignoring any .npmrc files in repository due to configured npmrc',\n );\n }\n applyNpmrc(resolvedConfig, 'resolved');\n resolvedConfig = applySecretsAndVariablesToConfig({\n config: resolvedConfig,\n secrets: mergeChildConfig(\n coerceObject(config.secrets),\n coerceObject(resolvedConfig.secrets),\n ),\n variables: mergeChildConfig(\n coerceObject(config.variables),\n coerceObject(resolvedConfig.variables),\n ),\n });\n\n applyHostRules(resolvedConfig);\n returnConfig = mergeChildConfig(returnConfig, resolvedConfig);\n ({ config: returnConfig } = await presets.resolveConfigPresets(\n returnConfig,\n config,\n ));\n returnConfig.renovateJsonPresent = true;\n // istanbul ignore if\n if (returnConfig.ignorePaths?.length) {\n logger.debug(\n { ignorePaths: returnConfig.ignorePaths },\n `Found repo ignorePaths`,\n );\n }\n\n setUserEnv(filterAllowedEnv(returnConfig.env, adminSuppliedEnv));\n delete returnConfig.env;\n\n return returnConfig;\n}\n\nexport function applyNpmrc(\n config: RenovateConfig,\n configType?: 'resolved' | 'resolvedRepoEntry' | 'decrypted',\n): void {\n setNpmTokenInNpmrc(config);\n if (!isString(config.npmrc)) {\n return;\n }\n logger.debug(\n `Setting npmrc from ${configType ? `${configType} ` : ''}config`,\n );\n npmApi.setNpmrc(config.npmrc);\n}\n\nexport function applyHostRules(\n config: RenovateConfig,\n options?: hostRules.AddHostRuleOptions,\n): void {\n if (!config.hostRules) {\n return;\n }\n\n logger.debug('Setting hostRules from config');\n // `hostRules.add` enforces `allowedHeaders` on every rule it registers\n for (const rule of config.hostRules) {\n try {\n hostRules.add(rule, options);\n } catch (err) {\n logger.warn({ err, config: rule }, 'Error setting hostRule from config');\n }\n }\n // host rules can change concurrency\n queue.clear();\n throttle.clear();\n delete config.hostRules;\n}\n\n/** needed when using portal secrets for npmToken */\nexport function setNpmTokenInNpmrc(config: RenovateConfig): void {\n if (!isString(config.npmToken)) {\n return;\n }\n\n const token = config.npmToken;\n logger.debug({ npmToken: maskToken(token) }, 'Migrating npmToken to npmrc');\n\n if (!isString(config.npmrc)) {\n logger.debug('Adding npmrc to config');\n config.npmrc = `//registry.npmjs.org/:_authToken=${token}\\n`;\n delete config.npmToken;\n return;\n }\n\n if (config.npmrc.includes(`\\${NPM_TOKEN}`)) {\n logger.debug(`Replacing \\${NPM_TOKEN} with npmToken`);\n config.npmrc = config.npmrc.replace(regEx(/\\${NPM_TOKEN}/g), token);\n } else {\n logger.debug('Appending _authToken= to end of existing npmrc');\n config.npmrc = config.npmrc.replace(\n regEx(/\\n?$/),\n `\\n_authToken=${token}\\n`,\n );\n }\n\n delete config.npmToken;\n}\n\nexport async function resolveStaticRepoConfig(\n config: AllConfig,\n filename: string | undefined,\n): Promise<AllConfig> {\n if (!isNonEmptyString(filename)) {\n return config;\n }\n\n let staticRepoConfig: AllConfig;\n\n try {\n staticRepoConfig = await tryReadStaticRepoFileConfig(filename);\n } catch (err) {\n logger.fatal({ err }, 'Failed to load static repository config file');\n process.exit(1);\n }\n\n if (!isNonEmptyObject(staticRepoConfig)) {\n return config;\n }\n\n return mergeStaticConfig(config, staticRepoConfig);\n}\n\nexport async function tryReadStaticRepoFileConfig(\n staticRepoConfigFile: string,\n): Promise<AllConfig> {\n logger.debug(`Reading static repo config file from ${staticRepoConfigFile}`);\n\n let staticRepoConfigRaw: string;\n try {\n staticRepoConfigRaw = await readSystemFile(staticRepoConfigFile, 'utf8');\n } catch (err) {\n throw new Error(\n `Failed to read static repo config file: \"${staticRepoConfigFile}\"`,\n { cause: err },\n );\n }\n\n const staticRepoConfig = parseJson(\n staticRepoConfigRaw,\n staticRepoConfigFile,\n ) as AllConfig;\n\n // validate and log issues here to preserve context, caller handles migration and full validation.\n const { errors, warnings } = await configValidation.validateConfig(\n 'repo',\n staticRepoConfig,\n );\n\n if (isNonEmptyArray(errors) || isNonEmptyArray(warnings)) {\n logger.info(\n { errors, warnings },\n 'Static repo config validation issues detected',\n );\n } else {\n logger.debug(\n { staticRepoConfig },\n 'Static repository config file successfully parsed and validated',\n );\n }\n\n return staticRepoConfig;\n}\n\nexport function mergeStaticConfig(\n config: AllConfig,\n staticRepoConfig: AllConfig,\n): AllConfig {\n // merge extends\n if (isNonEmptyArray(staticRepoConfig.extends)) {\n config.extends = [\n ...staticRepoConfig.extends,\n ...coerceArray(config.extends),\n ];\n delete staticRepoConfig.extends;\n }\n\n // renovate repo config overrides RENOVATE_STATIC_REPO_CONFIG[_FILE]\n return mergeChildConfig(staticRepoConfig, config);\n}\n\n/**\n * Resolve everything but internal Renovate presets and log it out.\n *\n* This allows users to understand the fully resolved configuration, including any `github>`, `local>`, etc presets, but excluding anything that's internal to Renovate (which can be verbose and/or less relevant), and provides useful output for debugging purposes.\n\n* This is also known as the \"shallow\" config.\n\n* Due to caching, this doesn't add any additional requests.\n */\nasync function logShallowConfig(\n _decryptedConfig: RenovateConfig,\n _config: RepositoryWorkerConfig,\n): Promise<void> {\n // make sure we clone the existing config, so we don't modify the existing settings when resolving this in a shallow fashion\n const decryptedConfig = clone(_decryptedConfig);\n const config = clone(_config);\n\n const { config: resolvedConfig, visitedPresets } =\n await presets.resolveConfigPresets(\n clone(decryptedConfig),\n clone(config),\n [],\n [],\n false,\n );\n logger.debug(\n {\n renovateVersion: pkg.version,\n config: resolvedConfig,\n visitedPresets,\n },\n 'Resolved shallow config, without merging internal presets',\n );\n}\n"],"mappings":"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"}
|
|
@@ -142,9 +142,8 @@ function getBranchUpgradeTypes(branch) {
|
|
|
142
142
|
}
|
|
143
143
|
function sortBaseBranches(bases) {
|
|
144
144
|
return [...bases].sort((a, b) => {
|
|
145
|
-
if
|
|
146
|
-
|
|
147
|
-
return 0;
|
|
145
|
+
// v8 ignore if -- base branches are unique Record keys, so never equal
|
|
146
|
+
if (a === b) return 0;
|
|
148
147
|
if (a === "") return -1;
|
|
149
148
|
if (b === "") return 1;
|
|
150
149
|
return a.localeCompare(b);
|