Skip to content

feat!: consolidate the general-purpose presets into default.json - #89

Merged
onedr0p merged 1 commit into
mainfrom
refactor/inline-default-presets
Aug 8, 2026
Merged

feat!: consolidate the general-purpose presets into default.json#89
onedr0p merged 1 commit into
mainfrom
refactor/inline-default-presets

Conversation

@onedr0p

@onedr0p onedr0p commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Problem

A #tag on a preset reference does not propagate to references made inside that preset, and Renovate has no relative or self-referencing preset syntax: parsePreset (config/presets/parse.js:70-88) resolves every reference to an absolute source, repo, path and tag. default.json listed its siblings untagged, so Renovate resolved every one of them from the default branch regardless of what tag a consumer pinned. Two consequences:

  1. The pin was inert. Anyone on #5.0.0 was running main's preset bodies, and had been all along.
  2. The directory layout was a permanent public API. feat!: make app-specific presets opt-in under apps/ #86 moved the app-specific presets under apps/, breaking every previously published tag at once: default.json@5.0.0 still asks main for managers/cnpg.json5. Downstream saw Cannot find preset's package (...). Note: this is a *nested* preset and Renovate stopped opening PRs entirely (example: Action Required: Fix Renovate Configuration onedr0p/home-ops#11489).

Change

config/, managers/, overrides/ and policies/ are folded into default.json. It is one self-contained preset now, so a tag pins all of it and the layout stops being something no published tag can stop depending on.

apps/ is untouched. Separating the defaults from opt-in application presets is the point of the repo; only the defaults needed consolidating, and they were always consumed as a set.

This also drops the general-purpose presets from thirteen fetches to one. The only references left are stock Renovate presets, which resolve from inside the binary rather than over the network:

OLD default.json extends            NEW default.json extends
  NETWORK  //config/baseConfig.json5      in binary  config:recommended
  NETWORK  //config/dependencyDashboard   in binary  docker:enableMajor
  ... 10 more ...                         in binary  helpers:pinGitHubActionDigestsToSemver
  network fetches: 12                     ... 3 more ...
                                          network fetches: 0

scripts/, the gen and verify mise tasks, and the CI steps that regenerated and cross-checked default.json are all removed. There is no generated file left to drift or to diff against its sources.

Rationale that lived in JSON5 comments moves into the description of the rule it explains, which is the only prose strict JSON carries and which surfaces in resolved config. Nothing was dropped.

Verification

Both refs run through Renovate's own resolveConfigPresets and diffed. The entire difference is the three description edits above:

36c36
<   "Process annotated dependencies"
>   "Process annotated dependencies: a `# renovate: datasource=<ds> depName=<name>` comment followed by ..."
10545c10545
<   "zer0ver: 0.x minors can break at any time, give them the breaking `!` prefix"
>   "... No matchCurrentVersion guard is shipped for automerge: repo packageRules concatenate ..."
10556c10556
<   "zer0ver: 0.x minors can break at any time, route them onto the major branches"
>   "... The default branchName template includes additionalBranchPrefix, so this lands them ..."

Ignoring description fields the two resolved configs are equal, and the counts match: 733 packageRules, 4 customManagers, 1 registryAliases, same dependencyDashboardTitle.

mise run lint, mise run validate over all 8 remaining configs, actionlint and zizmor are clean.

Breaking

The general-purpose presets no longer exist as individual files. Extending //policies/zer0ver.json5, or any other path under config/, managers/, overrides/ or policies/, stops resolving. Extend the repo itself instead. ignorePresets can no longer drop one of them out of the bundle, which shouldResolvePreset did allow while they were separate references. apps/ presets are unaffected and stay individually opt-in.

Tags at or below 6.0.0 are not repaired; their default.json will ask main for managers/cnpg.json5 forever. Fixing that would mean restoring the moved paths as shims. Deliberately skipped: the broken-config issue Renovate files is loud enough to drive an upgrade.

@onedr0p

onedr0p commented Aug 7, 2026

Copy link
Copy Markdown
Contributor Author

Added a guard, after considering whether release-please should stamp the version onto the nested refs instead.

Why not stamping. It would work, and it would be more general than inlining, but release-please cannot do it natively. The json updater replaces the whole value at a jsonpath, so $.extends[*] would rewrite each entry to the literal "6.0.0". The generic updater is line-based and needs an x-release-please-version annotation comment, which strict JSON cannot carry, and Renovate only ever fetches default.json for a bare repo reference (config/presets/util.js:20-24, falling back only to a deprecated renovate.json), so the file cannot move to a commentable format. That leaves a custom regeneration step on the bot's release branch, which ci.yaml:28-30 deliberately skips. It would also mean main's default.json points at the last release's leaves, so unpinned consumers stop tracking main between releases, and it costs 13 preset fetches per repo per run instead of 1.

What stamping was right about. Inlining only works because the nesting is one level deep, and nothing enforced that. A sibling extends in any leaf preset passed straight through into the generated extends list untagged, putting the bug back with nothing looking wrong.

mise run gen now fails on any preset that extends a sibling:

$ node scripts/gen-default.mjs
Error: overrides/mise.json5 extends github>home-operations/renovate-presets//config/registryAliases.json5
Presets must be self-contained: a tag does not propagate into a preset's own references.

The check covers apps/ too, even though those stay out of the bundle: an opt-in preset is exactly what a consumer pins a tag on directly, so the same reference would reach them unpinned.

default.json is byte-identical to the commit verified above (blob c787ae0), and the resolved-config diff against main was re-run on the updated branch: still identical, 10569 lines. Lint clean.

@onedr0p
onedr0p force-pushed the refactor/inline-default-presets branch 2 times, most recently from b039f88 to a59f243 Compare August 7, 2026 13:34
@onedr0p onedr0p changed the title fix: inline preset bodies into default.json so a pinned tag pins the whole bundle fix: stamp the release version onto every preset default.json extends Aug 7, 2026
@onedr0p

onedr0p commented Aug 7, 2026

Copy link
Copy Markdown
Contributor Author

Switched from inlining to stamping. Superseded approach is in the force-pushed history; the PR description now reflects what is here.

Correcting myself twice on the way: extra-files type json maps to GenericJson, which substring-replaces the version inside each string rather than replacing the whole value, so stamping was always natively expressible. And the variant I then proposed, untagged on main with stamping only at release, cannot bootstrap, since GenericJson skips any string with no version to replace.

@onedr0p
onedr0p force-pushed the refactor/inline-default-presets branch from a59f243 to 112bae1 Compare August 7, 2026 14:12
@onedr0p onedr0p changed the title fix: stamp the release version onto every preset default.json extends fix: inline preset bodies into default.json so a pinned tag pins the whole bundle Aug 7, 2026
@onedr0p

onedr0p commented Aug 7, 2026

Copy link
Copy Markdown
Contributor Author

Back to inlining, now with mise run verify closing the gap that made stamping attractive.

Checked Renovate's parser rather than the docs: parsePreset resolves every reference to an absolute source, repo, path and tag, with no relative or self-referencing form, and path syntax and sub-preset syntax cannot be combined at all. There is no supported mechanism for tag inheritance, so a self-contained default.json is the shape the model actually supports and stamping was tooling compensating for a shape Renovate has no story for.

Also withdrawing something I said earlier in this thread: renovatebot/renovate#15464 is about multiple presets inside one file, not about presets extending presets, so it was not evidence either way.

@onedr0p
onedr0p force-pushed the refactor/inline-default-presets branch from 112bae1 to 9238e81 Compare August 7, 2026 14:34
@onedr0p onedr0p changed the title fix: inline preset bodies into default.json so a pinned tag pins the whole bundle feat!: inline preset bodies into default.json so a pinned tag pins the whole bundle Aug 7, 2026
A `#tag` on a preset reference does not propagate to references made inside
that preset, and Renovate has no relative or self-referencing preset syntax:
parsePreset resolves every reference to an absolute source, repo, path and
tag. default.json listed its siblings untagged, so Renovate resolved every
one of them from the default branch no matter what tag a consumer pinned.
The pin covered the entry point and nothing else, and #86 moving files under
apps/ broke every previously published tag at once.

Fold config/, managers/, overrides/ and policies/ into default.json. It is
one self-contained preset now, so a tag pins all of it, the directory layout
stops being a public API that no tag can stop depending on, and the general
-purpose presets cost one fetch instead of thirteen. The only references left
are stock presets that ship inside Renovate.

apps/ is untouched. Splitting the defaults from opt-in application presets is
the point of the repo, and only the defaults needed consolidating.

The scripts, mise tasks and CI steps that generated and checked default.json
go too. There is no generated file left to drift or to diff against its
sources.

The rationale that lived in JSON5 comments moves into the `description` of
the rule it explains, which is the only prose strict JSON carries and shows
up in resolved config.

The resolved config is unchanged apart from those description edits, verified
by running Renovate's own resolveConfigPresets over the bare reference on main
and on this branch and diffing.

BREAKING CHANGE: the general-purpose presets no longer exist as individual
files. Extending github>home-operations/renovate-presets//policies/zer0ver.json5
or any other path under config/, managers/, overrides/ or policies/ stops
resolving; extend the repo itself instead. ignorePresets can no longer drop
one of them out of the bundle. apps/ presets are unaffected.

Signed-off-by: Devin Buhl <devin@buhl.casa>
@onedr0p
onedr0p force-pushed the refactor/inline-default-presets branch from 9238e81 to b5d034b Compare August 7, 2026 14:43
@onedr0p onedr0p changed the title feat!: inline preset bodies into default.json so a pinned tag pins the whole bundle feat!: consolidate the general-purpose presets into default.json Aug 7, 2026
@onedr0p
onedr0p merged commit 8f8e06a into main Aug 8, 2026
3 checks passed
@onedr0p
onedr0p deleted the refactor/inline-default-presets branch August 8, 2026 10:34
@sticky-gecko sticky-gecko Bot mentioned this pull request Aug 8, 2026
doonga pushed a commit to doonga/renovate-config that referenced this pull request Aug 10, 2026
…ts (6.0.0 ➔ 7.0.0) (#9)

This PR contains the following updates:

| Package | Update | Change |
|---|---|---|
| [home-operations/renovate-presets](https://github.com/home-operations/renovate-presets) | major | `6.0.0` → `7.0.0` |

---

### Release Notes

<details>
<summary>home-operations/renovate-presets (home-operations/renovate-presets)</summary>

### [`v7.0.0`](https://github.com/home-operations/renovate-presets/blob/HEAD/CHANGELOG.md#700-2026-08-08)

[Compare Source](home-operations/renovate-presets@6.0.0...7.0.0)

##### ⚠ BREAKING CHANGES

- consolidate the general-purpose presets into default.json ([#&#8203;89](home-operations/renovate-presets#89))

##### Features

- consolidate the general-purpose presets into default.json ([#&#8203;89](home-operations/renovate-presets#89)) ([8f8e06a](home-operations/renovate-presets@8f8e06a))

</details>

---

### Configuration

📅 **Schedule**: (in timezone America/New_York)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Mend Renovate CLI](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC43LjQiLCJ1cGRhdGVkSW5WZXIiOiI0NC43LjQiLCJ0YXJnZXRCcmFuY2giOiJtYWluIiwibGFiZWxzIjpbInJlbm92YXRlL2dpdGh1Yi1yZWxlYXNlIiwidHlwZS9tYWpvciJdfQ==-->

Reviewed-on: https://git.greyrock.io/greyrock-labs/renovate-config/pulls/9
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant