Files
homelab-design/decisions/0057-renovate-per-repo-configs.md
Billy D. 51e6cee8ab
All checks were successful
Update README with ADR Index / update-readme (push) Successful in 6s
feat: ADR-0056 custom voice support, ADR-0057 Renovate per-repo configs
- ADR-0056: custom voice support in tts-module (VoiceRegistry)
- ADR-0057: shared Renovate preset rollout to all app repos
- Update ADR-0013: add tts-module and stt-module to CI table
- Update ADR-0036: cross-reference ADR-0057
2026-02-13 15:31:33 -05:00

8.3 KiB

Per-Repository Renovate Configurations

  • Status: accepted
  • Date: 2026-02-13
  • Deciders: Billy
  • Technical Story: Roll out Renovate configs to all application repos so the self-hosted CronJob (ADR-0036) can scan them for dependency and security updates

Context and Problem Statement

ADR-0036 deployed a self-hosted Renovate CronJob that auto-discovers all daviestechlabs/* repos, and the homelab-k8s2 GitOps repo already has a detailed .renovaterc.json5. However, none of the application repositories contain a renovate.json yet, which means:

  • Renovate falls back to its bare defaults (no grouping, no auto-merge, no schedule control).
  • Python repos with both pyproject.toml and requirements.txt get duplicate PRs.
  • No security-update fast-path is configured.
  • Major updates are auto-merged without review because no rule prevents it.

We need a consistent per-repo configuration that applies the correct managers, grouping, auto-merge policy, and security rules to every repo.

Decision Drivers

  • Consistent behaviour across all repos in the org
  • Correct manager selection per ecosystem (Python/Go/Node/Docker)
  • Security updates treated with highest priority
  • Non-major updates grouped and auto-merged to reduce PR noise
  • Major updates require manual review
  • Schedule aligned with CI runner availability

Considered Options

  1. Shared org-preset in a dedicated renovate-config repo
  2. Identical standalone renovate.json copied into every repo
  3. No per-repo config (rely on autodiscover defaults)

Decision Outcome

Chosen option: Option 1 — Shared org-preset with thin per-repo renovate.json

A central renovate-config repo holds a default.json preset that every application repo extends. Repo-specific overrides (extra managers, ignored paths) live in each repo's renovate.json. This keeps configuration DRY while allowing per-repo tailoring.

Positive Consequences

  • Single place to update grouping strategy, schedule, and auto-merge policy
  • Each repo's renovate.json is 5-10 lines — easy to audit
  • Security updates auto-merge immediately across all repos
  • Major updates always require manual review

Negative Consequences

  • Extra repository (renovate-config) to maintain
  • Preset changes propagate to all repos on next run — regressions possible

Shared Preset (renovate-config repo)

default.json

{
  "$schema": "https://docs.renovatebot.com/renovate-schema.json",
  "description": "DaviesTechLabs shared Renovate preset for application repos",
  "extends": [
    "config:recommended",
    "group:allNonMajor",
    ":automergeMinor",
    ":automergePatch",
    ":semanticCommits"
  ],
  "dependencyDashboard": true,
  "platformAutomerge": true,
  "schedule": ["before 6am on monday"],
  "timezone": "America/New_York",
  "prCreation": "immediate",
  "vulnerabilityAlerts": {
    "enabled": true,
    "labels": ["security"]
  },
  "packageRules": [
    {
      "description": "Auto-merge security updates immediately",
      "matchCategories": ["security"],
      "automerge": true,
      "schedule": ["at any time"],
      "prPriority": 10
    },
    {
      "description": "Major updates require manual review",
      "matchUpdateTypes": ["major"],
      "automerge": false,
      "labels": ["major-update"]
    },
    {
      "description": "Group Gitea Actions updates",
      "matchManagers": ["gitea-actions"],
      "groupName": "gitea-actions"
    },
    {
      "description": "Group Docker base-image updates",
      "matchManagers": ["dockerfile"],
      "groupName": "docker-base-images"
    },
    {
      "description": "Pin uv in CI to digest for reproducibility",
      "matchManagers": ["gitea-actions"],
      "matchPackageNames": ["astral-sh/setup-uv"],
      "pinDigests": true
    }
  ]
}

python.json (supplemental preset for Python repos)

{
  "$schema": "https://docs.renovatebot.com/renovate-schema.json",
  "description": "Python-specific rules for uv/pip repos",
  "packageRules": [
    {
      "description": "Group Python dev dependencies",
      "matchManagers": ["pep621", "pip_requirements"],
      "matchDepTypes": ["devDependencies", "optional-dependencies"],
      "groupName": "python-dev-deps"
    },
    {
      "description": "Prefer pyproject.toml over requirements.txt when both exist",
      "matchManagers": ["pip_requirements"],
      "matchFileNames": ["requirements.txt"],
      "enabled": false
    }
  ]
}

golang.json (supplemental preset for Go repos)

{
  "$schema": "https://docs.renovatebot.com/renovate-schema.json",
  "description": "Go-specific rules",
  "packageRules": [
    {
      "description": "Group all Go module updates",
      "matchManagers": ["gomod"],
      "groupName": "go-modules"
    }
  ],
  "postUpdateOptions": ["gomodTidy"]
}

Per-Repo Configuration

Each application repo gets a minimal renovate.json that extends the org preset.

Python repos (chat-handler, voice-assistant, handler-base, pipeline-bridge, stt-module, tts-module, ray-serve, mlflow, gradio-ui)

{
  "$schema": "https://docs.renovatebot.com/renovate-schema.json",
  "extends": [
    "local>daviestechlabs/renovate-config",
    "local>daviestechlabs/renovate-config:python"
  ]
}

Go repos (companions-frontend, ntfy-discord)

{
  "$schema": "https://docs.renovatebot.com/renovate-schema.json",
  "extends": [
    "local>daviestechlabs/renovate-config",
    "local>daviestechlabs/renovate-config:golang"
  ]
}

companions-frontend (Go + Node hybrid)

{
  "$schema": "https://docs.renovatebot.com/renovate-schema.json",
  "extends": [
    "local>daviestechlabs/renovate-config",
    "local>daviestechlabs/renovate-config:golang"
  ],
  "packageRules": [
    {
      "description": "Group npm dev dependencies",
      "matchManagers": ["npm"],
      "matchDepTypes": ["devDependencies"],
      "groupName": "npm-dev-deps"
    }
  ]
}

Repo Coverage Matrix

Repository Ecosystem Preset(s) Notes
homelab-k8s2 Helm/Flux/K8s/Docker Own .renovaterc.json5 Already configured
chat-handler Python, Docker, Gitea Actions default + python
voice-assistant Python, Docker, Gitea Actions default + python
handler-base Python, Docker, Gitea Actions default + python
pipeline-bridge Python, Docker, Gitea Actions default + python
stt-module Python, Docker, Gitea Actions default + python requirements.txt disabled
tts-module Python, Docker, Gitea Actions default + python requirements.txt disabled
ray-serve Python, Gitea Actions default + python requirements.txt disabled
mlflow Python, Gitea Actions default + python requirements.txt disabled
gradio-ui Python (requirements.txt only), Docker default + python No pyproject.toml — requirements.txt stays enabled
kuberay-images Python (amdsmi-shim), Docker default + python Multiple Dockerfiles
companions-frontend Go, Node, Docker default + golang + npm Hybrid repo
ntfy-discord Go, Docker, Gitea Actions default + golang
kubeflow Gitea Actions only default Pipeline definitions only
argo None default Workflow templates only

Update Flow

 Renovate CronJob (every 8h)
       │
       ▼
 Autodiscover daviestechlabs/*
       │
       ▼
 Read repo's renovate.json
       │
       ├── extends local>daviestechlabs/renovate-config
       │         │
       │         └── Fetches default.json + python.json/golang.json
       │
       ▼
 Scan dependencies (pyproject.toml, Dockerfile, go.mod, etc.)
       │
       ▼
 Create/update PRs
       │
       ├── Security → auto-merge immediately
       ├── Patch/Minor → auto-merge (minor after 3-day stabilisation)
       └── Major → label "major-update", await manual review