renovate 44.238.3 → 44.239.1

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.
Files changed (38) hide show
  1. package/dist/config/migrated-content.js +29 -0
  2. package/dist/config/migrated-content.js.map +1 -0
  3. package/dist/config/parse.js +1 -1
  4. package/dist/config-validator.js +60 -9
  5. package/dist/config-validator.js.map +1 -1
  6. package/dist/modules/datasource/apk/index.js +1 -1
  7. package/dist/modules/datasource/deb/packages.js +1 -1
  8. package/dist/modules/datasource/rpm/providers/common.js +1 -1
  9. package/dist/modules/manager/cocoapods/artifacts.js +1 -1
  10. package/dist/modules/manager/copier/artifacts.js +1 -1
  11. package/dist/modules/manager/deno/artifacts.js +1 -1
  12. package/dist/modules/manager/gomod/artifacts.js +1 -1
  13. package/dist/modules/manager/gradle/artifacts.js +1 -1
  14. package/dist/modules/manager/gradle-wrapper/artifacts.js +1 -1
  15. package/dist/modules/manager/helmv3/common.js +1 -1
  16. package/dist/modules/manager/hermit/artifacts.js +1 -1
  17. package/dist/modules/manager/kustomize/artifacts.js +1 -1
  18. package/dist/modules/manager/maven-wrapper/artifacts.js +1 -1
  19. package/dist/modules/manager/mise/artifacts.js +1 -1
  20. package/dist/modules/manager/npm/artifacts.js +1 -1
  21. package/dist/modules/manager/npm/post-update/npm.js +1 -1
  22. package/dist/modules/manager/npm/post-update/pnpm.js +1 -1
  23. package/dist/modules/manager/npm/post-update/yarn.js +1 -1
  24. package/dist/modules/manager/nuget/artifacts.js +1 -1
  25. package/dist/modules/manager/pep621/processors/uv.js +1 -1
  26. package/dist/modules/manager/pip-compile/artifacts.js +1 -1
  27. package/dist/modules/manager/pip-compile/common.js +1 -1
  28. package/dist/modules/manager/terraform/lockfile/hash.js +1 -1
  29. package/dist/util/cache/package/impl/file.js +1 -1
  30. package/dist/util/fs/index.js +1 -1
  31. package/dist/util/git/index.js +1 -1
  32. package/dist/workers/global/initialize.js +1 -1
  33. package/dist/workers/repository/config-migration/branch/migrated-data.js +3 -16
  34. package/dist/workers/repository/config-migration/branch/migrated-data.js.map +1 -1
  35. package/dist/workers/repository/process/vulnerabilities.js +1 -1
  36. package/dist/workers/repository/update/branch/execute-post-upgrade-commands.js +1 -1
  37. package/package.json +2 -2
  38. package/renovate-schema.json +2 -2
@@ -0,0 +1,29 @@
1
+ import { logger } from "../logger/index.js";
2
+ import detectIndent from "detect-indent";
3
+ import JSON5 from "json5";
4
+ import { weave } from "jsonc-weaver";
5
+ // lib/config/migrated-content.ts
6
+ /**
7
+ * Serializes a migrated config for `filename`, preserving the comments and indentation of its `raw` content where possible.
8
+ */
9
+ function stringifyMigratedConfig(filename, raw, migratedConfig) {
10
+ const indent = detectIndent(raw ?? "");
11
+ const indentSpace = indent.indent ?? " ";
12
+ let content;
13
+ if (filename.endsWith(".json5")) content = JSON5.stringify(migratedConfig, void 0, indentSpace);
14
+ else if (raw) try {
15
+ content = weave(raw, migratedConfig);
16
+ } catch (err) {
17
+ logger.warn({ err }, "Error weaving JSONC to preserve comments, falling back to JSON.stringify");
18
+ content = JSON.stringify(migratedConfig, void 0, indentSpace);
19
+ }
20
+ else content = JSON.stringify(migratedConfig, void 0, indentSpace);
21
+ if (!content.endsWith("\n")) content += "\n";
22
+ return {
23
+ content,
24
+ indent
25
+ };
26
+ }
27
+ export { stringifyMigratedConfig };
28
+
29
+ //# sourceMappingURL=migrated-content.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrated-content.js","names":[],"sources":["../../lib/config/migrated-content.ts"],"sourcesContent":["import type { Indent } from 'detect-indent';\nimport detectIndent from 'detect-indent';\nimport JSON5 from 'json5';\nimport { weave } from 'jsonc-weaver';\nimport { logger } from '../logger/index.ts';\nimport type { RenovateConfig } from './types.ts';\n\nexport interface MigratedContent {\n content: string;\n indent: Indent;\n}\n\n/**\n * Serializes a migrated config for `filename`, preserving the comments and indentation of its `raw` content where possible.\n */\nexport function stringifyMigratedConfig(\n filename: string,\n raw: string | null,\n migratedConfig: RenovateConfig,\n): MigratedContent {\n const indent = detectIndent(raw ?? '');\n // indent defaults to 2 spaces\n const indentSpace = indent.indent ?? ' ';\n let content: string;\n\n if (filename.endsWith('.json5')) {\n content = JSON5.stringify(migratedConfig, undefined, indentSpace);\n } else if (raw) {\n try {\n content = weave(raw, migratedConfig);\n } catch (err) {\n logger.warn(\n { err },\n 'Error weaving JSONC to preserve comments, falling back to JSON.stringify',\n );\n content = JSON.stringify(migratedConfig, undefined, indentSpace);\n }\n } else {\n content = JSON.stringify(migratedConfig, undefined, indentSpace);\n }\n\n if (!content.endsWith('\\n')) {\n content += '\\n';\n }\n\n return { content, indent };\n}\n"],"mappings":";;;;;;;;AAeA,SAAgB,wBACd,UACA,KACA,gBACiB;CACjB,MAAM,SAAS,aAAa,OAAO,EAAE;CAErC,MAAM,cAAc,OAAO,UAAU;CACrC,IAAI;CAEJ,IAAI,SAAS,SAAS,QAAQ,GAC5B,UAAU,MAAM,UAAU,gBAAgB,KAAA,GAAW,WAAW;MAC3D,IAAI,KACT,IAAI;EACF,UAAU,MAAM,KAAK,cAAc;CACrC,SAAS,KAAK;EACZ,OAAO,KACL,EAAE,IAAI,GACN,0EACF;EACA,UAAU,KAAK,UAAU,gBAAgB,KAAA,GAAW,WAAW;CACjE;MAEA,UAAU,KAAK,UAAU,gBAAgB,KAAA,GAAW,WAAW;CAGjE,IAAI,CAAC,QAAQ,SAAS,IAAI,GACxB,WAAW;CAGb,OAAO;EAAE;EAAS;CAAO;AAC3B"}
@@ -1,8 +1,8 @@
1
1
  import { logger } from "../logger/index.js";
2
2
  import { parseJson } from "../util/common.js";
3
3
  import { regEx } from "../util/regex.js";
4
- import JSON5 from "json5";
5
4
  import upath from "upath";
5
+ import JSON5 from "json5";
6
6
  import stripJsonComments from "strip-json-comments";
7
7
  import jsonValidator from "json-dup-key-validator";
8
8
  // lib/config/parse.ts
@@ -3,6 +3,7 @@ import { require_punycode } from "./punycode.js";
3
3
  import { getConfigFileNames } from "./config/app-strings.js";
4
4
  import { GlobalConfig } from "./config/global.js";
5
5
  import { massageConfig } from "./config/massage.js";
6
+ import { stringifyMigratedConfig } from "./config/migrated-content.js";
6
7
  import { migrateConfig } from "./config/migration.js";
7
8
  import { validateConfig } from "./config/validation.js";
8
9
  import { pkg } from "./expose.js";
@@ -20,9 +21,10 @@ import { Command, CommanderError } from "commander";
20
21
  import { dequal } from "dequal";
21
22
  import { diffLines } from "diff";
22
23
  import fs from "fs-extra";
24
+ import upath from "upath";
23
25
  require_punycode();
24
26
  await init();
25
- const { pathExists, readFile } = fs;
27
+ const { pathExists, readFile, writeFile } = fs;
26
28
  let returnVal = 0;
27
29
  /**
28
30
  * Make sure that we've resolved configuration from the different places that Renovate users would expect them to be specified
@@ -36,7 +38,39 @@ async function partiallyGlobalInitialize() {
36
38
  GlobalConfig.set(globalConfig);
37
39
  if (globalConfig.hostRules) for (const hostRule of globalConfig.hostRules) add(hostRule, { trusted: true });
38
40
  }
39
- async function validate(configType, desc, config, strict, isPreset = false) {
41
+ function isMigratableFile(file) {
42
+ const basename = upath.basename(file);
43
+ if (basename === "package.json") return false;
44
+ if (basename === ".renovaterc") return true;
45
+ return [
46
+ ".json",
47
+ ".jsonc",
48
+ ".json5"
49
+ ].includes(upath.extname(file));
50
+ }
51
+ /**
52
+ * Writes `migratedConfig` to `file`, returning whether the migration was applied.
53
+ */
54
+ async function writeMigratedConfig(file, migratedConfig) {
55
+ if (!isMigratableFile(file)) {
56
+ logger.warn({ file }, "Config migration cannot be applied automatically to this file type");
57
+ return false;
58
+ }
59
+ try {
60
+ const raw = await readFile(file, "utf8");
61
+ const { content } = stringifyMigratedConfig(file, raw, migratedConfig);
62
+ await writeFile(file, content);
63
+ } catch (err) {
64
+ logger.warn({
65
+ file,
66
+ err
67
+ }, "Config migration could not be written");
68
+ return false;
69
+ }
70
+ logger.info(`Applied config migration to ${file}`);
71
+ return true;
72
+ }
73
+ async function validate(configType, desc, config, { strict, isPreset = false, migrateFile }) {
40
74
  if (config.hostRules) for (const hostRule of config.hostRules) add(hostRule, { trusted: configType === "global" });
41
75
  const { isMigrated, migratedConfig } = migrateConfig(config);
42
76
  if (isMigrated) {
@@ -58,7 +92,9 @@ async function validate(configType, desc, config, strict, isPreset = false) {
58
92
  return part.value.split("\n").filter(isNonEmptyStringAndNotWhitespace).map((line) => line.replace(regEx(/^(?<ws> *)/), `${linePrefix}$<ws>`));
59
93
  }).join("\n");
60
94
  logger.warn(`Config migration diff:\n${msg}`);
61
- if (strict) returnVal = 1;
95
+ let isMigrationApplied = false;
96
+ if (migrateFile) isMigrationApplied = await writeMigratedConfig(migrateFile, migratedConfig);
97
+ if (strict && !isMigrationApplied) returnVal = 1;
62
98
  }
63
99
  const massagedConfig = massageConfig(migratedConfig);
64
100
  const res = await validateConfig(configType, massagedConfig, isPreset);
@@ -88,6 +124,7 @@ Examples:
88
124
  $ renovate-config-validator --strict
89
125
  $ renovate-config-validator first_config.json
90
126
  $ renovate-config-validator --strict config.js
127
+ $ renovate-config-validator --migrate
91
128
  $ renovate-config-validator --no-global renovate.json5
92
129
  $ env RENOVATE_CONFIG_FILE=obscure-name.json renovate-config-validator
93
130
 
@@ -97,9 +134,10 @@ If you have specified global self-hosted configuration (https://docs.renovatebot
97
134
 
98
135
  $ env RENOVATE_ALLOWED_ENV='["GO*"]' renovate-config-validator
99
136
  # if passing the filename, make sure it's not validating as a global config
100
- $ env RENOVATE_ALLOWED_ENV='["GO*"]' renovate-config-validator --no-global renovate.json`).argument("[config-files...]").version(pkg.version, "-v, --version").option("--strict", "Fail command if any configuration warnings, errors, or a migration is needed").option("--no-global", "When specifying [config-files], do not treat them as global self-hosted configuration file(s)", true).exitOverride();
137
+ $ env RENOVATE_ALLOWED_ENV='["GO*"]' renovate-config-validator --no-global renovate.json`).argument("[config-files...]").version(pkg.version, "-v, --version").option("--strict", "Fail command if any configuration warnings, errors, or a migration is needed").option("--migrate", "Apply any necessary configuration migrations to the JSON, JSONC or JSON5 configuration file(s)").option("--no-global", "When specifying [config-files], do not treat them as global self-hosted configuration file(s)", true).exitOverride();
101
138
  program.action(async (files, opts) => {
102
139
  const strict = opts.strict ?? false;
140
+ const migrate = opts.migrate ?? false;
103
141
  let filesValidated = 0;
104
142
  if (regexEngineStatus.type === "unavailable") logger.warn({ err: regexEngineStatus.err }, "RE2 not usable, falling back to RegExp: regex validation may be inaccurate");
105
143
  else if (regexEngineStatus.type === "ignored") logger.debug("RE2 ignored via RENOVATE_X_IGNORE_RE2: regex validation may be inaccurate");
@@ -117,7 +155,10 @@ If you have specified global self-hosted configuration (https://docs.renovatebot
117
155
  const parsedContent = await getParsedContent(file);
118
156
  try {
119
157
  logger.info(`Validating ${file} as ${configType} config`);
120
- await validate(configType, file, parsedContent, strict);
158
+ await validate(configType, file, parsedContent, {
159
+ strict,
160
+ migrateFile: migrate ? file : void 0
161
+ });
121
162
  } catch (err) {
122
163
  logger.warn({
123
164
  file,
@@ -141,7 +182,10 @@ If you have specified global self-hosted configuration (https://docs.renovatebot
141
182
  const parsedContent = await getParsedContent(file);
142
183
  try {
143
184
  logger.info(`Validating ${file}`);
144
- await validate("repo", file, parsedContent, strict);
185
+ await validate("repo", file, parsedContent, {
186
+ strict,
187
+ migrateFile: migrate ? file : void 0
188
+ });
145
189
  } catch (err) {
146
190
  logger.warn({
147
191
  file,
@@ -162,13 +206,20 @@ If you have specified global self-hosted configuration (https://docs.renovatebot
162
206
  const pkgJson = JSON.parse(await readFile("package.json", "utf8"));
163
207
  if (pkgJson.renovate) {
164
208
  logger.info(`Validating package.json > renovate`);
165
- await validate("repo", "package.json > renovate", pkgJson.renovate, strict);
209
+ await validate("repo", "package.json > renovate", pkgJson.renovate, {
210
+ strict,
211
+ migrateFile: migrate ? "package.json" : void 0
212
+ });
166
213
  filesValidated++;
167
214
  }
168
215
  if (pkgJson["renovate-config"]) {
169
216
  logger.info(`Validating package.json > renovate-config`);
170
217
  for (const presetConfig of Object.values(pkgJson["renovate-config"])) {
171
- await validate("repo", "package.json > renovate-config", presetConfig, strict, true);
218
+ await validate("repo", "package.json > renovate-config", presetConfig, {
219
+ strict,
220
+ isPreset: true,
221
+ migrateFile: migrate ? "package.json" : void 0
222
+ });
172
223
  filesValidated++;
173
224
  }
174
225
  }
@@ -180,7 +231,7 @@ If you have specified global self-hosted configuration (https://docs.renovatebot
180
231
  const file = env.RENOVATE_CONFIG_FILE ?? "config.js";
181
232
  logger.info(`Validating ${file}`);
182
233
  try {
183
- await validate("global", file, fileConfig, strict);
234
+ await validate("global", file, fileConfig, { strict });
184
235
  } catch (err) {
185
236
  logger.error({
186
237
  file,
@@ -1 +1 @@
1
- {"version":3,"file":"config-validator.js","names":["getFileConfig"],"sources":["../lib/config-validator.ts"],"sourcesContent":["#!/usr/bin/env node\nimport 'source-map-support/register.js';\nimport './punycode.cjs';\n\nimport { styleText } from 'node:util';\nimport { isNonEmptyStringAndNotWhitespace } from '@sindresorhus/is';\nimport { Command, CommanderError } from 'commander';\nimport { dequal } from 'dequal';\nimport { diffLines } from 'diff';\nimport fs from 'fs-extra';\nimport { getConfigFileNames } from './config/app-strings.ts';\nimport { GlobalConfig } from './config/global.ts';\nimport { massageConfig } from './config/massage.ts';\nimport { migrateConfig } from './config/migration.ts';\nimport type { RenovateConfig } from './config/types.ts';\nimport { validateConfig } from './config/validation.ts';\nimport { pkg } from './expose.ts';\nimport { init, logger } from './logger/index.ts';\nimport { getEnv } from './util/env.ts';\nimport { add as addHostRule } from './util/host-rules.ts';\nimport { regEx, regexEngineStatus } from './util/regex.ts';\nimport { getConfig as getFileConfig } from './workers/global/config/parse/file.ts';\nimport { parseConfigs } from './workers/global/config/parse/index.ts';\nimport { getParsedContent } from './workers/global/config/parse/util.ts';\n\nawait init();\n\nconst { pathExists, readFile } = fs;\n\nlet returnVal = 0;\n\n/**\n * Make sure that we've resolved configuration from the different places that Renovate users would expect them to be specified\n *\n * This then allows a `configType=repo` config to i.e. be validated alongside a `config.js` or `env RENOVATE_ALLOWED_COMMANDS=...`\n *\n * Note that we intentionally don't fully initialize Renovate and its modules, as we're not fully running, and it would require a Platform to be configured\n * */\nasync function partiallyGlobalInitialize(): Promise<void> {\n // NOTE that this doesn't allow command-line arguments\n const globalConfig = await parseConfigs(getEnv(), []);\n GlobalConfig.set(globalConfig);\n\n if (globalConfig.hostRules) {\n // this is the self-hosted admin's own config, so its `headers` are exempt from `allowedHeaders` altogether - see `hostRules.add()`\n for (const hostRule of globalConfig.hostRules) {\n addHostRule(hostRule, { trusted: true });\n }\n }\n}\n\nasync function validate(\n configType: 'global' | 'repo',\n desc: string,\n config: RenovateConfig,\n strict: boolean,\n isPreset = false,\n): Promise<void> {\n if (config.hostRules) {\n // a `global` config is the self-hosted administrator's own, so its `headers` are exempt from `allowedHeaders` altogether - see `hostRules.add()`; a `repo` config's `hostRules` are still constrained by this instance's `allowedHeaders`\n for (const hostRule of config.hostRules) {\n addHostRule(hostRule, { trusted: configType === 'global' });\n }\n }\n const { isMigrated, migratedConfig } = migrateConfig(config);\n if (isMigrated) {\n logger.warn(\n {\n oldConfig: config,\n newConfig: migratedConfig,\n },\n 'Config migration necessary',\n );\n const changedObjects = diffLines(\n JSON.stringify(config, null, 2),\n JSON.stringify(migratedConfig, null, 2),\n { ignoreWhitespace: false, newlineIsToken: false },\n );\n const added = styleText('green', '+ ');\n const removed = styleText('red', '- ');\n const msg = changedObjects\n .flatMap((part) => {\n let linePrefix: string;\n if (part.added) {\n linePrefix = added;\n } else if (part.removed) {\n linePrefix = removed;\n } else {\n linePrefix = ' ';\n }\n return part.value\n .split('\\n')\n .filter(isNonEmptyStringAndNotWhitespace)\n .map((line) =>\n line.replace(regEx(/^(?<ws> *)/), `${linePrefix}$<ws>`),\n );\n })\n .join('\\n');\n // oxlint-disable-next-line renovate/logger-static-message -- the multi-line, colorized diff must be interpolated to stay readable; as a metadata field it is JSON-escaped onto one line\n logger.warn(`Config migration diff:\\n${msg}`);\n if (strict) {\n returnVal = 1;\n }\n }\n const massagedConfig = massageConfig(migratedConfig);\n const res = await validateConfig(configType, massagedConfig, isPreset);\n if (res.errors.length) {\n logger.error(\n { file: desc, errors: res.errors },\n 'Found errors in configuration',\n );\n returnVal = 1;\n }\n if (res.warnings.length) {\n logger.warn(\n { file: desc, warnings: res.warnings },\n 'Found errors in configuration',\n );\n returnVal = 1;\n }\n}\n\ninterface PackageJson {\n renovate?: RenovateConfig;\n 'renovate-config'?: Record<string, RenovateConfig>;\n}\n\n(async () => {\n await partiallyGlobalInitialize();\n\n const program = new Command('renovate-config-validator')\n .summary('Validate Renovate configuration files')\n .description(\n `Validate your Renovate configuration (repo config, shared presets or global configuration) files\\n` +\n // oxlint-disable-next-line renovate/no-hardcoded-docs-url -- CLI help text, no config available\n 'If no [config-files...] are given, renovate-config-validator will look at the default config file locations (https://docs.renovatebot.com/configuration-options/)',\n )\n .addHelpText(\n 'after',\n // oxlint-disable-next-line renovate/no-hardcoded-docs-url -- CLI help text, no config available\n `\nWhen specifying [config-files...], Renovate will treat them as global self-hosted configuration files. You can disable this behaviour with --no-global\n\nExamples:\n\n $ renovate-config-validator\n $ renovate-config-validator --strict\n $ renovate-config-validator first_config.json\n $ renovate-config-validator --strict config.js\n $ renovate-config-validator --no-global renovate.json5\n $ env RENOVATE_CONFIG_FILE=obscure-name.json renovate-config-validator\n\nGlobal configuration:\n\nIf you have specified global self-hosted configuration (https://docs.renovatebot.com/self-hosted-configuration/) in environment variables or in a \\`config.js\\`, this will be detected:\n\n $ env RENOVATE_ALLOWED_ENV='[\"GO*\"]' renovate-config-validator\n # if passing the filename, make sure it's not validating as a global config\n $ env RENOVATE_ALLOWED_ENV='[\"GO*\"]' renovate-config-validator --no-global renovate.json`,\n )\n .argument('[config-files...]')\n .version(pkg.version, '-v, --version')\n .option(\n '--strict',\n 'Fail command if any configuration warnings, errors, or a migration is needed',\n )\n .option(\n '--no-global',\n 'When specifying [config-files], do not treat them as global self-hosted configuration file(s)',\n true,\n )\n // allow us to manage the exit code\n .exitOverride();\n\n program.action(async (files, opts) => {\n const strict = opts.strict ?? false;\n let filesValidated = 0;\n\n // without RE2, patterns are checked by RegExp, which accepts syntax RE2 rejects (e.g. lookahead)\n if (regexEngineStatus.type === 'unavailable') {\n logger.warn(\n { err: regexEngineStatus.err },\n 'RE2 not usable, falling back to RegExp: regex validation may be inaccurate',\n );\n } else if (regexEngineStatus.type === 'ignored') {\n logger.debug(\n 'RE2 ignored via RENOVATE_X_IGNORE_RE2: regex validation may be inaccurate',\n );\n }\n\n if (files.length) {\n let isGlobalConfig = true;\n if (opts.global === false) {\n isGlobalConfig = false;\n }\n const configType = isGlobalConfig ? 'global' : 'repo';\n for (const file of files) {\n try {\n if (!(await pathExists(file))) {\n returnVal = 1;\n logger.error({ file }, 'File does not exist');\n break;\n }\n const parsedContent = await getParsedContent(file);\n try {\n logger.info(`Validating ${file} as ${configType} config`);\n await validate(configType, file, parsedContent, strict);\n } catch (err) {\n logger.warn({ file, err }, 'File is not valid Renovate config');\n returnVal = 1;\n }\n } catch (err) {\n logger.warn({ file, err }, 'File could not be parsed');\n returnVal = 1;\n }\n\n filesValidated++;\n }\n } else {\n for (const file of getConfigFileNames().filter(\n (name) => name !== 'package.json',\n )) {\n try {\n if (!(await pathExists(file))) {\n continue;\n }\n const parsedContent = await getParsedContent(file);\n try {\n logger.info(`Validating ${file}`);\n await validate('repo', file, parsedContent, strict);\n } catch (err) {\n logger.warn({ file, err }, 'File is not valid Renovate config');\n returnVal = 1;\n }\n } catch (err) {\n logger.warn({ file, err }, 'File could not be parsed');\n returnVal = 1;\n }\n\n filesValidated++;\n }\n try {\n const pkgJson = JSON.parse(\n await readFile('package.json', 'utf8'),\n ) as PackageJson;\n if (pkgJson.renovate) {\n logger.info(`Validating package.json > renovate`);\n await validate(\n 'repo',\n 'package.json > renovate',\n pkgJson.renovate,\n strict,\n );\n\n filesValidated++;\n }\n if (pkgJson['renovate-config']) {\n logger.info(`Validating package.json > renovate-config`);\n for (const presetConfig of Object.values(\n pkgJson['renovate-config'],\n )) {\n await validate(\n 'repo',\n 'package.json > renovate-config',\n presetConfig,\n strict,\n true,\n );\n\n filesValidated++;\n }\n }\n } catch {\n // ignore\n }\n try {\n const env = getEnv();\n const fileConfig = await getFileConfig(env);\n if (!dequal(fileConfig, {})) {\n const file = env.RENOVATE_CONFIG_FILE ?? 'config.js';\n logger.info(`Validating ${file}`);\n try {\n await validate('global', file, fileConfig, strict);\n } catch (err) {\n logger.error({ file, err }, 'File is not valid Renovate config');\n returnVal = 1;\n }\n filesValidated++;\n }\n } catch {\n // ignore\n }\n }\n if (returnVal === 0 && filesValidated) {\n logger.info(\n `Config validated successfully against ${filesValidated} file(s)`,\n );\n } else if (!filesValidated) {\n logger.warn(`No files to perform configuration validation against`);\n }\n // Use exitCode (not process.exit) so async log streams can flush\n process.exitCode = returnVal;\n });\n\n await program.parseAsync();\n})().catch((e) => {\n // Commander throws an error at the end of Action execution i.e. as part of the `help` and `version` commands, and so we don't want to return an error code in this case\n if (\n e instanceof CommanderError &&\n ['commander.helpDisplayed', 'commander.version'].includes(e.code)\n ) {\n return;\n }\n\n // oxlint-disable-next-line no-console -- intentional: display critical error on CLI\n console.error(e);\n process.exit(99);\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"config-validator.js","names":["getFileConfig"],"sources":["../lib/config-validator.ts"],"sourcesContent":["#!/usr/bin/env node\nimport 'source-map-support/register.js';\nimport './punycode.cjs';\n\nimport { styleText } from 'node:util';\nimport { isNonEmptyStringAndNotWhitespace } from '@sindresorhus/is';\nimport { Command, CommanderError } from 'commander';\nimport { dequal } from 'dequal';\nimport { diffLines } from 'diff';\nimport fs from 'fs-extra';\nimport upath from 'upath';\nimport { getConfigFileNames } from './config/app-strings.ts';\nimport { GlobalConfig } from './config/global.ts';\nimport { massageConfig } from './config/massage.ts';\nimport { stringifyMigratedConfig } from './config/migrated-content.ts';\nimport { migrateConfig } from './config/migration.ts';\nimport type { RenovateConfig } from './config/types.ts';\nimport { validateConfig } from './config/validation.ts';\nimport { pkg } from './expose.ts';\nimport { init, logger } from './logger/index.ts';\nimport { getEnv } from './util/env.ts';\nimport { add as addHostRule } from './util/host-rules.ts';\nimport { regEx, regexEngineStatus } from './util/regex.ts';\nimport { getConfig as getFileConfig } from './workers/global/config/parse/file.ts';\nimport { parseConfigs } from './workers/global/config/parse/index.ts';\nimport { getParsedContent } from './workers/global/config/parse/util.ts';\n\nawait init();\n\nconst { pathExists, readFile, writeFile } = fs;\n\nlet returnVal = 0;\n\n/**\n * Make sure that we've resolved configuration from the different places that Renovate users would expect them to be specified\n *\n * This then allows a `configType=repo` config to i.e. be validated alongside a `config.js` or `env RENOVATE_ALLOWED_COMMANDS=...`\n *\n * Note that we intentionally don't fully initialize Renovate and its modules, as we're not fully running, and it would require a Platform to be configured\n * */\nasync function partiallyGlobalInitialize(): Promise<void> {\n // NOTE that this doesn't allow command-line arguments\n const globalConfig = await parseConfigs(getEnv(), []);\n GlobalConfig.set(globalConfig);\n\n if (globalConfig.hostRules) {\n // this is the self-hosted admin's own config, so its `headers` are exempt from `allowedHeaders` altogether - see `hostRules.add()`\n for (const hostRule of globalConfig.hostRules) {\n addHostRule(hostRule, { trusted: true });\n }\n }\n}\n\ninterface ValidateOptions {\n strict: boolean;\n isPreset?: boolean;\n /** the file to write any needed config migration to, when `--migrate` is set */\n migrateFile?: string;\n}\n\nfunction isMigratableFile(file: string): boolean {\n const basename = upath.basename(file);\n if (basename === 'package.json') {\n return false;\n }\n if (basename === '.renovaterc') {\n return true;\n }\n return ['.json', '.jsonc', '.json5'].includes(upath.extname(file));\n}\n\n/**\n * Writes `migratedConfig` to `file`, returning whether the migration was applied.\n */\nasync function writeMigratedConfig(\n file: string,\n migratedConfig: RenovateConfig,\n): Promise<boolean> {\n if (!isMigratableFile(file)) {\n logger.warn(\n { file },\n 'Config migration cannot be applied automatically to this file type',\n );\n return false;\n }\n\n try {\n const raw = await readFile(file, 'utf8');\n const { content } = stringifyMigratedConfig(file, raw, migratedConfig);\n await writeFile(file, content);\n } catch (err) {\n logger.warn({ file, err }, 'Config migration could not be written');\n return false;\n }\n logger.info(`Applied config migration to ${file}`);\n return true;\n}\n\nasync function validate(\n configType: 'global' | 'repo',\n desc: string,\n config: RenovateConfig,\n { strict, isPreset = false, migrateFile }: ValidateOptions,\n): Promise<void> {\n if (config.hostRules) {\n // a `global` config is the self-hosted administrator's own, so its `headers` are exempt from `allowedHeaders` altogether - see `hostRules.add()`; a `repo` config's `hostRules` are still constrained by this instance's `allowedHeaders`\n for (const hostRule of config.hostRules) {\n addHostRule(hostRule, { trusted: configType === 'global' });\n }\n }\n const { isMigrated, migratedConfig } = migrateConfig(config);\n if (isMigrated) {\n logger.warn(\n {\n oldConfig: config,\n newConfig: migratedConfig,\n },\n 'Config migration necessary',\n );\n const changedObjects = diffLines(\n JSON.stringify(config, null, 2),\n JSON.stringify(migratedConfig, null, 2),\n { ignoreWhitespace: false, newlineIsToken: false },\n );\n const added = styleText('green', '+ ');\n const removed = styleText('red', '- ');\n const msg = changedObjects\n .flatMap((part) => {\n let linePrefix: string;\n if (part.added) {\n linePrefix = added;\n } else if (part.removed) {\n linePrefix = removed;\n } else {\n linePrefix = ' ';\n }\n return part.value\n .split('\\n')\n .filter(isNonEmptyStringAndNotWhitespace)\n .map((line) =>\n line.replace(regEx(/^(?<ws> *)/), `${linePrefix}$<ws>`),\n );\n })\n .join('\\n');\n // oxlint-disable-next-line renovate/logger-static-message -- the multi-line, colorized diff must be interpolated to stay readable; as a metadata field it is JSON-escaped onto one line\n logger.warn(`Config migration diff:\\n${msg}`);\n let isMigrationApplied = false;\n if (migrateFile) {\n isMigrationApplied = await writeMigratedConfig(\n migrateFile,\n migratedConfig,\n );\n }\n if (strict && !isMigrationApplied) {\n returnVal = 1;\n }\n }\n const massagedConfig = massageConfig(migratedConfig);\n const res = await validateConfig(configType, massagedConfig, isPreset);\n if (res.errors.length) {\n logger.error(\n { file: desc, errors: res.errors },\n 'Found errors in configuration',\n );\n returnVal = 1;\n }\n if (res.warnings.length) {\n logger.warn(\n { file: desc, warnings: res.warnings },\n 'Found errors in configuration',\n );\n returnVal = 1;\n }\n}\n\ninterface PackageJson {\n renovate?: RenovateConfig;\n 'renovate-config'?: Record<string, RenovateConfig>;\n}\n\n(async () => {\n await partiallyGlobalInitialize();\n\n const program = new Command('renovate-config-validator')\n .summary('Validate Renovate configuration files')\n .description(\n `Validate your Renovate configuration (repo config, shared presets or global configuration) files\\n` +\n // oxlint-disable-next-line renovate/no-hardcoded-docs-url -- CLI help text, no config available\n 'If no [config-files...] are given, renovate-config-validator will look at the default config file locations (https://docs.renovatebot.com/configuration-options/)',\n )\n .addHelpText(\n 'after',\n // oxlint-disable-next-line renovate/no-hardcoded-docs-url -- CLI help text, no config available\n `\nWhen specifying [config-files...], Renovate will treat them as global self-hosted configuration files. You can disable this behaviour with --no-global\n\nExamples:\n\n $ renovate-config-validator\n $ renovate-config-validator --strict\n $ renovate-config-validator first_config.json\n $ renovate-config-validator --strict config.js\n $ renovate-config-validator --migrate\n $ renovate-config-validator --no-global renovate.json5\n $ env RENOVATE_CONFIG_FILE=obscure-name.json renovate-config-validator\n\nGlobal configuration:\n\nIf you have specified global self-hosted configuration (https://docs.renovatebot.com/self-hosted-configuration/) in environment variables or in a \\`config.js\\`, this will be detected:\n\n $ env RENOVATE_ALLOWED_ENV='[\"GO*\"]' renovate-config-validator\n # if passing the filename, make sure it's not validating as a global config\n $ env RENOVATE_ALLOWED_ENV='[\"GO*\"]' renovate-config-validator --no-global renovate.json`,\n )\n .argument('[config-files...]')\n .version(pkg.version, '-v, --version')\n .option(\n '--strict',\n 'Fail command if any configuration warnings, errors, or a migration is needed',\n )\n .option(\n '--migrate',\n 'Apply any necessary configuration migrations to the JSON, JSONC or JSON5 configuration file(s)',\n )\n .option(\n '--no-global',\n 'When specifying [config-files], do not treat them as global self-hosted configuration file(s)',\n true,\n )\n // allow us to manage the exit code\n .exitOverride();\n\n program.action(async (files, opts) => {\n const strict = opts.strict ?? false;\n const migrate = opts.migrate ?? false;\n let filesValidated = 0;\n\n // without RE2, patterns are checked by RegExp, which accepts syntax RE2 rejects (e.g. lookahead)\n if (regexEngineStatus.type === 'unavailable') {\n logger.warn(\n { err: regexEngineStatus.err },\n 'RE2 not usable, falling back to RegExp: regex validation may be inaccurate',\n );\n } else if (regexEngineStatus.type === 'ignored') {\n logger.debug(\n 'RE2 ignored via RENOVATE_X_IGNORE_RE2: regex validation may be inaccurate',\n );\n }\n\n if (files.length) {\n let isGlobalConfig = true;\n if (opts.global === false) {\n isGlobalConfig = false;\n }\n const configType = isGlobalConfig ? 'global' : 'repo';\n for (const file of files) {\n try {\n if (!(await pathExists(file))) {\n returnVal = 1;\n logger.error({ file }, 'File does not exist');\n break;\n }\n const parsedContent = await getParsedContent(file);\n try {\n logger.info(`Validating ${file} as ${configType} config`);\n await validate(configType, file, parsedContent, {\n strict,\n migrateFile: migrate ? file : undefined,\n });\n } catch (err) {\n logger.warn({ file, err }, 'File is not valid Renovate config');\n returnVal = 1;\n }\n } catch (err) {\n logger.warn({ file, err }, 'File could not be parsed');\n returnVal = 1;\n }\n\n filesValidated++;\n }\n } else {\n for (const file of getConfigFileNames().filter(\n (name) => name !== 'package.json',\n )) {\n try {\n if (!(await pathExists(file))) {\n continue;\n }\n const parsedContent = await getParsedContent(file);\n try {\n logger.info(`Validating ${file}`);\n await validate('repo', file, parsedContent, {\n strict,\n migrateFile: migrate ? file : undefined,\n });\n } catch (err) {\n logger.warn({ file, err }, 'File is not valid Renovate config');\n returnVal = 1;\n }\n } catch (err) {\n logger.warn({ file, err }, 'File could not be parsed');\n returnVal = 1;\n }\n\n filesValidated++;\n }\n try {\n const pkgJson = JSON.parse(\n await readFile('package.json', 'utf8'),\n ) as PackageJson;\n if (pkgJson.renovate) {\n logger.info(`Validating package.json > renovate`);\n await validate('repo', 'package.json > renovate', pkgJson.renovate, {\n strict,\n migrateFile: migrate ? 'package.json' : undefined,\n });\n\n filesValidated++;\n }\n if (pkgJson['renovate-config']) {\n logger.info(`Validating package.json > renovate-config`);\n for (const presetConfig of Object.values(\n pkgJson['renovate-config'],\n )) {\n await validate(\n 'repo',\n 'package.json > renovate-config',\n presetConfig,\n {\n strict,\n isPreset: true,\n migrateFile: migrate ? 'package.json' : undefined,\n },\n );\n\n filesValidated++;\n }\n }\n } catch {\n // ignore\n }\n try {\n const env = getEnv();\n const fileConfig = await getFileConfig(env);\n if (!dequal(fileConfig, {})) {\n const file = env.RENOVATE_CONFIG_FILE ?? 'config.js';\n logger.info(`Validating ${file}`);\n try {\n await validate('global', file, fileConfig, { strict });\n } catch (err) {\n logger.error({ file, err }, 'File is not valid Renovate config');\n returnVal = 1;\n }\n filesValidated++;\n }\n } catch {\n // ignore\n }\n }\n if (returnVal === 0 && filesValidated) {\n logger.info(\n `Config validated successfully against ${filesValidated} file(s)`,\n );\n } else if (!filesValidated) {\n logger.warn(`No files to perform configuration validation against`);\n }\n // Use exitCode (not process.exit) so async log streams can flush\n process.exitCode = returnVal;\n });\n\n await program.parseAsync();\n})().catch((e) => {\n // Commander throws an error at the end of Action execution i.e. as part of the `help` and `version` commands, and so we don't want to return an error code in this case\n if (\n e instanceof CommanderError &&\n ['commander.helpDisplayed', 'commander.version'].includes(e.code)\n ) {\n return;\n }\n\n // oxlint-disable-next-line no-console -- intentional: display critical error on CLI\n console.error(e);\n process.exit(99);\n});\n"],"mappings":"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"}
@@ -12,8 +12,8 @@ import { Datasource } from "../datasource.js";
12
12
  import { parseApkIndexFile } from "./parser.js";
13
13
  import { constructComponentUrls } from "./url.js";
14
14
  import { isNonEmptyObject } from "@sindresorhus/is";
15
- import { randomUUID } from "node:crypto";
16
15
  import upath from "upath";
16
+ import { randomUUID } from "node:crypto";
17
17
  import { extract } from "tar";
18
18
  const defaultConfig = {
19
19
  commitMessageTopic: "{{{depName}}} APK package",
@@ -6,8 +6,8 @@ import { computeFileChecksum, parseChecksumsFromInRelease } from "./checksum.js"
6
6
  import "./common.js";
7
7
  import { checkIfModified, getBaseSuiteUrl } from "./url.js";
8
8
  import { extract, getFileCreationTime } from "./utils.js";
9
- import { randomUUID } from "node:crypto";
10
9
  import upath from "upath";
10
+ import { randomUUID } from "node:crypto";
11
11
  // lib/modules/datasource/deb/packages.ts
12
12
  /**
13
13
  * Downloads and extracts a package file from a component URL.
@@ -5,8 +5,8 @@ import { toSha256 } from "../../../../util/hash.js";
5
5
  import { isNotModified } from "../../../../util/http/status.js";
6
6
  import { acquireLock } from "../../../../util/mutex.js";
7
7
  import { isNullOrUndefined } from "@sindresorhus/is";
8
- import { randomUUID } from "node:crypto";
9
8
  import upath from "upath";
9
+ import { randomUUID } from "node:crypto";
10
10
  // lib/modules/datasource/rpm/providers/common.ts
11
11
  const cacheSubDir = "rpm";
12
12
  function formatRpmVersion(ver, rel) {
@@ -6,8 +6,8 @@ import { collectFileChanges } from "../../../util/git/file-changes.js";
6
6
  import { getRepoStatus } from "../../../util/git/index.js";
7
7
  import { newlineRegex, regEx } from "../../../util/regex.js";
8
8
  import { artifactErrorResult, fileAddition, fileChangesToArtifactResults } from "../util.js";
9
- import { quote } from "shlex";
10
9
  import upath from "upath";
10
+ import { quote } from "shlex";
11
11
  // lib/modules/manager/cocoapods/artifacts.ts
12
12
  const pluginRegex = regEx(`^\\s*plugin\\s*(['"])(?<plugin>[^'"]+)(['"])`);
13
13
  function getPluginCommands(content) {
@@ -5,8 +5,8 @@ import { withGitEnvironment } from "../../../util/git/exec.js";
5
5
  import { collectFileChanges } from "../../../util/git/file-changes.js";
6
6
  import { getRepoStatus, isFileModeEnabled } from "../../../util/git/index.js";
7
7
  import { artifactError, artifactErrorResult, resolveToolConstraint } from "../util.js";
8
- import { quote } from "shlex";
9
8
  import upath from "upath";
9
+ import { quote } from "shlex";
10
10
  // lib/modules/manager/copier/artifacts.ts
11
11
  const DEFAULT_COMMAND_OPTIONS = ["--skip-answered", "--defaults"];
12
12
  const ownerExecutePermission = 64;
@@ -7,8 +7,8 @@ import { processHostRules } from "../npm/post-update/rules.js";
7
7
  import { withNpmrcHostRules } from "../npm/utils.js";
8
8
  import { artifactError, artifactErrorResult, resolveToolConstraint, updateLockFile } from "../util.js";
9
9
  import { isEmptyArray } from "@sindresorhus/is";
10
- import { quote } from "shlex";
11
10
  import upath from "upath";
11
+ import { quote } from "shlex";
12
12
  // lib/modules/manager/deno/artifacts.ts
13
13
  async function updateArtifacts(updateArtifact) {
14
14
  const { packageFileName, updatedDeps, newPackageFileContent, config } = updateArtifact;
@@ -15,8 +15,8 @@ import { artifactErrorResult, fileAddition, fileChangesToArtifactResults, resolv
15
15
  import { getExtraDepsNotice } from "./artifacts-extra.js";
16
16
  import { getGoModulesInTidyOrder } from "./package-tree.js";
17
17
  import { isString } from "@sindresorhus/is";
18
- import { quote } from "shlex";
19
18
  import upath from "upath";
19
+ import { quote } from "shlex";
20
20
  import semver from "semver";
21
21
  // lib/modules/manager/gomod/artifacts.ts
22
22
  const { major: major$1, valid: valid$1 } = semver;
@@ -11,8 +11,8 @@ import { resolveToolConstraint } from "../util.js";
11
11
  import { isGcvLockFile, isGcvPropsFile } from "./extract/consistent-versions-plugin.js";
12
12
  import { isGradleBuildFile } from "./utils.js";
13
13
  import { isNonEmptyStringAndNotWhitespace } from "@sindresorhus/is";
14
- import { quote } from "shlex";
15
14
  import upath from "upath";
15
+ import { quote } from "shlex";
16
16
  // lib/modules/manager/gradle/artifacts.ts
17
17
  function isGradleExecutionAllowed(command) {
18
18
  if (!GlobalConfig.get("allowedUnsafeExecutions").includes("gradleWrapper")) {
@@ -11,8 +11,8 @@ import "../gradle/index.js";
11
11
  import { resolveToolConstraint } from "../util.js";
12
12
  import { extraEnv, getJavaConstraint, gradleWrapperFileName, prepareGradleCommand } from "./utils.js";
13
13
  import { isTruthy } from "@sindresorhus/is";
14
- import { quote } from "shlex";
15
14
  import upath from "upath";
15
+ import { quote } from "shlex";
16
16
  import { lang, query } from "@renovatebot/good-enough-parser";
17
17
  // lib/modules/manager/gradle-wrapper/artifacts.ts
18
18
  const http = new Http("gradle-wrapper");
@@ -8,8 +8,8 @@ import { ecrRegex, getECRAuthToken } from "../../datasource/docker/ecr.js";
8
8
  import { DockerDatasource } from "../../datasource/docker/index.js";
9
9
  import { HelmDatasource } from "../../datasource/helm/index.js";
10
10
  import { removeOCIPrefix } from "./oci.js";
11
- import { quote } from "shlex";
12
11
  import upath from "upath";
12
+ import { quote } from "shlex";
13
13
  import semver from "semver";
14
14
  // lib/modules/manager/helmv3/common.ts
15
15
  async function generateLoginCmd(repositoryRule) {
@@ -4,8 +4,8 @@ import { localPathIsSymbolicLink, readLocalSymlink } from "../../../util/fs/inde
4
4
  import { withGitEnvironment } from "../../../util/git/exec.js";
5
5
  import { getRepoStatus } from "../../../util/git/index.js";
6
6
  import { map } from "../../../util/promises.js";
7
- import { quote } from "shlex";
8
7
  import upath from "upath";
8
+ import { quote } from "shlex";
9
9
  // lib/modules/manager/hermit/artifacts.ts
10
10
  const gitExec = withGitEnvironment(["hermit"]);
11
11
  /**
@@ -10,8 +10,8 @@ import { generateHelmEnvs, generateRegistryLoginCmd, helmRepositoryCredentialArg
10
10
  import { artifactError, artifactErrorResult, fileChangesToArtifactResults, resolveToolConstraint } from "../util.js";
11
11
  import { parseKustomize } from "./extract.js";
12
12
  import { isNonEmptyString, isNullOrUndefined } from "@sindresorhus/is";
13
- import { quote } from "shlex";
14
13
  import upath from "upath";
14
+ import { quote } from "shlex";
15
15
  // lib/modules/manager/kustomize/artifacts.ts
16
16
  async function localExistingChartPath(chartHome, dependencyName, version) {
17
17
  const folderName = `${dependencyName}-${version}`;
@@ -12,8 +12,8 @@ import { MavenDatasource } from "../../datasource/maven/index.js";
12
12
  import { api } from "../../versioning/maven/index.js";
13
13
  import { resolveToolConstraint } from "../util.js";
14
14
  import { isTruthy } from "@sindresorhus/is";
15
- import { quote } from "shlex";
16
15
  import upath from "upath";
16
+ import { quote } from "shlex";
17
17
  import os from "node:os";
18
18
  // lib/modules/manager/maven-wrapper/artifacts.ts
19
19
  const http = new Http("maven-wrapper");
@@ -13,8 +13,8 @@ import { api } from "../../versioning/semver/index.js";
13
13
  import { artifactErrorResult, fileChangesToArtifactResults, resolveToolConstraint, updateLockFile } from "../util.js";
14
14
  import { getConfigType, getLockFileName, getSidecarDir } from "./lockfile.js";
15
15
  import { isNonEmptyStringAndNotWhitespace } from "@sindresorhus/is";
16
- import { quote } from "shlex";
17
16
  import upath from "upath";
17
+ import { quote } from "shlex";
18
18
  // lib/modules/manager/mise/artifacts.ts
19
19
  /**
20
20
  * First mise release that supports the features this manager relies on:
@@ -7,8 +7,8 @@ import { regEx } from "../../../util/regex.js";
7
7
  import { matchRegexOrGlob } from "../../../util/string-match.js";
8
8
  import { updateDependency } from "./update/dependency/index.js";
9
9
  import { isEmptyArray, isNonEmptyObject, isString } from "@sindresorhus/is";
10
- import { isScalar, isSeq, parseDocument } from "yaml";
11
10
  import upath from "upath";
11
+ import { isScalar, isSeq, parseDocument } from "yaml";
12
12
  // lib/modules/manager/npm/artifacts.ts
13
13
  const versionWithHashRegString = "^(?<version>.*)\\+(?<hash>.*)";
14
14
  const sriRegString = "^(?<algo>sha\\d+)-(?<hash>[A-Za-z0-9+/]+={0,2})$";
@@ -17,9 +17,9 @@ import { composeLockFile, parseLockFile } from "../utils.js";
17
17
  import { getNodeToolConstraint } from "./node-version.js";
18
18
  import { getNodeOptions, getPackageManagerVersion, lazyLoadPackageJson } from "./utils.js";
19
19
  import { isNonEmptyString, isNullOrUndefined, isString } from "@sindresorhus/is";
20
+ import upath from "upath";
20
21
  import { DateTime, Duration } from "luxon";
21
22
  import { quote } from "shlex";
22
- import upath from "upath";
23
23
  import semver from "semver";
24
24
  // lib/modules/manager/npm/post-update/npm.ts
25
25
  async function getNpmConstraintFromPackageLock(lockFileDir, filename) {
@@ -21,8 +21,8 @@ import "../minimum-release-age.js";
21
21
  import { getNodeToolConstraint } from "./node-version.js";
22
22
  import { getInstalledPackageName, getNodeOptions, getPackageManagerVersion, lazyLoadPackageJson } from "./utils.js";
23
23
  import { isNonEmptyString, isNullOrUndefined } from "@sindresorhus/is";
24
- import { quote } from "shlex";
25
24
  import upath from "upath";
25
+ import { quote } from "shlex";
26
26
  // lib/modules/manager/npm/post-update/pnpm.ts
27
27
  function getPnpmConstraintFromUpgrades(upgrades) {
28
28
  for (const upgrade of upgrades) if (upgrade.depName === "pnpm" && upgrade.newVersion) return upgrade.newVersion;
@@ -22,8 +22,8 @@ import "../minimum-release-age.js";
22
22
  import { getNodeToolConstraint } from "./node-version.js";
23
23
  import { getInstalledPackageName, getNodeOptions, getPackageManagerVersion, lazyLoadPackageJson } from "./utils.js";
24
24
  import { isNullOrUndefined, isString } from "@sindresorhus/is";
25
- import { quote } from "shlex";
26
25
  import upath from "upath";
26
+ import { quote } from "shlex";
27
27
  import semver from "semver";
28
28
  // lib/modules/manager/npm/post-update/yarn.ts
29
29
  async function checkYarnrc(lockFileDir) {
@@ -10,8 +10,8 @@ import { createNuGetConfigXml } from "./config-formatter.js";
10
10
  import { GLOBAL_JSON, getDependentPackageFiles } from "./package-tree.js";
11
11
  import { findGlobalJson, getConfiguredRegistries, getDefaultRegistries } from "./util.js";
12
12
  import { isNonEmptyString } from "@sindresorhus/is";
13
- import { quote } from "shlex";
14
13
  import upath from "upath";
14
+ import { quote } from "shlex";
15
15
  // lib/modules/manager/nuget/artifacts.ts
16
16
  async function createCachedNuGetConfigFile(nugetCacheDir, packageFileName, updatedDeps) {
17
17
  const registries = await getConfiguredRegistries(packageFileName) ?? getDefaultRegistries();
@@ -13,8 +13,8 @@ import { UvLockfile } from "../schema.js";
13
13
  import { depTypes } from "../utils.js";
14
14
  import { BasePyProjectProcessor } from "./abstract.js";
15
15
  import { isString } from "@sindresorhus/is";
16
- import { quote } from "shlex";
17
16
  import upath from "upath";
17
+ import { quote } from "shlex";
18
18
  // lib/modules/manager/pep621/processors/uv.ts
19
19
  const uvUpdateCMD = "uv lock";
20
20
  const gitExec = withGitEnvironment(["pep621"]);
@@ -8,8 +8,8 @@ import { parseUrl } from "../../../util/url.js";
8
8
  import { extractPackageFileFlags } from "../pip_requirements/common.js";
9
9
  import { extractHeaderCommand, extractPythonVersion, getExecOptions, getRegistryCredVarsFromPackageFiles, matchManager } from "./common.js";
10
10
  import { inferCommandExecDir } from "./utils.js";
11
- import { quote } from "shlex";
12
11
  import upath from "upath";
12
+ import { quote } from "shlex";
13
13
  // lib/modules/manager/pip-compile/artifacts.ts
14
14
  function haveCredentialsInPipEnvironmentVariables() {
15
15
  const env = getEnv();
@@ -6,8 +6,8 @@ import { regEx } from "../../../util/regex.js";
6
6
  import { parseUrl } from "../../../util/url.js";
7
7
  import { findPypiIndexCredentials } from "../../datasource/pypi/host-rules.js";
8
8
  import { resolveToolConstraint } from "../util.js";
9
- import { split } from "shlex";
10
9
  import upath from "upath";
10
+ import { split } from "shlex";
11
11
  // lib/modules/manager/pip-compile/common.ts
12
12
  async function getPythonVersionConstraint(config, extractedPythonVersion) {
13
13
  return await resolveToolConstraint(config, "python", () => {
@@ -7,9 +7,9 @@ import { hashStream } from "../../../../util/hash.js";
7
7
  import { Http } from "../../../../util/http/index.js";
8
8
  import { map } from "../../../../util/promises.js";
9
9
  import { TerraformProviderDatasource } from "../../../datasource/terraform-provider/index.js";
10
+ import upath from "upath";
10
11
  import crypto from "node:crypto";
11
12
  import { Transform } from "node:stream";
12
- import upath from "upath";
13
13
  import { crc32 } from "node:zlib";
14
14
  import { once } from "node:events";
15
15
  import { openPromise, validateFileName } from "yauzl";
@@ -2,8 +2,8 @@ import { logger } from "../../../../logger/index.js";
2
2
  import { encodeEntry } from "../codec.js";
3
3
  import { PackageCacheBase } from "./base.js";
4
4
  import { isObject } from "@sindresorhus/is";
5
- import { DateTime } from "luxon";
6
5
  import upath from "upath";
6
+ import { DateTime } from "luxon";
7
7
  import cacache from "cacache";
8
8
  // lib/util/cache/package/impl/file.ts
9
9
  var PackageCacheFile = class PackageCacheFile extends PackageCacheBase {
@@ -5,8 +5,8 @@ import { ensureCachePath, ensureLocalPath, isValidPath } from "./util.js";
5
5
  import util from "node:util";
6
6
  import { isNonEmptyString } from "@sindresorhus/is";
7
7
  import fs from "fs-extra";
8
- import stream from "node:stream";
9
8
  import upath from "upath";
9
+ import stream from "node:stream";
10
10
  import { findUp } from "find-up";
11
11
  // lib/util/fs/index.ts
12
12
  const pipeline$1 = util.promisify(stream.pipeline);
@@ -29,8 +29,8 @@ import { GitTreeMode } from "./types.js";
29
29
  import { getCachedUpdateDateResult, setCachedUpdateDateResult } from "./update-date-cache.js";
30
30
  import { isBoolean, isNonEmptyObject, isNonEmptyStringAndNotWhitespace, isNullOrUndefined, isString, isTruthy } from "@sindresorhus/is";
31
31
  import fs from "fs-extra";
32
- import { DateTime } from "luxon";
33
32
  import upath from "upath";
33
+ import { DateTime } from "luxon";
34
34
  import URL from "node:url";
35
35
  import semver from "semver";
36
36
  import { setTimeout } from "node:timers/promises";
@@ -11,8 +11,8 @@ import { initMergeConfidence } from "../../util/merge-confidence/index.js";
11
11
  import { Vulnerabilities } from "../repository/process/vulnerabilities.js";
12
12
  import { setMaxLimit } from "./limits.js";
13
13
  import fs from "fs-extra";
14
- import { configure, isContainerbase, validateContainerbaseVersion } from "@renovatebot/base-image";
15
14
  import upath from "upath";
15
+ import { configure, isContainerbase, validateContainerbaseVersion } from "@renovatebot/base-image";
16
16
  import os from "node:os";
17
17
  // lib/workers/global/initialize.ts
18
18
  async function setDirectories(input) {
@@ -1,3 +1,4 @@
1
+ import { stringifyMigratedConfig } from "../../../../config/migrated-content.js";
1
2
  import { migrateConfig } from "../../../../config/migration.js";
2
3
  import { prettier } from "../../../../expose.js";
3
4
  import { logger } from "../../../../logger/index.js";
@@ -8,10 +9,7 @@ import { EditorConfig } from "../../../../util/json-writer/editor-config.js";
8
9
  import "../../../../util/json-writer/index.js";
9
10
  import { detectRepoFileConfig } from "../../init/merge.js";
10
11
  import { isNumber } from "@sindresorhus/is";
11
- import JSON5 from "json5";
12
- import { weave } from "jsonc-weaver";
13
12
  import upath from "upath";
14
- import detectIndent from "detect-indent";
15
13
  // lib/workers/repository/config-migration/branch/migrated-data.ts
16
14
  const prettierConfigFilenames = /* @__PURE__ */ new Set([
17
15
  ".prettierrc",
@@ -77,20 +75,9 @@ var MigratedDataFactory = class {
77
75
  if (!isMigrated) return null;
78
76
  delete migratedConfig.errors;
79
77
  delete migratedConfig.warnings;
80
- const raw = await platform.getRawFile(configFileName);
81
- const indent = detectIndent(raw ?? "");
82
- const indentSpace = indent.indent ?? " ";
83
78
  const filename = configFileName;
84
- let content;
85
- if (filename.endsWith(".json5")) content = JSON5.stringify(migratedConfig, void 0, indentSpace);
86
- else if (raw) try {
87
- content = weave(raw, migratedConfig);
88
- } catch (err) {
89
- logger.warn({ err }, "Error weaving JSONC to preserve comments, falling back to JSON.stringify");
90
- content = JSON.stringify(migratedConfig, void 0, indentSpace);
91
- }
92
- else content = JSON.stringify(migratedConfig, void 0, indentSpace);
93
- if (!content.endsWith("\n")) content += "\n";
79
+ const raw = await platform.getRawFile(filename);
80
+ const { content, indent } = stringifyMigratedConfig(filename, raw, migratedConfig);
94
81
  res = {
95
82
  content,
96
83
  filename,
@@ -1 +1 @@
1
- {"version":3,"file":"migrated-data.js","names":[],"sources":["../../../../../lib/workers/repository/config-migration/branch/migrated-data.ts"],"sourcesContent":["import { isNumber } from '@sindresorhus/is';\nimport detectIndent from 'detect-indent';\nimport JSON5 from 'json5';\nimport { weave } from 'jsonc-weaver';\nimport type { BuiltInParserName, Options } from 'prettier';\nimport upath from 'upath';\nimport { migrateConfig } from '../../../../config/migration.ts';\nimport { prettier } from '../../../../expose.ts';\nimport { logger } from '../../../../logger/index.ts';\nimport { platform } from '../../../../modules/platform/index.ts';\nimport { scm } from '../../../../modules/platform/scm.ts';\nimport { readLocalFile } from '../../../../util/fs/index.ts';\nimport { EditorConfig } from '../../../../util/json-writer/index.ts';\nimport { detectRepoFileConfig } from '../../init/merge.ts';\n\nexport interface MigratedData {\n content: string;\n filename: string;\n indent: Indent;\n}\n\ninterface Indent {\n amount: number;\n indent: string;\n type?: string;\n}\n\nconst prettierConfigFilenames = new Set([\n '.prettierrc',\n '.prettierrc.json',\n '.prettierrc.yml',\n '.prettierrc.yaml',\n '.prettierrc.json5',\n '.prettierrc.js',\n '.prettierrc.cjs',\n '.prettierrc.mjs',\n 'prettier.config.js',\n 'prettier.config.cjs',\n 'prettier.config.mjs',\n '.prettierrc.toml',\n]);\n\nexport type PrettierParser = BuiltInParserName;\n\nexport async function applyPrettierFormatting(\n filename: string,\n content: string,\n parser: PrettierParser,\n indent?: Indent,\n): Promise<string> {\n try {\n logger.trace('applyPrettierFormatting - START');\n const fileList = await scm.getFileList();\n let prettierExists = fileList.some((file) =>\n prettierConfigFilenames.has(file),\n );\n\n const editorconfigExists = fileList.some(\n (file) => file === '.editorconfig',\n );\n\n if (!prettierExists) {\n try {\n const packageJsonContent = await readLocalFile('package.json', 'utf8');\n prettierExists =\n packageJsonContent && JSON.parse(packageJsonContent).prettier;\n } catch {\n logger.warn(\n 'applyPrettierFormatting - Error processing package.json file',\n );\n }\n }\n\n if (!prettierExists || !parser) {\n return content;\n }\n\n const options: Options = {\n parser,\n tabWidth: indent?.amount === 0 ? 2 : indent?.amount,\n useTabs: indent?.type === 'tab',\n };\n\n if (editorconfigExists) {\n const editorconf = await EditorConfig.getCodeFormat(filename);\n\n // https://github.com/prettier/prettier/blob/bab892242a1f9d8fcae50514b9304bf03f2e25ab/src/config/editorconfig/editorconfig-to-prettier.js#L47\n if (editorconf.maxLineLength) {\n options.printWidth = isNumber(editorconf.maxLineLength)\n ? editorconf.maxLineLength\n : Number.POSITIVE_INFINITY;\n }\n\n // TODO: support editor config `indent_style` and `indent_size`\n }\n\n return prettier().format(content, options);\n } finally {\n logger.trace('applyPrettierFormatting - END');\n }\n}\n\nexport class MigratedDataFactory {\n // singleton\n private static data: MigratedData | null;\n\n static async getAsync(): Promise<MigratedData | null> {\n if (this.data) {\n return this.data;\n }\n const migrated = await this.build();\n\n if (!migrated) {\n return null;\n }\n\n this.data = migrated;\n return this.data;\n }\n\n static reset(): void {\n this.data = null;\n }\n\n static applyPrettierFormatting({\n content,\n filename,\n indent,\n }: MigratedData): Promise<string> {\n const parser = upath.extname(filename).replace('.', '') as PrettierParser;\n return applyPrettierFormatting(filename, content, parser, indent);\n }\n\n private static async build(): Promise<MigratedData | null> {\n let res: MigratedData | null = null;\n try {\n const { configFileName, configFileParsed = {} } =\n await detectRepoFileConfig();\n\n // get migrated config\n const { isMigrated, migratedConfig } = migrateConfig(configFileParsed);\n if (!isMigrated) {\n return null;\n }\n\n delete migratedConfig.errors;\n delete migratedConfig.warnings;\n\n // TODO #22198\n const raw = await platform.getRawFile(configFileName!);\n const indent = detectIndent(raw ?? '');\n // indent defaults to 2 spaces\n const indentSpace = indent.indent ?? ' ';\n const filename = configFileName!;\n let content: string;\n\n if (filename.endsWith('.json5')) {\n content = JSON5.stringify(migratedConfig, undefined, indentSpace);\n } else if (raw) {\n try {\n content = weave(raw, migratedConfig);\n } catch (err) {\n logger.warn(\n { err },\n 'Error weaving JSONC to preserve comments, falling back to JSON.stringify',\n );\n content = JSON.stringify(migratedConfig, undefined, indentSpace);\n }\n } else {\n content = JSON.stringify(migratedConfig, undefined, indentSpace);\n }\n\n if (!content.endsWith('\\n')) {\n content += '\\n';\n }\n\n res = { content, filename, indent };\n } catch (err) {\n logger.debug(\n { err },\n 'MigratedDataFactory.getAsync() Error initializing renovate MigratedData',\n );\n }\n return res;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;AA2BA,MAAM,0CAA0B,IAAI,IAAI;CACtC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AAID,eAAsB,wBACpB,UACA,SACA,QACA,QACiB;CACjB,IAAI;EACF,OAAO,MAAM,iCAAiC;EAC9C,MAAM,WAAW,MAAM,IAAI,YAAY;EACvC,IAAI,iBAAiB,SAAS,MAAM,SAClC,wBAAwB,IAAI,IAAI,CAClC;EAEA,MAAM,qBAAqB,SAAS,MACjC,SAAS,SAAS,eACrB;EAEA,IAAI,CAAC,gBACH,IAAI;GACF,MAAM,qBAAqB,MAAM,cAAc,gBAAgB,MAAM;GACrE,iBACE,sBAAsB,KAAK,MAAM,kBAAkB,CAAC,CAAC;EACzD,QAAQ;GACN,OAAO,KACL,8DACF;EACF;EAGF,IAAI,CAAC,kBAAkB,CAAC,QACtB,OAAO;EAGT,MAAM,UAAmB;GACvB;GACA,UAAU,QAAQ,WAAW,IAAI,IAAI,QAAQ;GAC7C,SAAS,QAAQ,SAAS;EAC5B;EAEA,IAAI,oBAAoB;GACtB,MAAM,aAAa,MAAM,aAAa,cAAc,QAAQ;GAG5D,IAAI,WAAW,eACb,QAAQ,aAAa,SAAS,WAAW,aAAa,IAClD,WAAW,gBACX,OAAO;EAIf;EAEA,OAAO,SAAS,CAAC,CAAC,OAAO,SAAS,OAAO;CAC3C,UAAU;EACR,OAAO,MAAM,+BAA+B;CAC9C;AACF;AAEA,IAAa,sBAAb,MAAiC;CAE/B,OAAe;CAEf,aAAa,WAAyC;EACpD,IAAI,KAAK,MACP,OAAO,KAAK;EAEd,MAAM,WAAW,MAAM,KAAK,MAAM;EAElC,IAAI,CAAC,UACH,OAAO;EAGT,KAAK,OAAO;EACZ,OAAO,KAAK;CACd;CAEA,OAAO,QAAc;EACnB,KAAK,OAAO;CACd;CAEA,OAAO,wBAAwB,EAC7B,SACA,UACA,UACgC;EAEhC,OAAO,wBAAwB,UAAU,SAD1B,MAAM,QAAQ,QAAQ,CAAC,CAAC,QAAQ,KAAK,EACG,GAAG,MAAM;CAClE;CAEA,aAAqB,QAAsC;EACzD,IAAI,MAA2B;EAC/B,IAAI;GACF,MAAM,EAAE,gBAAgB,mBAAmB,CAAC,MAC1C,MAAM,qBAAqB;GAG7B,MAAM,EAAE,YAAY,mBAAmB,cAAc,gBAAgB;GACrE,IAAI,CAAC,YACH,OAAO;GAGT,OAAO,eAAe;GACtB,OAAO,eAAe;GAGtB,MAAM,MAAM,MAAM,SAAS,WAAW,cAAe;GACrD,MAAM,SAAS,aAAa,OAAO,EAAE;GAErC,MAAM,cAAc,OAAO,UAAU;GACrC,MAAM,WAAW;GACjB,IAAI;GAEJ,IAAI,SAAS,SAAS,QAAQ,GAC5B,UAAU,MAAM,UAAU,gBAAgB,KAAA,GAAW,WAAW;QAC3D,IAAI,KACT,IAAI;IACF,UAAU,MAAM,KAAK,cAAc;GACrC,SAAS,KAAK;IACZ,OAAO,KACL,EAAE,IAAI,GACN,0EACF;IACA,UAAU,KAAK,UAAU,gBAAgB,KAAA,GAAW,WAAW;GACjE;QAEA,UAAU,KAAK,UAAU,gBAAgB,KAAA,GAAW,WAAW;GAGjE,IAAI,CAAC,QAAQ,SAAS,IAAI,GACxB,WAAW;GAGb,MAAM;IAAE;IAAS;IAAU;GAAO;EACpC,SAAS,KAAK;GACZ,OAAO,MACL,EAAE,IAAI,GACN,yEACF;EACF;EACA,OAAO;CACT;AACF"}
1
+ {"version":3,"file":"migrated-data.js","names":[],"sources":["../../../../../lib/workers/repository/config-migration/branch/migrated-data.ts"],"sourcesContent":["import { isNumber } from '@sindresorhus/is';\nimport type { BuiltInParserName, Options } from 'prettier';\nimport upath from 'upath';\nimport { stringifyMigratedConfig } from '../../../../config/migrated-content.ts';\nimport { migrateConfig } from '../../../../config/migration.ts';\nimport { prettier } from '../../../../expose.ts';\nimport { logger } from '../../../../logger/index.ts';\nimport { platform } from '../../../../modules/platform/index.ts';\nimport { scm } from '../../../../modules/platform/scm.ts';\nimport { readLocalFile } from '../../../../util/fs/index.ts';\nimport { EditorConfig } from '../../../../util/json-writer/index.ts';\nimport { detectRepoFileConfig } from '../../init/merge.ts';\n\nexport interface MigratedData {\n content: string;\n filename: string;\n indent: Indent;\n}\n\ninterface Indent {\n amount: number;\n indent: string;\n type?: string;\n}\n\nconst prettierConfigFilenames = new Set([\n '.prettierrc',\n '.prettierrc.json',\n '.prettierrc.yml',\n '.prettierrc.yaml',\n '.prettierrc.json5',\n '.prettierrc.js',\n '.prettierrc.cjs',\n '.prettierrc.mjs',\n 'prettier.config.js',\n 'prettier.config.cjs',\n 'prettier.config.mjs',\n '.prettierrc.toml',\n]);\n\nexport type PrettierParser = BuiltInParserName;\n\nexport async function applyPrettierFormatting(\n filename: string,\n content: string,\n parser: PrettierParser,\n indent?: Indent,\n): Promise<string> {\n try {\n logger.trace('applyPrettierFormatting - START');\n const fileList = await scm.getFileList();\n let prettierExists = fileList.some((file) =>\n prettierConfigFilenames.has(file),\n );\n\n const editorconfigExists = fileList.some(\n (file) => file === '.editorconfig',\n );\n\n if (!prettierExists) {\n try {\n const packageJsonContent = await readLocalFile('package.json', 'utf8');\n prettierExists =\n packageJsonContent && JSON.parse(packageJsonContent).prettier;\n } catch {\n logger.warn(\n 'applyPrettierFormatting - Error processing package.json file',\n );\n }\n }\n\n if (!prettierExists || !parser) {\n return content;\n }\n\n const options: Options = {\n parser,\n tabWidth: indent?.amount === 0 ? 2 : indent?.amount,\n useTabs: indent?.type === 'tab',\n };\n\n if (editorconfigExists) {\n const editorconf = await EditorConfig.getCodeFormat(filename);\n\n // https://github.com/prettier/prettier/blob/bab892242a1f9d8fcae50514b9304bf03f2e25ab/src/config/editorconfig/editorconfig-to-prettier.js#L47\n if (editorconf.maxLineLength) {\n options.printWidth = isNumber(editorconf.maxLineLength)\n ? editorconf.maxLineLength\n : Number.POSITIVE_INFINITY;\n }\n\n // TODO: support editor config `indent_style` and `indent_size`\n }\n\n return prettier().format(content, options);\n } finally {\n logger.trace('applyPrettierFormatting - END');\n }\n}\n\nexport class MigratedDataFactory {\n // singleton\n private static data: MigratedData | null;\n\n static async getAsync(): Promise<MigratedData | null> {\n if (this.data) {\n return this.data;\n }\n const migrated = await this.build();\n\n if (!migrated) {\n return null;\n }\n\n this.data = migrated;\n return this.data;\n }\n\n static reset(): void {\n this.data = null;\n }\n\n static applyPrettierFormatting({\n content,\n filename,\n indent,\n }: MigratedData): Promise<string> {\n const parser = upath.extname(filename).replace('.', '') as PrettierParser;\n return applyPrettierFormatting(filename, content, parser, indent);\n }\n\n private static async build(): Promise<MigratedData | null> {\n let res: MigratedData | null = null;\n try {\n const { configFileName, configFileParsed = {} } =\n await detectRepoFileConfig();\n\n // get migrated config\n const { isMigrated, migratedConfig } = migrateConfig(configFileParsed);\n if (!isMigrated) {\n return null;\n }\n\n delete migratedConfig.errors;\n delete migratedConfig.warnings;\n\n // TODO #22198\n const filename = configFileName!;\n const raw = await platform.getRawFile(filename);\n const { content, indent } = stringifyMigratedConfig(\n filename,\n raw,\n migratedConfig,\n );\n\n res = { content, filename, indent };\n } catch (err) {\n logger.debug(\n { err },\n 'MigratedDataFactory.getAsync() Error initializing renovate MigratedData',\n );\n }\n return res;\n }\n}\n"],"mappings":";;;;;;;;;;;;;AAyBA,MAAM,0CAA0B,IAAI,IAAI;CACtC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AAID,eAAsB,wBACpB,UACA,SACA,QACA,QACiB;CACjB,IAAI;EACF,OAAO,MAAM,iCAAiC;EAC9C,MAAM,WAAW,MAAM,IAAI,YAAY;EACvC,IAAI,iBAAiB,SAAS,MAAM,SAClC,wBAAwB,IAAI,IAAI,CAClC;EAEA,MAAM,qBAAqB,SAAS,MACjC,SAAS,SAAS,eACrB;EAEA,IAAI,CAAC,gBACH,IAAI;GACF,MAAM,qBAAqB,MAAM,cAAc,gBAAgB,MAAM;GACrE,iBACE,sBAAsB,KAAK,MAAM,kBAAkB,CAAC,CAAC;EACzD,QAAQ;GACN,OAAO,KACL,8DACF;EACF;EAGF,IAAI,CAAC,kBAAkB,CAAC,QACtB,OAAO;EAGT,MAAM,UAAmB;GACvB;GACA,UAAU,QAAQ,WAAW,IAAI,IAAI,QAAQ;GAC7C,SAAS,QAAQ,SAAS;EAC5B;EAEA,IAAI,oBAAoB;GACtB,MAAM,aAAa,MAAM,aAAa,cAAc,QAAQ;GAG5D,IAAI,WAAW,eACb,QAAQ,aAAa,SAAS,WAAW,aAAa,IAClD,WAAW,gBACX,OAAO;EAIf;EAEA,OAAO,SAAS,CAAC,CAAC,OAAO,SAAS,OAAO;CAC3C,UAAU;EACR,OAAO,MAAM,+BAA+B;CAC9C;AACF;AAEA,IAAa,sBAAb,MAAiC;CAE/B,OAAe;CAEf,aAAa,WAAyC;EACpD,IAAI,KAAK,MACP,OAAO,KAAK;EAEd,MAAM,WAAW,MAAM,KAAK,MAAM;EAElC,IAAI,CAAC,UACH,OAAO;EAGT,KAAK,OAAO;EACZ,OAAO,KAAK;CACd;CAEA,OAAO,QAAc;EACnB,KAAK,OAAO;CACd;CAEA,OAAO,wBAAwB,EAC7B,SACA,UACA,UACgC;EAEhC,OAAO,wBAAwB,UAAU,SAD1B,MAAM,QAAQ,QAAQ,CAAC,CAAC,QAAQ,KAAK,EACG,GAAG,MAAM;CAClE;CAEA,aAAqB,QAAsC;EACzD,IAAI,MAA2B;EAC/B,IAAI;GACF,MAAM,EAAE,gBAAgB,mBAAmB,CAAC,MAC1C,MAAM,qBAAqB;GAG7B,MAAM,EAAE,YAAY,mBAAmB,cAAc,gBAAgB;GACrE,IAAI,CAAC,YACH,OAAO;GAGT,OAAO,eAAe;GACtB,OAAO,eAAe;GAGtB,MAAM,WAAW;GACjB,MAAM,MAAM,MAAM,SAAS,WAAW,QAAQ;GAC9C,MAAM,EAAE,SAAS,WAAW,wBAC1B,UACA,KACA,cACF;GAEA,MAAM;IAAE;IAAS;IAAU;GAAO;EACpC,SAAS,KAAK;GACZ,OAAO,MACL,EAAE,IAAI,GACN,yEACF;EACF;EACA,OAAO;CACT;AACF"}
@@ -13,8 +13,8 @@ import { titleCase } from "../../../util/string.js";
13
13
  import { datasourceToOsvEcosystem } from "../../../util/vulnerability/ecosystem.js";
14
14
  import { getFixedVersionConstraint, getLastAffectedVersionConstraint } from "../../../util/vulnerability/utils.js";
15
15
  import { isEmptyArray, isNonEmptyString, isNullOrUndefined, isTruthy } from "@sindresorhus/is";
16
- import { z } from "zod/v4";
17
16
  import upath from "upath";
17
+ import { z } from "zod/v4";
18
18
  import aeCvss from "ae-cvss-calculator";
19
19
  // lib/workers/repository/process/vulnerabilities.ts
20
20
  const { fromVector } = aeCvss;
@@ -12,8 +12,8 @@ import { regEx } from "../../../../util/regex.js";
12
12
  import { sanitize } from "../../../../util/sanitize.js";
13
13
  import { compile } from "../../../../util/template/index.js";
14
14
  import { isNonEmptyArray, isString } from "@sindresorhus/is";
15
- import crypto from "node:crypto";
16
15
  import upath from "upath";
16
+ import crypto from "node:crypto";
17
17
  // lib/workers/repository/update/branch/execute-post-upgrade-commands.ts
18
18
  const ownerExecutePermission = 64;
19
19
  const gitExec = withGitEnvironment();
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "renovate",
3
3
  "description": "Automated dependency updates. Flexible so you don't need to be.",
4
- "version": "44.238.3",
4
+ "version": "44.239.1",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "renovate": "dist/renovate.js",
@@ -114,7 +114,7 @@
114
114
  "@opentelemetry/resource-detector-github": "0.34.1",
115
115
  "@opentelemetry/resources": "3.1.0",
116
116
  "@opentelemetry/sdk-trace": "3.1.0",
117
- "@opentelemetry/semantic-conventions": "1.44.0",
117
+ "@opentelemetry/semantic-conventions": "1.45.0",
118
118
  "@pnpm/parse-overrides": "1001.0.4",
119
119
  "@qnighy/marshal": "0.1.3",
120
120
  "@redis/client": "6.3.1",
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "$id": "https://docs.renovatebot.com/renovate-schema.json",
3
- "title": "JSON schema for Renovate 44.238.3 config files (https://renovatebot.com/)",
3
+ "title": "JSON schema for Renovate 44.239.1 config files (https://renovatebot.com/)",
4
4
  "$schema": "http://json-schema.org/draft-07/schema#",
5
- "x-renovate-version": "44.238.3",
5
+ "x-renovate-version": "44.239.1",
6
6
  "allowComments": true,
7
7
  "type": "object",
8
8
  "definitions": {