···355355356356* avoid spamming Komodo Action webhook with any/all push/pr actions from our repo
357357* only re-deploy changed Stacks that don't include the Stacks we potentially need to make the deployments happen in the first place
358358+359359+## Reducing Renovate PR Noise
360360+361361+Nick's guide [provides a good starting point](https://nickcunningh.am/blog/how-to-automate-version-updates-for-your-self-hosted-docker-containers-with-gitea-renovate-and-komodo#configure-renovate-in-the-repo) for renovate config by showing that some packages can be ignored or clamped based on version matching. However, any further config it left up to the reader. While his example is a good starting point the config as described is not sufficient to make good use of renovate bot for a non-trivial lab, like once you get past 20 stacks.
362362+363363+### The Problem
364364+365365+#### No Project Context
366366+367367+The default PR/commit title template for Renovate only tells you the *image* that is being updated and to what version. This is fine when Renovate is being used in a single-project setting where there is maybe only one `compose.yaml` stack with a few images, but in the homelab monorepo where there can be many dozens of stack files this is not helpful at a glance:
368368+369369+
370370+_What stack do each of these images belong to? What folder? Which project?_
371371+372372+To get this context you need to 1) open the PR page and 2) switch to the Files Changed view. This is too many steps when you just want an at-a-glance view or are reviewing many opened PRs.
373373+374374+#### No Version Bump Context
375375+376376+The above screenshot reveals another issue. *What kind of update is this?* Minor? Major? Patch bump? The PR details page does describe this, but that means opening every single PR. Not useful for skimming new PRs to see what needs to be triaged.
377377+378378+#### Updates for Common Dependencies Pinned by Project
379379+380380+Though some projects do a [good job](https://github.com/immich-app/immich/blob/f909648bce8cf181512f388072abb6d1141f8a23/docker/docker-compose.yml#L52) of pinning their dependencies to specific digests or patch versions, most do not. You'll often find projects that only specify a major version like `postgres:14` or `redis:8`.
381381+382382+Usually, it's inferred by these projects that this version must stay the same. Even if the dependency can be updated to the next major version with breaking compatibility, the project may still depend on the version in their compose.yaml stack for some specific behavior.
383383+384384+Additionally, many projects in the selfhosted community use the *same, known, common dependencies* in this style. Dependencies like databases, cache, and queues are common in projects found in the homelab. With the Renovate config given in Nick's guide, all of these dependencies get PRs to bump major/minor versions when we really do not want them. It adds a ton of noise and alarm fatigue to have to constantly close these.
385385+386386+### The Solution
387387+388388+#### Better PR Titles and Labels
389389+390390+First, in your repo create new labels for the different type of version updates, like this:
391391+392392+
393393+_Version Update type labels added to the repo for PRs/Issues_
394394+395395+Next, in your `renovate.json` add to the `docker-compose` object:
396396+397397+{% raw %}
398398+```json
399399+"prBodyNotes": [
400400+ "Updates for stacks in `{{packageFileDir}}`."
401401+]
402402+```
403403+{: file='docker-compose in renovate.json'}
404404+{% endraw %}
405405+406406+and in the `docker-compose.packageRules` list **at the beginning** at the following entry:
407407+408408+{% raw %}
409409+```json
410410+{
411411+ "matchPackageNames": [
412412+ "/.*/"
413413+ ],
414414+ "addLabels": [
415415+ "{{updateType}}"
416416+ ],
417417+ "commitMessageExtra": "in stack {{packageFileDir}} from {{currentVersion}} to {{#if isPinDigest}}{{{newDigestShort}}}{{else}}{{#if isMajor}}{{prettyNewMajor}}{{else}}{{#if isSingleVersion}}{{prettyNewVersion}}{{else}}{{#if newValue}}{{{newValue}}}{{else}}{{{newDigestShort}}}{{/if}}{{/if}}{{/if}}{{/if}}",
418418+ "enabled": true
419419+}
420420+```
421421+{: file='docker-compose.packageRules in renovate.json'}
422422+{% endraw %}
423423+424424+This will modify PR titles, add labels new PRs, and include a searchable folder name in the PR body:
425425+426426+
427427+_PRs specify where compose file is located, from version, and version label_
428428+429429+The `commitMessageExtra` property modifies our PRs titles so that they include
430430+431431+* the folder path to the `compose.yaml` where the image is located (`in stacks stack/karakeep`)
432432+* the current version of the image immediately proceeding the proposed version update (`from 1.6.2 to 1.42.1`)
433433+434434+and `addLabels` makes Renovate add a label with the version update type (`minor`). If you chose distinctive colors then it is now easy to see at a glance what type of version update is being proposed.
435435+436436+#### Disable Updates for Common Dependencies
437437+438438+To fix [PR noise from common dependencies](#updates-for-common-dependencies-pinned-by-project) we can disable updates types based on package regex patterns. Add these two entries **at the end** of your `docker-compose.packageRules` list:
439439+440440+```json
441441+{
442442+ "description": "Common images that may have breaking changes between any non-patch versions (will only open patch PRs)",
443443+ "matchPackageNames": [
444444+ "/influxdb/",
445445+ "/mysql/",
446446+ "/mongo/",
447447+ "/elasticsearch/",
448448+ "/keydb/",
449449+ "/rabbitmq/",
450450+ "/mariadb/",
451451+ "/etcd/"
452452+ ],
453453+ "matchUpdateTypes": [
454454+ "major",
455455+ "minor"
456456+ ],
457457+ "enabled": false
458458+}
459459+```
460460+{: file='docker-compose.packageRules in renovate.json'}
461461+462462+```json
463463+{
464464+ "description": "Common images that may have breaking changes between major versions (will only open patch/minor PRs)",
465465+ "matchPackageNames": [
466466+ "/couchdb/",
467467+ "/redis/",
468468+ "/valkey/",
469469+ "/postgres/",
470470+ "/postgis/",
471471+ "/pgadmin/",
472472+ "/clickhouse/",
473473+ "/grafana/"
474474+ ],
475475+ "matchUpdateTypes": [
476476+ "major"
477477+ ],
478478+ "enabled": false
479479+}
480480+```
481481+{: file='docker-compose.packageRules in renovate.json'}
482482+483483+This will ensure that PRs are only opened for these images if the version update is both backwards compatible and unlikely to break the main service's usage of the dependency. I assigned these by going to each depedency's website and verifying their version update policy, or defaulting to patch-only if no policy was found.
484484+485485+> If you have specific versions of any of these you want to override per project then add another entry to `packageRules` **after** the above entries and use either [`matchPackageNames`](https://docs.renovatebot.com/configuration-options/#packagerulesmatchpackagenames) or [`matchFileNames`](https://docs.renovatebot.com/configuration-options/#packagerulesmatchfilenames) to match your specific scenario.
486486+{: .prompt-tip}
487487+488488+#### (Optional) More Noise Reducton
489489+490490+To further reduce PR noise you can add these other options to `renovate.json`:
491491+492492+##### Major Dependency Approval
493493+494494+Make sure [Dependency Dashboard](https://docs.renovatebot.com/key-concepts/dashboard/) is enabled at the top-level of your `renovate.json`
495495+496496+Use [`dependencyDashboardApproval`](https://docs.renovatebot.com/key-concepts/dashboard/#require-approval-for-major-updates) to redirect all major version bumps to the dependency dashboard. This will make Renovate list the update in the dashboard *first*, where you can then enable it via checkbox to have Renovate create the PR for it the next time it is run. Add to `docker-compose` object:
497497+498498+```json
499499+"major": {
500500+ "dependencyDashboardApproval": true
501501+}
502502+```
503503+{: file='renovate.json'}
504504+505505+##### Minimum Release Age
506506+507507+Use [`minimumReleaseAge`](https://docs.renovatebot.com/configuration-options/#minimumreleaseage) to also redirect PRs to the Dependency Dashboard. Setting a time value for this option means that all *unique* version updates that would become PRs are instead added to the Dashboard if the *last* digest update for that version is newer than Time X.
508508+509509+EX `"minimumReleaseAge": "4 day"` means if the digest for `redis:9` was created less than 4 days ago then PR will be opened and instead it will be shown on the Dashboard as a Pending Update.
510510+511511+Add add the top-level:
512512+513513+```json
514514+"minimumReleaseAge": "4 day"
515515+```
516516+{: file='renovate.json'}
517517+518518+##### Alpine Preset
519519+520520+Add [`workarounds:doNotUpgradeFromAlpineStableToEdge`](https://docs.renovatebot.com/presets-workarounds/#workaroundsdonotupgradefromalpinestabletoedge) to the `renovate.json` `extends` list to prevent PRs that try to upgrade alpine images.