renovate: align the config with cluster-config
Validate Helm Charts / Detect changed charts (pull_request) Successful in 3s
Validate Helm Charts / Build ${{ fromJSON(needs.detect-changed-charts.outputs.charts) }} (pull_request) Skipped
Validate Helm Charts / Trivy config ${{ fromJSON(needs.detect-changed-charts.outputs.scan-charts) }} (pull_request) Skipped
Validate Helm Charts / Install-test ${{ fromJSON(needs.detect-changed-charts.outputs.install-charts) }} (pull_request) Skipped
Validate Helm Charts / Resource quantities (pull_request) Successful in 8s
Validate Helm Charts / Detect changed charts (pull_request) Successful in 3s
Validate Helm Charts / Build ${{ fromJSON(needs.detect-changed-charts.outputs.charts) }} (pull_request) Skipped
Validate Helm Charts / Trivy config ${{ fromJSON(needs.detect-changed-charts.outputs.scan-charts) }} (pull_request) Skipped
Validate Helm Charts / Install-test ${{ fromJSON(needs.detect-changed-charts.outputs.install-charts) }} (pull_request) Skipped
Validate Helm Charts / Resource quantities (pull_request) Successful in 8s
The shared jlab-renovate-bot instance serves this repo and cluster-config,
and two repos behaving differently under one bot is a source of surprises
rather than of safety. This adopts cluster-config's configuration:
config:best-practices in extends, labels ["renovate"], no PR caps
(prHourlyLimit 0, prConcurrentLimit 100), separateMinorPatch, an explicit
dependencyDashboard, and global automerge with platformAutomerge.
Two of those choices were previously wrong here and are now right, because
the branch protection on main has caught up: a review requirement and
validate-charts as a required check are both active. platformAutomerge
therefore arms the PR on the forge and Gitea merges it when the check
passes AND the review exists - the review is the gate, which is what makes
automerging majors something other than unattended merging.
Comments that asserted the opposite are rewritten rather than left to rot:
the platformAutomerge: false comment ("not (yet) a required check on either
side"), the "Majors stay manual" rule, the README PR policy bullets and the
required-check paragraph, and the CLAUDE.md forge notes.
config:best-practices pulls in docker:pinDigests, which is switched off
again for custom.regex and helm-values: an appVersion: is a tag by
construction and has nowhere to put a digest. Kept deliberately:
minimumReleaseAge of three days on the routine updates (every merge here
publishes a chart), the ignorePaths and ci/** opt-outs, every per-chart
manager, the nginx and qbittorrent constraints, and postUpgradeTasks.
Fixes #34
This commit was merged in pull request #35.
This commit is contained in:
3 files changed
+88
-35
No files matched your search
+77
-28
@@ -16,15 +16,45 @@
|
||||
// Commit subjects in this repo are plain sentences, not conventional
|
||||
// commits. Renovate's own merged PRs already look like that.
|
||||
":semanticCommitsDisabled",
|
||||
// Same preset as cluster-config, so both repos behave identically on the
|
||||
// shared jlab-renovate-bot instance. Two of the things it pulls in are
|
||||
// load-bearing here: `helpers:pinGitHubActionDigests` (wanted — the
|
||||
// workflow files move from `actions/checkout@v7` to SHA pins) and
|
||||
// `docker:pinDigests`, which is turned off again for the two managers that
|
||||
// cannot carry a digest — see the pinDigests rule below. The
|
||||
// npm-flavoured members (`:pinDevDependencies`,
|
||||
// `security:minimumReleaseAgeNpm`, `:maintainLockFilesWeekly`) are inert
|
||||
// in a repo without a package manager.
|
||||
"config:best-practices",
|
||||
],
|
||||
|
||||
timezone: "Europe/Berlin",
|
||||
labels: ["dependencies"],
|
||||
labels: ["renovate"],
|
||||
dependencyDashboard: true,
|
||||
|
||||
// 21 charts plus the workflows: without a cap the first run after a quiet
|
||||
// week opens a wall of PRs, and every chart PR spins up a k3d install-test.
|
||||
prConcurrentLimit: 10,
|
||||
prHourlyLimit: 4,
|
||||
// No caps, as in cluster-config. The first run after a quiet week can open
|
||||
// many PRs at once and every chart PR starts a k3d install-test; on Gitea a
|
||||
// whole matrix runs inside one job on one runner, so those queue instead of
|
||||
// fanning out. That queue is the accepted price for not having updates
|
||||
// trickle in four per hour — nothing merges without a review anyway.
|
||||
prConcurrentLimit: 100,
|
||||
prHourlyLimit: 0,
|
||||
|
||||
// Minor and patch arrive as separate PRs rather than one combined branch.
|
||||
// With 23 charts a shared branch means one red install-test blocks unrelated
|
||||
// updates, and the separation is what lets a patch be reviewed in seconds.
|
||||
separateMinorPatch: true,
|
||||
|
||||
// Every update automerges once the PR is mergeable, majors included, and
|
||||
// `platformAutomerge` hands that decision to the forge instead of letting
|
||||
// Renovate poll: Gitea arms the PR and merges it when the required check
|
||||
// (`validate-charts`) passes AND the required review exists. Both are active
|
||||
// on `main`, which is why this is not unattended merging — the review is the
|
||||
// gate, and without it the armed PR simply sits there. Same reasoning as
|
||||
// cluster-config, where the dashboard approval was retired for it.
|
||||
automerge: true,
|
||||
automergeType: "pr",
|
||||
platformAutomerge: true,
|
||||
|
||||
// template-chart is the scaffold. Its image is the literal placeholder
|
||||
// ghcr.io/ORG/IMAGE and its appVersion is "xxx" — nothing to update, and the
|
||||
@@ -80,26 +110,43 @@
|
||||
},
|
||||
{
|
||||
description: [
|
||||
"Patch, minor and digest updates merge themselves once the PR pipeline is green.",
|
||||
"Minor is included because the sidecar images barely move in patch steps —",
|
||||
"alpine 3.22 -> 3.24 and nginx 1.30.4 -> 1.31.4 are both minor, so a patch-only",
|
||||
"rule would practically never fire. Majors stay manual.",
|
||||
"Routine updates wait three days before Renovate even opens the PR. Automerge is",
|
||||
"global now (top of this file), so this rule no longer decides WHAT merges by itself —",
|
||||
"it decides how fresh a release may be when it does. A merge here is never just a",
|
||||
"merge: every chart change publishes a chart straight away, and a release that is",
|
||||
"yanked hours after it appeared should not reach the registry at all.",
|
||||
"cluster-config spends the same three days on the dependencies where a merge is",
|
||||
"expensive (authentik, rancher); here that is every one of them.",
|
||||
"",
|
||||
"Majors deliberately carry no age gate: they are not the updates that slip through",
|
||||
"unnoticed, they are the ones held at the review, and separateMultipleMajor makes",
|
||||
"them arrive one line at a time anyway.",
|
||||
],
|
||||
matchUpdateTypes: ["patch", "minor", "digest"],
|
||||
automerge: true,
|
||||
automergeType: "pr",
|
||||
// Renovate waits for the checks itself instead of handing the PR to the
|
||||
// forge's own auto-merge. Both of them — GitHub's, and the auto-merge
|
||||
// that takes the merge queue's place on Gitea, which has none — merge
|
||||
// immediately when the branch has no required status checks configured,
|
||||
// and validate-charts is not (yet) a required check on either side. This
|
||||
// is a statement about the branch protection, not about the platform:
|
||||
// once required checks exist on `main`, true is the better value.
|
||||
platformAutomerge: false,
|
||||
// A release that is hours old should not walk into main unattended; a
|
||||
// chart publish follows the merge straight away.
|
||||
minimumReleaseAge: "3 days",
|
||||
},
|
||||
{
|
||||
description: [
|
||||
"`config:best-practices` brings `docker:pinDigests`, and two of this repo's managers",
|
||||
"have nowhere to put a digest. custom.regex reads `appVersion:` out of a Chart.yaml,",
|
||||
"and that value is a TAG by construction: the templates render",
|
||||
"`<repo>:{{ .Chart.AppVersion }}`, and the chart version's `+up<appVersion>` suffix is",
|
||||
"built from the same string — an `@sha256:...` fits into neither. cluster-config makes",
|
||||
"the identical opt-out for its fleet manager, for the identical reason.",
|
||||
"",
|
||||
"helm-values is opted out too, but as a decision rather than a necessity: sidecar",
|
||||
"images there COULD be pinned by digest, and every digest change would then be a chart",
|
||||
"patch plus a publish. Whether that is worth it is its own question, not part of this",
|
||||
"alignment.",
|
||||
"",
|
||||
"Unaffected: the freesailarr/mediathekarr block below, which extracts a digest that is",
|
||||
"written in values.yaml on purpose (pinDigests only ADDS digests where none exists),",
|
||||
"and the GitHub Actions pinning from `helpers:pinGitHubActionDigests` — a different",
|
||||
"datasource, and wanted.",
|
||||
],
|
||||
matchManagers: ["custom.regex", "helm-values"],
|
||||
pinDigests: false,
|
||||
},
|
||||
{
|
||||
description: [
|
||||
"Chart app versions. Kept out of the automerge grouping decisions above only by label,",
|
||||
@@ -121,10 +168,10 @@
|
||||
"This rule adds only a label. It exists because the update matters more here than",
|
||||
"its size suggests: a subchart is invisible to everything downstream that watches",
|
||||
"Helm release versions, so this PR is the ONLY way a new proxy version - a security",
|
||||
"fix included - ever reaches a cluster. Under the automerge rule above, patch and",
|
||||
"minor updates do that on their own once the pipeline is green, and",
|
||||
"ci/renovate-bump-chart.sh bumps the chart patch that publishes it (appVersion is",
|
||||
"unchanged, so it takes the patch branch). A major arrives as a PR to merge by hand.",
|
||||
"fix included - ever reaches a cluster. Automerge carries that PR to main once it is",
|
||||
"reviewed and the check is green, and ci/renovate-bump-chart.sh bumps the chart patch",
|
||||
"that publishes it (appVersion is unchanged, so it takes the patch branch). A major",
|
||||
"goes the same way - it is the review, not a separate policy, that gives it a look.",
|
||||
],
|
||||
matchManagers: ["helmv3"],
|
||||
addLabels: ["subchart"],
|
||||
@@ -230,7 +277,8 @@
|
||||
"points at the moving 'beta'. The built-in helm-values manager reads repository/tag and",
|
||||
"would have nothing to compare, so this manager captures all three keys and lets Renovate",
|
||||
"propose digest updates for the beta tag (currentDigest + currentValue = a digest-only",
|
||||
"lookup; automerged under the 'digest' update type in the rule above).",
|
||||
"lookup; it arrives as a 'digest' update, which the three-day age gate above covers and",
|
||||
"automerge then carries once the PR is reviewed and green).",
|
||||
"",
|
||||
"The pattern is anchored on the three keys in their values.yaml order: repository, tag,",
|
||||
"digest. Reordering or renaming them does not fail anything — it silently stops matching,",
|
||||
@@ -407,8 +455,9 @@
|
||||
// isGreaterThan("2026.8.22-777ba8fa4", current) -> false, equals -> true
|
||||
// 777ba8fa4 was pushed at 03:06 and 9fea41204 at 05:38 the SAME day, so
|
||||
// the build group makes Renovate offer the older image as an update -
|
||||
// a downgrade, unattended, because date updates land in the patch/minor
|
||||
// automerge rule. With NaN the pair is neither equal nor ordered at all.
|
||||
// a downgrade, and one that automerge would carry to main as soon as the
|
||||
// PR is waved through as the routine date bump it looks like. With NaN
|
||||
// the pair is neither equal nor ordered at all.
|
||||
//
|
||||
// Uncaptured, the hash still has to be THERE (the pattern is anchored),
|
||||
// it just takes no part in the comparison: two builds of one day are
|
||||
|
||||
Reference in new issue
Block a user