renovate-mcp 1.5.5 → 1.6.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/README.md +10 -8
- package/dist/data/managers.generated.js +2 -2
- package/dist/data/migrations.generated.js +95 -7
- package/dist/data/options.generated.js +13 -3
- package/dist/data/presets.generated.js +2 -2
- package/dist/lib/configExplainer.js +9 -15
- package/dist/lib/configLinter.js +38 -30
- package/dist/lib/configLocations.js +8 -7
- package/dist/lib/configWriter.js +27 -58
- package/dist/lib/customManagerPreview.js +226 -154
- package/dist/lib/dependencyExplainer.js +1 -1
- package/dist/lib/dryRunDiff.js +0 -0
- package/dist/lib/endpointProbe.js +11 -15
- package/dist/lib/endpointValidator.js +38 -58
- package/dist/lib/externalPresetFetcher.js +56 -112
- package/dist/lib/hostRulesConfig.js +10 -7
- package/dist/lib/lookupProblems.js +6 -8
- package/dist/lib/mergeWorker.js +3 -59
- package/dist/lib/mergeWorkerImpl.js +1 -1
- package/dist/lib/migrationWorker.js +3 -58
- package/dist/lib/packageRulesAnalysis.js +30 -4
- package/dist/lib/packageRulesWorker.js +6 -52
- package/dist/lib/packageRulesWorkerImpl.js +3 -7
- package/dist/lib/presetResolver.js +23 -28
- package/dist/lib/presetSuggester.js +3 -8
- package/dist/lib/renovateCli.js +121 -13
- package/dist/lib/renovateWorker.js +61 -0
- package/dist/lib/runtimeWarnings.js +6 -17
- package/dist/lib/setupCheck.js +19 -2
- package/dist/lib/toolInputs.js +41 -0
- package/dist/lib/uriVariable.js +14 -0
- package/dist/lib/util.js +10 -0
- package/dist/lib/version.js +1 -1
- package/dist/prompts/workflows.js +1 -1
- package/dist/resources/options.js +3 -7
- package/dist/resources/presets.js +7 -15
- package/dist/tools/annotateDryRun.js +14 -38
- package/dist/tools/checkSetup.js +3 -7
- package/dist/tools/dryRun.js +89 -81
- package/dist/tools/dryRunDiff.js +24 -25
- package/dist/tools/explainConfig.js +8 -35
- package/dist/tools/explainDependency.js +20 -28
- package/dist/tools/lintConfig.js +11 -6
- package/dist/tools/migrateConfig.js +6 -0
- package/dist/tools/previewCustomManager.js +15 -7
- package/dist/tools/readConfig.js +4 -0
- package/dist/tools/resolveConfig.js +8 -35
- package/dist/tools/resolveConfigDiff.js +6 -19
- package/dist/tools/testPackageRules.js +12 -47
- package/dist/tools/validateConfig.js +22 -5
- package/dist/tools/writeConfig.js +45 -20
- package/package.json +4 -6
- package/dist/data/managers.generated.d.ts +0 -12
- package/dist/data/migrations.generated.d.ts +0 -15
- package/dist/data/options.generated.d.ts +0 -21
- package/dist/data/presets.generated.d.ts +0 -8
- package/dist/index.d.ts +0 -2
- package/dist/lib/configExplainer.d.ts +0 -63
- package/dist/lib/configLinter.d.ts +0 -11
- package/dist/lib/configLocations.d.ts +0 -9
- package/dist/lib/configWriter.d.ts +0 -48
- package/dist/lib/credentialResolver.d.ts +0 -13
- package/dist/lib/customManagerPreview.d.ts +0 -80
- package/dist/lib/dependencyExplainer.d.ts +0 -48
- package/dist/lib/dryRunDiff.d.ts +0 -79
- package/dist/lib/dryRunProgress.d.ts +0 -24
- package/dist/lib/endpointProbe.d.ts +0 -20
- package/dist/lib/endpointValidator.d.ts +0 -17
- package/dist/lib/externalPresetFetcher.d.ts +0 -22
- package/dist/lib/gitRemote.d.ts +0 -28
- package/dist/lib/hostRulesConfig.d.ts +0 -26
- package/dist/lib/inputLimits.d.ts +0 -22
- package/dist/lib/log.d.ts +0 -1
- package/dist/lib/lookupProblems.d.ts +0 -19
- package/dist/lib/mergeWorker.d.ts +0 -34
- package/dist/lib/mergeWorkerImpl.d.ts +0 -1
- package/dist/lib/migrationWorker.d.ts +0 -22
- package/dist/lib/migrationWorkerImpl.d.ts +0 -1
- package/dist/lib/packageRulesAnalysis.d.ts +0 -89
- package/dist/lib/packageRulesWorker.d.ts +0 -49
- package/dist/lib/packageRulesWorkerImpl.d.ts +0 -1
- package/dist/lib/presetResolver.d.ts +0 -145
- package/dist/lib/presetSuggester.d.ts +0 -125
- package/dist/lib/renovateCli.d.ts +0 -71
- package/dist/lib/reportInput.d.ts +0 -13
- package/dist/lib/resolveConfigDiff.d.ts +0 -50
- package/dist/lib/runtimeWarnings.d.ts +0 -45
- package/dist/lib/setupCheck.d.ts +0 -139
- package/dist/lib/version.d.ts +0 -9
- package/dist/prompts/workflows.d.ts +0 -2
- package/dist/resources/options.d.ts +0 -9
- package/dist/resources/presets.d.ts +0 -2
- package/dist/tools/annotateDryRun.d.ts +0 -2
- package/dist/tools/checkSetup.d.ts +0 -2
- package/dist/tools/dryRun.d.ts +0 -10
- package/dist/tools/dryRunDiff.d.ts +0 -2
- package/dist/tools/explainConfig.d.ts +0 -2
- package/dist/tools/explainDependency.d.ts +0 -2
- package/dist/tools/getVersion.d.ts +0 -2
- package/dist/tools/lintConfig.d.ts +0 -2
- package/dist/tools/migrateConfig.d.ts +0 -2
- package/dist/tools/previewCustomManager.d.ts +0 -2
- package/dist/tools/readConfig.d.ts +0 -2
- package/dist/tools/resolveConfig.d.ts +0 -2
- package/dist/tools/resolveConfigDiff.d.ts +0 -2
- package/dist/tools/suggestPresets.d.ts +0 -2
- package/dist/tools/testPackageRules.d.ts +0 -2
- package/dist/tools/validateConfig.d.ts +0 -2
- package/dist/tools/writeConfig.d.ts +0 -2
package/README.md
CHANGED
|
@@ -32,7 +32,7 @@ Restart your client and try the prompt: *"List the namespaces available under `r
|
|
|
32
32
|
|
|
33
33
|
- **Read and explain configs** — locate the active `renovate.json*`, expand every `extends` preset offline, and trace which preset set each field.
|
|
34
34
|
- **Discover presets from intent** — describe what you want ("automerge patches, group dev deps") and get ranked built-in (and your own local-repo) presets, plus a draft config skeleton when nothing fits.
|
|
35
|
-
- **Preview custom managers** before running Renovate — regex and JSONata, with file/line hits and extracted dep info.
|
|
35
|
+
- **Preview custom managers** before running Renovate — regex and JSONata, with Renovate's `managerFilePatterns` glob/regex file selection, file/line hits and extracted dep info.
|
|
36
36
|
- **Validate and lint** — schema validation plus a semantic lint pass for Renovate-specific footguns (unwrapped regexes, unknown manager names, deprecated keys).
|
|
37
37
|
- **Dry-run** against a local checkout or a remote GitHub/GitLab — see exactly which PRs Renovate would open.
|
|
38
38
|
- **Save back atomically** — round-trip writes preserve comments and key order in existing JSON-with-comments files.
|
|
@@ -80,7 +80,7 @@ Seventeen tools, six resources, and three workflow prompts. Each tool name below
|
|
|
80
80
|
- **Linux or macOS.** Windows is not supported — `package.json` declares `"os": ["darwin", "linux"]`, so `npm i` surfaces an `EBADPLATFORM` warning on Windows and the server exits with a clear stderr message at startup. Use WSL2 or a Linux/macOS host instead.
|
|
81
81
|
- **Node.js ≥ 24** (aligns with Renovate's own engine requirement).
|
|
82
82
|
|
|
83
|
-
Renovate ships bundled — the `renovate` package is a runtime dependency, so `validate_config`, `dry_run`, and `write_config` work out of the box with no separate install. The offline tools (`read_config`, `suggest_presets`, `resolve_config`, `explain_config`, `resolve_config_diff`, `preview_custom_manager`, `lint_config`, `explain_dependency`) never spawn Renovate at all.
|
|
83
|
+
Renovate ships bundled — the `renovate` package is a runtime dependency, so `validate_config`, `dry_run`, and `write_config` work out of the box with no separate install. The offline tools (`read_config`, `suggest_presets`, `resolve_config`, `explain_config`, `resolve_config_diff`, `test_package_rules`, `preview_custom_manager`, `lint_config`, `dry_run_diff`, `annotate_dry_run`, `explain_dependency`, `migrate_config`) never spawn Renovate at all — nor do `check_setup` (by default it reads version metadata from the bundled install instead of spawning) or `get_version` (it only reports the renovate-mcp server's own version).
|
|
84
84
|
|
|
85
85
|
**Optional env vars:**
|
|
86
86
|
|
|
@@ -156,8 +156,9 @@ Once the server is wired up, try prompts like these. Written for Claude but work
|
|
|
156
156
|
|
|
157
157
|
**Authoring a custom manager (regex or JSONata)**
|
|
158
158
|
|
|
159
|
-
- "I have `# renovate: datasource=docker depName=...` comments above image tags in my Dockerfiles. Draft a `customManagers` regex entry and preview it against this repo so I can see what it extracts."
|
|
160
|
-
- "Here's a `customManagers` entry — preview it and tell me which files match
|
|
159
|
+
- "I have `# renovate: datasource=docker depName=...` comments above image tags in my Dockerfiles. Draft a `customManagers` regex entry with `managerFilePatterns: ["**/Dockerfile"]` and preview it against this repo so I can see what it extracts."
|
|
160
|
+
- "Here's a `customManagers` entry — preview it and tell me which files match `managerFilePatterns`, which lines hit each `matchStrings` regex, and what dep info gets extracted."
|
|
161
|
+
- "My custom manager still uses `fileMatch`. Lint the config, then run `migrate_config` so it becomes `managerFilePatterns`."
|
|
161
162
|
- "Draft a `customType: \"jsonata\"` customManager with `fileFormat: \"yaml\"` to extract Helm chart dependencies (`name`, `version`, `repository`) from `Chart.yaml`, and preview it against this repo."
|
|
162
163
|
|
|
163
164
|
**Validating, previewing, saving**
|
|
@@ -173,8 +174,8 @@ A transcript-style walkthrough: design a Dockerfile custom manager from scratch,
|
|
|
173
174
|
|
|
174
175
|
> **You:** I've got `# renovate: datasource=docker depName=<image>` comments above `FROM` lines in my Dockerfiles. Draft a `customManagers` entry and preview it against this repo.
|
|
175
176
|
>
|
|
176
|
-
> **Claude** calls `preview_custom_manager` with a first-draft `
|
|
177
|
-
> → 4 Dockerfiles matched `
|
|
177
|
+
> **Claude** calls `preview_custom_manager` with a first-draft `managerFilePatterns` (`**/Dockerfile`) + `matchStrings`.
|
|
178
|
+
> → 4 Dockerfiles matched `managerFilePatterns`, 0 lines matched `matchStrings`. The regex anchored on `ARG`, but the Dockerfiles use `FROM`.
|
|
178
179
|
>
|
|
179
180
|
> **You:** Rewrite `matchStrings` to anchor on the renovate comment, then `FROM <image>:<version>` on the next line.
|
|
180
181
|
>
|
|
@@ -207,6 +208,7 @@ npm run generate:presets # regenerate src/data/presets.generated.ts
|
|
|
207
208
|
npm run generate:managers # regenerate src/data/managers.generated.ts
|
|
208
209
|
npm run generate:migrations # regenerate src/data/migrations.generated.ts
|
|
209
210
|
npm run generate:options # regenerate src/data/options.generated.ts
|
|
211
|
+
npm run sync:jsonata-pin # sync package.json's jsonata pin to Renovate's own
|
|
210
212
|
npm run check:snapshot-versions # fail if any src/data/*.generated.ts is stale vs installed renovate
|
|
211
213
|
```
|
|
212
214
|
|
|
@@ -225,5 +227,5 @@ See [`docs/development.md`](docs/development.md) for snapshot-file mechanics, CI
|
|
|
225
227
|
|
|
226
228
|
- **Not a Renovate replacement.** This server doesn't open PRs, run scheduled updates, or execute in CI — it's a design-time companion for a local `renovate.json`. Use the real Renovate for the actual dependency-update pipeline.
|
|
227
229
|
- **`resolve_config` merges faithfully.** Preset expansion runs offline against a committed snapshot, then folds with Renovate's real `mergeChildConfig` in a worker thread — `mergeQuality: "faithful"` (it falls back to an approximate in-process merge as `"preview"` only if the worker is unavailable). Template substitution still implements only positional `{{argN}}` placeholders — non-positional tokens and Handlebars helpers are flagged in `warnings` and pass through verbatim. For full config resolution (datasource lookups, etc.), run `dry_run`.
|
|
228
|
-
- **`preview_custom_manager` is a subset of Renovate's custom managers.** It covers `customType: "regex"` (with `matchStringsStrategy` of `any` / `combination` / `recursive`) and `customType: "jsonata"` (with `fileFormat: "json" | "yaml" | "toml"`). Template substitution is `{{groupName}}` only — full Handlebars helpers/conditionals are not implemented. Other custom types (e.g. `html`) are out of scope. Use it for fast iteration; confirm with `dry_run`. Full coverage matrix in [`docs/tools.md#preview_custom_manager`](docs/tools.md#preview_custom_manager).
|
|
229
|
-
- **`
|
|
230
|
+
- **`preview_custom_manager` is a subset of Renovate's custom managers.** It covers `customType: "regex"` (with `matchStringsStrategy` of `any` / `combination` / `recursive`) and `customType: "jsonata"` (with `fileFormat: "json" | "yaml" | "toml"`). File selection follows Renovate's `managerFilePatterns` semantics (globs or `/regex/`, entries unioned like Renovate's extract phase); the deprecated `fileMatch` is still accepted with a warning. Template substitution is `{{groupName}}` only — full Handlebars helpers/conditionals are not implemented. Other custom types (e.g. `html`) are out of scope. Use it for fast iteration; confirm with `dry_run`. Full coverage matrix in [`docs/tools.md#preview_custom_manager`](docs/tools.md#preview_custom_manager).
|
|
231
|
+
- **`dry_run` still uses fake binaries in CI.** The bundled Renovate is available (it's a runtime dependency), and `validate_config` / `write_config` now have one real-validator integration test (`test/integration/realValidator.test.ts`) exercising the actual bundled `renovate-config-validator` — but `dry_run` itself still runs per-PR against fake binaries via `RENOVATE_BIN` / `RENOVATE_CONFIG_VALIDATOR_BIN` env overrides, for determinism and speed. A separate nightly workflow re-runs the full suite against `renovate@latest` end-to-end. Run `dry_run` locally against a real config to validate behaviour.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
// AUTO-GENERATED by scripts/generate-managers.mjs from renovate@44.
|
|
1
|
+
// AUTO-GENERATED by scripts/generate-managers.mjs from renovate@44.115.10.
|
|
2
2
|
// Do not edit by hand. Run `npm run generate:managers` to refresh.
|
|
3
|
-
export const RENOVATE_VERSION = "44.
|
|
3
|
+
export const RENOVATE_VERSION = "44.115.10";
|
|
4
4
|
/**
|
|
5
5
|
* All manager names accepted by Renovate's `matchManagers` /
|
|
6
6
|
* `excludeManagers` fields. Includes both regular managers and custom
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
// AUTO-GENERATED by scripts/generate-migrations.mjs from renovate@44.
|
|
1
|
+
// AUTO-GENERATED by scripts/generate-migrations.mjs from renovate@44.115.10.
|
|
2
2
|
// Do not edit by hand. Run `npm run generate:migrations` to refresh.
|
|
3
|
-
export const RENOVATE_VERSION = "44.
|
|
3
|
+
export const RENOVATE_VERSION = "44.115.10";
|
|
4
4
|
/**
|
|
5
|
-
* Deprecated config keys
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
5
|
+
* Deprecated config keys. Sourced from Renovate's `MigrationsService`:
|
|
6
|
+
* `renamedProperties` (plain renames, with `newKey`) plus every
|
|
7
|
+
* `customMigrations` class flagged `deprecated` (value coercions such as
|
|
8
|
+
* `stabilityDays` → `minimumReleaseAge`, structural rewrites such as
|
|
9
|
+
* `fileMatch` → `managerFilePatterns`; no `newKey` — `migrate_config`
|
|
10
|
+
* shows the replacement).
|
|
10
11
|
*/
|
|
11
12
|
export const DEPRECATED_KEYS = Object.freeze([
|
|
12
13
|
{
|
|
@@ -21,14 +22,29 @@ export const DEPRECATED_KEYS = Object.freeze([
|
|
|
21
22
|
"oldKey": "allowedPostUpgradeCommands",
|
|
22
23
|
"newKey": "allowedCommands"
|
|
23
24
|
},
|
|
25
|
+
{
|
|
26
|
+
"oldKey": "automergeMajor"
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"oldKey": "automergeMinor"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"oldKey": "automergePatch"
|
|
33
|
+
},
|
|
24
34
|
{
|
|
25
35
|
"oldKey": "azureAutoApprove",
|
|
26
36
|
"newKey": "autoApprove"
|
|
27
37
|
},
|
|
38
|
+
{
|
|
39
|
+
"oldKey": "baseBranch"
|
|
40
|
+
},
|
|
28
41
|
{
|
|
29
42
|
"oldKey": "baseBranches",
|
|
30
43
|
"newKey": "baseBranchPatterns"
|
|
31
44
|
},
|
|
45
|
+
{
|
|
46
|
+
"oldKey": "compatibility"
|
|
47
|
+
},
|
|
32
48
|
{
|
|
33
49
|
"oldKey": "customChangelogUrl",
|
|
34
50
|
"newKey": "changelogUrl"
|
|
@@ -45,6 +61,24 @@ export const DEPRECATED_KEYS = Object.freeze([
|
|
|
45
61
|
"oldKey": "exposeEnv",
|
|
46
62
|
"newKey": "exposeAllEnv"
|
|
47
63
|
},
|
|
64
|
+
{
|
|
65
|
+
"oldKey": "fetchReleaseNotes"
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"oldKey": "fileMatch"
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
"oldKey": "gomodTidy"
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
"oldKey": "ignoreNodeModules"
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"oldKey": "ignoreNpmrcFile"
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"oldKey": "includeForks"
|
|
81
|
+
},
|
|
48
82
|
{
|
|
49
83
|
"oldKey": "keepalive",
|
|
50
84
|
"newKey": "keepAlive"
|
|
@@ -89,6 +123,33 @@ export const DEPRECATED_KEYS = Object.freeze([
|
|
|
89
123
|
"oldKey": "multipleMajorPrs",
|
|
90
124
|
"newKey": "separateMultipleMajor"
|
|
91
125
|
},
|
|
126
|
+
{
|
|
127
|
+
"oldKey": "packageFiles"
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
"oldKey": "packageName"
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
"oldKey": "packagePattern"
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
"oldKey": "packages"
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
"oldKey": "pathRules"
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
"oldKey": "pinVersions"
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
"oldKey": "rebaseConflictedPrs"
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
"oldKey": "rebaseStalePrs"
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
"oldKey": "recreateClosed"
|
|
152
|
+
},
|
|
92
153
|
{
|
|
93
154
|
"oldKey": "regexManagers",
|
|
94
155
|
"newKey": "customManagers"
|
|
@@ -97,12 +158,39 @@ export const DEPRECATED_KEYS = Object.freeze([
|
|
|
97
158
|
"oldKey": "renovate-config-presets",
|
|
98
159
|
"newKey": "renovate-config"
|
|
99
160
|
},
|
|
161
|
+
{
|
|
162
|
+
"oldKey": "renovateFork"
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
"oldKey": "requiredStatusChecks"
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
"oldKey": "semanticPrefix"
|
|
169
|
+
},
|
|
100
170
|
{
|
|
101
171
|
"oldKey": "separatePatchReleases",
|
|
102
172
|
"newKey": "separateMinorPatch"
|
|
103
173
|
},
|
|
174
|
+
{
|
|
175
|
+
"oldKey": "stabilityDays"
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
"oldKey": "trustLevel"
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
"oldKey": "unpublishSafe"
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
"oldKey": "updateLockFiles"
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
"oldKey": "upgradeInRange"
|
|
188
|
+
},
|
|
104
189
|
{
|
|
105
190
|
"oldKey": "versionScheme",
|
|
106
191
|
"newKey": "versioning"
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
"oldKey": "versionStrategy"
|
|
107
195
|
}
|
|
108
196
|
]);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
// AUTO-GENERATED by scripts/generate-options.mjs from renovate@44.
|
|
1
|
+
// AUTO-GENERATED by scripts/generate-options.mjs from renovate@44.115.10.
|
|
2
2
|
// Do not edit by hand. Run `npm run generate:options` to refresh.
|
|
3
|
-
export const RENOVATE_VERSION = "44.
|
|
3
|
+
export const RENOVATE_VERSION = "44.115.10";
|
|
4
4
|
export const OPTIONS = {
|
|
5
5
|
"abandonmentThreshold": {
|
|
6
6
|
"description": "Flags packages that have not been updated within this period as abandoned.",
|
|
@@ -1403,7 +1403,7 @@ export const OPTIONS = {
|
|
|
1403
1403
|
"dockerSidecarImage": {
|
|
1404
1404
|
"description": "Change this value to override the default Renovate sidecar image.",
|
|
1405
1405
|
"type": "string",
|
|
1406
|
-
"default": "ghcr.io/renovatebot/base-image:13.
|
|
1406
|
+
"default": "ghcr.io/renovatebot/base-image:13.102.5",
|
|
1407
1407
|
"globalOnly": true,
|
|
1408
1408
|
"deprecationMsg": "The usage of `binarySource=docker` is deprecated, and will be removed in the future"
|
|
1409
1409
|
},
|
|
@@ -2905,6 +2905,16 @@ export const OPTIONS = {
|
|
|
2905
2905
|
"cli": false,
|
|
2906
2906
|
"env": false
|
|
2907
2907
|
},
|
|
2908
|
+
"matchIsBreaking": {
|
|
2909
|
+
"description": "Matches only if the update is considered breaking (e.g. major, or minor for 0.x in ecosystems like Cargo) when `true`, or non-breaking when `false`. Valid only within a `packageRules` object.",
|
|
2910
|
+
"type": "boolean",
|
|
2911
|
+
"parents": [
|
|
2912
|
+
"packageRules"
|
|
2913
|
+
],
|
|
2914
|
+
"stage": "package",
|
|
2915
|
+
"cli": false,
|
|
2916
|
+
"env": false
|
|
2917
|
+
},
|
|
2908
2918
|
"matchJsonata": {
|
|
2909
2919
|
"description": "A JSONata expression to match against the full config object. Valid only within a `packageRules` object.",
|
|
2910
2920
|
"type": "array",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
// AUTO-GENERATED by scripts/generate-presets.mjs from renovate@44.
|
|
1
|
+
// AUTO-GENERATED by scripts/generate-presets.mjs from renovate@44.115.10.
|
|
2
2
|
// Do not edit by hand. Run `npm run generate:presets` to refresh.
|
|
3
|
-
export const RENOVATE_VERSION = "44.
|
|
3
|
+
export const RENOVATE_VERSION = "44.115.10";
|
|
4
4
|
export const PRESETS = {
|
|
5
5
|
"abandonments:recommended": {
|
|
6
6
|
"namespace": "abandonments",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { collectMergeSteps,
|
|
1
|
+
import { collectMergeSteps, } from "./presetResolver.js";
|
|
2
2
|
import { runMerge } from "./mergeWorker.js";
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
import { isRecord } from "./util.js";
|
|
4
|
+
import { isDeepStrictEqual } from "node:util";
|
|
5
5
|
/**
|
|
6
6
|
* Inverse of `resolveConfig`: instead of collapsing the preset tree into a flat
|
|
7
7
|
* resolved object, annotate each leaf field with the chain of presets that set
|
|
@@ -89,16 +89,16 @@ function diffLeaves(before, after, path, onContribution) {
|
|
|
89
89
|
for (const [key, afterVal] of Object.entries(after)) {
|
|
90
90
|
const beforeVal = before[key];
|
|
91
91
|
const childPath = [...path, key];
|
|
92
|
-
if (
|
|
93
|
-
diffLeaves(
|
|
92
|
+
if (isRecord(afterVal)) {
|
|
93
|
+
diffLeaves(isRecord(beforeVal) ? beforeVal : {}, afterVal, childPath, onContribution);
|
|
94
94
|
continue;
|
|
95
95
|
}
|
|
96
|
-
if (
|
|
96
|
+
if (isDeepStrictEqual(beforeVal, afterVal))
|
|
97
97
|
continue;
|
|
98
98
|
if (Array.isArray(beforeVal) &&
|
|
99
99
|
Array.isArray(afterVal) &&
|
|
100
100
|
afterVal.length > beforeVal.length &&
|
|
101
|
-
|
|
101
|
+
isDeepStrictEqual(afterVal.slice(0, beforeVal.length), beforeVal)) {
|
|
102
102
|
// Mergeable-array concatenation: record only the tail this step appended.
|
|
103
103
|
onContribution(childPath, afterVal.slice(beforeVal.length));
|
|
104
104
|
}
|
|
@@ -113,7 +113,7 @@ function diffLeaves(before, after, path, onContribution) {
|
|
|
113
113
|
* values) plus the path→contributions map produced by `diffLeaves`.
|
|
114
114
|
*/
|
|
115
115
|
function buildAnnotated(node, path, contribByPath) {
|
|
116
|
-
if (
|
|
116
|
+
if (isRecord(node)) {
|
|
117
117
|
const out = {};
|
|
118
118
|
for (const [key, child] of Object.entries(node)) {
|
|
119
119
|
out[key] = buildAnnotated(child, [...path, key], contribByPath);
|
|
@@ -122,9 +122,6 @@ function buildAnnotated(node, path, contribByPath) {
|
|
|
122
122
|
}
|
|
123
123
|
return { value: node, setBy: contribByPath.get(JSON.stringify(path)) ?? [] };
|
|
124
124
|
}
|
|
125
|
-
function jsonEqual(a, b) {
|
|
126
|
-
return JSON.stringify(a) === JSON.stringify(b);
|
|
127
|
-
}
|
|
128
125
|
/**
|
|
129
126
|
* Approximate annotated merge — the fallback when the faithful worker is
|
|
130
127
|
* unavailable. Arrays concat (and concat their `setBy`), plain objects recurse,
|
|
@@ -133,7 +130,7 @@ function jsonEqual(a, b) {
|
|
|
133
130
|
* tool produced before.
|
|
134
131
|
*/
|
|
135
132
|
function annotateValue(value, source, via) {
|
|
136
|
-
if (
|
|
133
|
+
if (isRecord(value)) {
|
|
137
134
|
const out = {};
|
|
138
135
|
for (const [k, v] of Object.entries(value)) {
|
|
139
136
|
out[k] = annotateValue(v, source, via);
|
|
@@ -175,6 +172,3 @@ function isAnnotatedLeaf(node) {
|
|
|
175
172
|
return false;
|
|
176
173
|
return Array.isArray(node.setBy);
|
|
177
174
|
}
|
|
178
|
-
function isPlainObject(v) {
|
|
179
|
-
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
180
|
-
}
|
package/dist/lib/configLinter.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ALL_MANAGERS, CUSTOM_MANAGERS } from "../data/managers.generated.js";
|
|
2
|
-
import { DEPRECATED_KEYS } from "../data/migrations.generated.js";
|
|
2
|
+
import { DEPRECATED_KEYS, } from "../data/migrations.generated.js";
|
|
3
|
+
import { isRecord } from "./util.js";
|
|
3
4
|
const REGEX_AWARE_FIELDS = new Set([
|
|
4
5
|
"matchPackageNames",
|
|
5
6
|
"matchDepNames",
|
|
@@ -11,7 +12,7 @@ const VALID_MANAGER_NAMES = new Set([
|
|
|
11
12
|
...ALL_MANAGERS,
|
|
12
13
|
...CUSTOM_MANAGERS.map((m) => `custom.${m}`),
|
|
13
14
|
]);
|
|
14
|
-
const DEPRECATED_KEY_LOOKUP = new Map(DEPRECATED_KEYS.map((e) => [e.oldKey, e
|
|
15
|
+
const DEPRECATED_KEY_LOOKUP = new Map(DEPRECATED_KEYS.map((e) => [e.oldKey, e]));
|
|
15
16
|
// Hand-maintained snapshot of keys that count as "actions" on a packageRules entry
|
|
16
17
|
// (i.e. keys whose presence means the rule actually *does* something to the matched
|
|
17
18
|
// deps). Source of truth: `node_modules/renovate/dist/config/options/index.js` —
|
|
@@ -251,12 +252,12 @@ function isSelectorKey(key) {
|
|
|
251
252
|
key === "excludePaths");
|
|
252
253
|
}
|
|
253
254
|
function checkPackageRuleWithoutAction(config, findings) {
|
|
254
|
-
if (!
|
|
255
|
+
if (!isRecord(config))
|
|
255
256
|
return;
|
|
256
257
|
if (!Array.isArray(config.packageRules))
|
|
257
258
|
return;
|
|
258
259
|
config.packageRules.forEach((entry, i) => {
|
|
259
|
-
if (!
|
|
260
|
+
if (!isRecord(entry))
|
|
260
261
|
return;
|
|
261
262
|
const keys = Object.keys(entry);
|
|
262
263
|
const selectors = [];
|
|
@@ -283,14 +284,14 @@ function checkPackageRuleWithoutAction(config, findings) {
|
|
|
283
284
|
});
|
|
284
285
|
}
|
|
285
286
|
function checkContradictoryDisabled(config, findings) {
|
|
286
|
-
if (!
|
|
287
|
+
if (!isRecord(config))
|
|
287
288
|
return;
|
|
288
289
|
if (config.enabled !== false)
|
|
289
290
|
return;
|
|
290
291
|
if (!Array.isArray(config.packageRules))
|
|
291
292
|
return;
|
|
292
293
|
config.packageRules.forEach((entry, i) => {
|
|
293
|
-
if (!
|
|
294
|
+
if (!isRecord(entry))
|
|
294
295
|
return;
|
|
295
296
|
if (entry.enabled !== true)
|
|
296
297
|
return;
|
|
@@ -315,7 +316,7 @@ function makeAutomergeFinding(path) {
|
|
|
315
316
|
};
|
|
316
317
|
}
|
|
317
318
|
function checkAutomergeWithoutType(config, findings) {
|
|
318
|
-
if (!
|
|
319
|
+
if (!isRecord(config))
|
|
319
320
|
return;
|
|
320
321
|
if (config.automerge === true && !("automergeType" in config)) {
|
|
321
322
|
findings.push(makeAutomergeFinding("automerge"));
|
|
@@ -323,7 +324,7 @@ function checkAutomergeWithoutType(config, findings) {
|
|
|
323
324
|
const pkgRules = config.packageRules;
|
|
324
325
|
if (Array.isArray(pkgRules)) {
|
|
325
326
|
pkgRules.forEach((entry, i) => {
|
|
326
|
-
if (!
|
|
327
|
+
if (!isRecord(entry))
|
|
327
328
|
return;
|
|
328
329
|
if (entry.automerge === true && !("automergeType" in entry)) {
|
|
329
330
|
findings.push(makeAutomergeFinding(`packageRules[${i}].automerge`));
|
|
@@ -332,7 +333,7 @@ function checkAutomergeWithoutType(config, findings) {
|
|
|
332
333
|
}
|
|
333
334
|
}
|
|
334
335
|
function checkAutomergeIncludesMajor(config, findings) {
|
|
335
|
-
if (!
|
|
336
|
+
if (!isRecord(config))
|
|
336
337
|
return;
|
|
337
338
|
const pkgRules = config.packageRules;
|
|
338
339
|
if (!Array.isArray(pkgRules))
|
|
@@ -344,7 +345,7 @@ function checkAutomergeIncludesMajor(config, findings) {
|
|
|
344
345
|
// findings for unrelated entries. Upgrade path: track guard ordering /
|
|
345
346
|
// selector overlap per-entry if false negatives show up in practice.
|
|
346
347
|
const hasLaterMajorGuard = pkgRules.some((entry) => {
|
|
347
|
-
if (!
|
|
348
|
+
if (!isRecord(entry))
|
|
348
349
|
return false;
|
|
349
350
|
if (entry.automerge !== false)
|
|
350
351
|
return false;
|
|
@@ -354,7 +355,7 @@ function checkAutomergeIncludesMajor(config, findings) {
|
|
|
354
355
|
if (hasLaterMajorGuard)
|
|
355
356
|
return;
|
|
356
357
|
pkgRules.forEach((entry, i) => {
|
|
357
|
-
if (!
|
|
358
|
+
if (!isRecord(entry))
|
|
358
359
|
return;
|
|
359
360
|
if (entry.automerge !== true)
|
|
360
361
|
return;
|
|
@@ -393,12 +394,12 @@ function normalizeSelectorValue(v) {
|
|
|
393
394
|
return v;
|
|
394
395
|
}
|
|
395
396
|
function checkDuplicatePackageRuleMatchers(config, findings) {
|
|
396
|
-
if (!
|
|
397
|
+
if (!isRecord(config))
|
|
397
398
|
return;
|
|
398
399
|
const pkgRules = config.packageRules;
|
|
399
400
|
if (!Array.isArray(pkgRules))
|
|
400
401
|
return;
|
|
401
|
-
const signatures = pkgRules.map((entry) =>
|
|
402
|
+
const signatures = pkgRules.map((entry) => isRecord(entry) ? selectorSignature(entry) : null);
|
|
402
403
|
for (let i = 0; i < signatures.length; i++) {
|
|
403
404
|
if (signatures[i] === null)
|
|
404
405
|
continue;
|
|
@@ -423,13 +424,13 @@ function checkDuplicatePackageRuleMatchers(config, findings) {
|
|
|
423
424
|
}
|
|
424
425
|
const HOST_RULE_SECRET_FIELDS = ["token", "password"];
|
|
425
426
|
function checkHostRuleInlineSecret(config, findings) {
|
|
426
|
-
if (!
|
|
427
|
+
if (!isRecord(config))
|
|
427
428
|
return;
|
|
428
429
|
const hostRules = config.hostRules;
|
|
429
430
|
if (!Array.isArray(hostRules))
|
|
430
431
|
return;
|
|
431
432
|
hostRules.forEach((entry, i) => {
|
|
432
|
-
if (!
|
|
433
|
+
if (!isRecord(entry))
|
|
433
434
|
return;
|
|
434
435
|
for (const field of HOST_RULE_SECRET_FIELDS) {
|
|
435
436
|
const value = entry[field];
|
|
@@ -450,10 +451,18 @@ function checkHostRuleInlineSecret(config, findings) {
|
|
|
450
451
|
}
|
|
451
452
|
});
|
|
452
453
|
}
|
|
453
|
-
function
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
454
|
+
function makeDeprecatedKeyFinding({ oldKey, newKey }, path) {
|
|
455
|
+
// Plain renames carry the replacement; custom migrations (value coercions,
|
|
456
|
+
// structural rewrites) only tell us the key is deprecated.
|
|
457
|
+
if (newKey === undefined) {
|
|
458
|
+
return {
|
|
459
|
+
ruleId: "deprecated-key",
|
|
460
|
+
severity: "warn",
|
|
461
|
+
path,
|
|
462
|
+
value: oldKey,
|
|
463
|
+
message: `Key '${oldKey}' is deprecated; Renovate migrates it automatically — run migrate_config to see the replacement.`,
|
|
464
|
+
};
|
|
465
|
+
}
|
|
457
466
|
return {
|
|
458
467
|
ruleId: "deprecated-key",
|
|
459
468
|
severity: "warn",
|
|
@@ -464,25 +473,24 @@ function makeDeprecatedKeyFinding(oldKey, newKey, path) {
|
|
|
464
473
|
};
|
|
465
474
|
}
|
|
466
475
|
function checkDeprecatedKeys(config, findings) {
|
|
467
|
-
if (!
|
|
476
|
+
if (!isRecord(config))
|
|
468
477
|
return;
|
|
469
478
|
for (const key of Object.keys(config)) {
|
|
470
|
-
const
|
|
471
|
-
if (
|
|
472
|
-
findings.push(makeDeprecatedKeyFinding(
|
|
473
|
-
}
|
|
479
|
+
const entry = DEPRECATED_KEY_LOOKUP.get(key);
|
|
480
|
+
if (entry)
|
|
481
|
+
findings.push(makeDeprecatedKeyFinding(entry, key));
|
|
474
482
|
}
|
|
475
483
|
for (const container of DEPRECATED_KEY_CONTAINERS) {
|
|
476
484
|
const arr = config[container];
|
|
477
485
|
if (!Array.isArray(arr))
|
|
478
486
|
continue;
|
|
479
|
-
arr.forEach((
|
|
480
|
-
if (!
|
|
487
|
+
arr.forEach((item, i) => {
|
|
488
|
+
if (!isRecord(item))
|
|
481
489
|
return;
|
|
482
|
-
for (const key of Object.keys(
|
|
483
|
-
const
|
|
484
|
-
if (
|
|
485
|
-
findings.push(makeDeprecatedKeyFinding(
|
|
490
|
+
for (const key of Object.keys(item)) {
|
|
491
|
+
const entry = DEPRECATED_KEY_LOOKUP.get(key);
|
|
492
|
+
if (entry) {
|
|
493
|
+
findings.push(makeDeprecatedKeyFinding(entry, `${container}[${i}].${key}`));
|
|
486
494
|
}
|
|
487
495
|
}
|
|
488
496
|
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { promises as fs } from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import JSON5 from "json5";
|
|
4
|
+
import { isRecord } from "./util.js";
|
|
4
5
|
const CANDIDATES = [
|
|
5
6
|
{ path: "renovate.json", format: "json" },
|
|
6
7
|
{ path: "renovate.json5", format: "json5" },
|
|
@@ -17,8 +18,11 @@ export async function locateConfig(repoPath) {
|
|
|
17
18
|
const abs = path.join(repoPath, candidate.path);
|
|
18
19
|
try {
|
|
19
20
|
const raw = await fs.readFile(abs, "utf8");
|
|
20
|
-
|
|
21
|
-
|
|
21
|
+
// Renovate parses every candidate JSONC-then-JSON5 regardless of
|
|
22
|
+
// extension (and write_config round-trips comments into renovate.json);
|
|
23
|
+
// JSON5 is a superset of JSONC, so one parser covers all of them.
|
|
24
|
+
const config = JSON5.parse(raw);
|
|
25
|
+
if (!isRecord(config)) {
|
|
22
26
|
throw new Error(`${candidate.path} does not contain a JSON object`);
|
|
23
27
|
}
|
|
24
28
|
return {
|
|
@@ -38,9 +42,9 @@ export async function locateConfig(repoPath) {
|
|
|
38
42
|
try {
|
|
39
43
|
const raw = await fs.readFile(pkgAbs, "utf8");
|
|
40
44
|
const pkg = JSON.parse(raw);
|
|
41
|
-
if (
|
|
45
|
+
if (isRecord(pkg) &&
|
|
42
46
|
"renovate" in pkg &&
|
|
43
|
-
|
|
47
|
+
isRecord(pkg.renovate)) {
|
|
44
48
|
return {
|
|
45
49
|
absPath: pkgAbs,
|
|
46
50
|
relPath: "package.json",
|
|
@@ -56,6 +60,3 @@ export async function locateConfig(repoPath) {
|
|
|
56
60
|
}
|
|
57
61
|
return null;
|
|
58
62
|
}
|
|
59
|
-
function isPlainObject(v) {
|
|
60
|
-
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
61
|
-
}
|