From a9ece85f7e8f45ed5a018126415985002f2486e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Wirtel?= Date: Tue, 3 Feb 2026 08:44:49 +0100 Subject: [PATCH 1/4] feat: integrate Renovate for automated dependency updates Add Renovate configuration with pip-compile support for automated dependency management. Configuration includes: - Explicit file patterns for main.txt, dev.txt, production.txt - Python 3.13 constraint matching Heroku runtime - Django/Wagtail ecosystem grouping with Monday scheduling - Intelligent automerge: only dev.txt patches, never production - Security updates prioritized with separate PRs - Rate limiting to avoid PR spam - Monthly lock file maintenance This setup is optimized for safe Heroku deployments with manual review required for production dependencies. Closes #187 Co-Authored-By: Claude Sonnet 4.5 --- renovate.json | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 renovate.json diff --git a/renovate.json b/renovate.json new file mode 100644 index 0000000..fb412c8 --- /dev/null +++ b/renovate.json @@ -0,0 +1,84 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": ["config:recommended"], + "description": "Renovate configuration for Python Ireland website - pip-compile workflow with Heroku deployment", + "pip-compile": { + "managerFilePatterns": [ + "^requirements/main\\.txt$", + "^requirements/dev\\.txt$", + "^requirements/production\\.txt$" + ] + }, + "pip_requirements": { + "enabled": false + }, + "pip_setup": { + "enabled": false + }, + "constraints": { + "python": "3.13" + }, + "ignorePaths": [ + "**/node_modules/**", + "**/bower_components/**", + "**/vendor/**", + "**/.venv/**", + "**/pythonie-venv/**" + ], + "packageRules": [ + { + "description": "Group Django ecosystem updates together", + "groupName": "Django ecosystem", + "matchPackagePatterns": ["^[Dd]jango", "^[Ww]agtail"], + "matchManagers": ["pip-compile"], + "schedule": ["before 9am on monday"] + }, + { + "description": "Separate PR for security updates - always prioritize", + "groupName": "Security updates", + "matchUpdateTypes": ["patch"], + "matchCurrentVersion": "!/^0/", + "vulnerabilityAlerts": { + "enabled": true + }, + "prPriority": 10 + }, + { + "description": "Automerge only dev dependencies patches (safer for production)", + "matchManagers": ["pip-compile"], + "matchFiles": ["requirements/dev.txt"], + "matchUpdateTypes": ["patch"], + "automerge": true, + "automergeType": "pr" + }, + { + "description": "Never automerge production dependencies - require manual review", + "matchManagers": ["pip-compile"], + "matchFiles": ["requirements/main.txt", "requirements/production.txt"], + "automerge": false + }, + { + "description": "Group all minor and patch updates together (except Django/Wagtail)", + "groupName": "All non-major dependencies", + "matchUpdateTypes": ["minor", "patch"], + "matchPackagePatterns": ["*"], + "excludePackagePatterns": ["^[Dd]jango", "^[Ww]agtail"], + "schedule": ["before 9am on monday"] + } + ], + "lockFileMaintenance": { + "enabled": true, + "schedule": ["before 9am on the first day of the month"], + "commitMessageAction": "Refresh pip-compile lock files", + "branchTopic": "pip-compile-refresh" + }, + "prConcurrentLimit": 3, + "prCreation": "not-pending", + "prHourlyLimit": 2, + "semanticCommits": "enabled", + "separateMajorMinor": true, + "separateMinorPatch": false, + "vulnerabilityAlerts": { + "enabled": true + } +} From 8e5fb21ccd1c43ced5ab65a1e3c6f1682d0c24de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Wirtel?= Date: Fri, 25 Sep 2026 07:07:48 +0200 Subject: [PATCH 2/4] fix(renovate): target pyproject.toml + uv.lock via the pep621 manager The previous config was written for the pip-compile workflow and pointed at requirements/{main,dev,production}.txt, which no longer exist since the migration to pyproject.toml + uv.lock (#247). It was a no-op. - Drop the pip-compile / pip_requirements / pip_setup blocks; the pep621 manager (enabled by config:recommended) picks up pyproject.toml and drives `uv lock` for uv.lock. - Main vs dev split now uses depTypes instead of file paths: [project.dependencies] -> "project.dependencies" (never automerged), [dependency-groups] -> "dependency-groups" (patch automerge). pep621 keeps the PEP 735 group name only in managerData, so it cannot be matched; "dev" is currently the only group. Dev patches get their own group so automerge is not blocked by production deps on the same branch. - Security: the vulnerability alert settings were inside a packageRule restricted to patch updates (and to non-0.x versions), which excluded fixes needing a minor bump. Move them to the top-level vulnerabilityAlerts object with no update-type restriction. prPriority is dropped: it is not allowed there, and vulnerability PRs already bypass schedule and PR limits. - Restrict the "All non-major dependencies" group to pep621 so Dockerfile and GitHub Actions bumps are not mixed into the Monday Python group. - Replace the removed matchPackagePatterns / excludePackagePatterns / matchFiles options with matchPackageNames regexes and depTypes. - Disable requires-python updates: Python is pinned to 3.13.x. - Run lockFileMaintenance weekly instead of monthly: most dependencies in pyproject.toml have no version specifier, so Renovate skips them (skipReason "unspecified-version") and the uv.lock refresh is the only way they get updated. Validated with `renovate-config-validator --strict --no-global` and a local `renovate --platform=local --dry-run=extract` run. --- renovate.json | 77 +++++++++++++++++++-------------------------------- 1 file changed, 28 insertions(+), 49 deletions(-) diff --git a/renovate.json b/renovate.json index fb412c8..2c96560 100644 --- a/renovate.json +++ b/renovate.json @@ -1,76 +1,53 @@ { "$schema": "https://docs.renovatebot.com/renovate-schema.json", "extends": ["config:recommended"], - "description": "Renovate configuration for Python Ireland website - pip-compile workflow with Heroku deployment", - "pip-compile": { - "managerFilePatterns": [ - "^requirements/main\\.txt$", - "^requirements/dev\\.txt$", - "^requirements/production\\.txt$" - ] - }, - "pip_requirements": { - "enabled": false - }, - "pip_setup": { - "enabled": false - }, + "description": "Renovate configuration for Python Ireland website - pyproject.toml + uv.lock (pep621 manager) with Heroku deployment", "constraints": { "python": "3.13" }, - "ignorePaths": [ - "**/node_modules/**", - "**/bower_components/**", - "**/vendor/**", - "**/.venv/**", - "**/pythonie-venv/**" - ], "packageRules": [ + { + "description": "Python is pinned to 3.13.x (Heroku, Docker, mise): never bump requires-python", + "matchManagers": ["pep621"], + "matchDepTypes": ["requires-python"], + "enabled": false + }, { "description": "Group Django ecosystem updates together", "groupName": "Django ecosystem", - "matchPackagePatterns": ["^[Dd]jango", "^[Ww]agtail"], - "matchManagers": ["pip-compile"], + "matchManagers": ["pep621"], + "matchPackageNames": ["/^django/i", "/^wagtail/i"], "schedule": ["before 9am on monday"] }, { - "description": "Separate PR for security updates - always prioritize", - "groupName": "Security updates", - "matchUpdateTypes": ["patch"], - "matchCurrentVersion": "!/^0/", - "vulnerabilityAlerts": { - "enabled": true - }, - "prPriority": 10 + "description": "Group all minor and patch Python updates together (except Django/Wagtail). Restricted to pep621 so Dockerfile and GitHub Actions bumps are not mixed in", + "groupName": "All non-major dependencies", + "matchManagers": ["pep621"], + "matchUpdateTypes": ["minor", "patch"], + "matchPackageNames": ["!/^django/i", "!/^wagtail/i"], + "schedule": ["before 9am on monday"] }, { - "description": "Automerge only dev dependencies patches (safer for production)", - "matchManagers": ["pip-compile"], - "matchFiles": ["requirements/dev.txt"], + "description": "Automerge only patches of the PEP 735 dev group (safer for production). The pep621 manager reports every [dependency-groups] entry with depType 'dependency-groups' (the group name is not matchable); 'dev' is the only group in pyproject.toml. Own group so automerge is not blocked by production deps sharing the branch", + "groupName": "Dev dependencies (patch)", + "matchManagers": ["pep621"], + "matchDepTypes": ["dependency-groups"], "matchUpdateTypes": ["patch"], "automerge": true, "automergeType": "pr" }, { - "description": "Never automerge production dependencies - require manual review", - "matchManagers": ["pip-compile"], - "matchFiles": ["requirements/main.txt", "requirements/production.txt"], + "description": "Never automerge production dependencies ([project.dependencies]) - require manual review", + "matchManagers": ["pep621"], + "matchDepTypes": ["project.dependencies"], "automerge": false - }, - { - "description": "Group all minor and patch updates together (except Django/Wagtail)", - "groupName": "All non-major dependencies", - "matchUpdateTypes": ["minor", "patch"], - "matchPackagePatterns": ["*"], - "excludePackagePatterns": ["^[Dd]jango", "^[Ww]agtail"], - "schedule": ["before 9am on monday"] } ], "lockFileMaintenance": { "enabled": true, - "schedule": ["before 9am on the first day of the month"], - "commitMessageAction": "Refresh pip-compile lock files", - "branchTopic": "pip-compile-refresh" + "schedule": ["before 9am on monday"], + "commitMessageAction": "Refresh uv.lock", + "branchTopic": "uv-lock-refresh" }, "prConcurrentLimit": 3, "prCreation": "not-pending", @@ -79,6 +56,8 @@ "separateMajorMinor": true, "separateMinorPatch": false, "vulnerabilityAlerts": { - "enabled": true + "enabled": true, + "groupName": "Security updates", + "labels": ["security"] } } From ff55026636f5622e95afda86ea630063fafe92ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Wirtel?= Date: Fri, 25 Sep 2026 07:44:42 +0200 Subject: [PATCH 3/4] fix(renovate): use rangeStrategy "bump" for pep621 pep621 has no manager-specific range strategy, so "auto" resolves to "replace". With "replace", a ">=" lower bound that already allows the new version produces no update at all, which would make the lower bounds added to pyproject.toml useless. "bump" raises the lower bound in pyproject.toml and updates uv.lock in the same PR. Checked with a local renovate dry-run on a copy with older locked versions: "replace" proposed nothing, while "bump" proposed boto3 >=1.43.90 -> >=1.43.102, requests >=2.33.0 -> >=2.34.2, etc. --- renovate.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/renovate.json b/renovate.json index 2c96560..3e16ceb 100644 --- a/renovate.json +++ b/renovate.json @@ -6,6 +6,11 @@ "python": "3.13" }, "packageRules": [ + { + "description": "Bump the '>=' lower bounds in pyproject.toml together with uv.lock. With the default 'replace' strategy a '>=' range already satisfied by the new version produces no update at all", + "matchManagers": ["pep621"], + "rangeStrategy": "bump" + }, { "description": "Python is pinned to 3.13.x (Heroku, Docker, mise): never bump requires-python", "matchManagers": ["pep621"], From d32f1524455811702529028f5df60acb979ea6ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Wirtel?= Date: Fri, 25 Sep 2026 07:54:31 +0200 Subject: [PATCH 4/4] feat(renovate): group uv updates, keep Python on 3.13 and Postgres on 17 - uv is versioned in three places (pep621 dev dependency "uv", Docker image "ghcr.io/astral-sh/uv", mise tool "astral-sh/uv"): group them in a single "uv" PR so they stay in sync. - Python is pinned to 3.13.x: the Docker base image, mise and .python-version only accept 3.13 (requires-python is already disabled). - Production runs PostgreSQL 17 on Heroku: CI and docker-compose stay on 17. Checked with a local renovate dry-run across all managers: the Dockerfile and mise uv bumps land on renovate/uv, and no Python 3.14 or Postgres 18 update is proposed. --- renovate.json | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/renovate.json b/renovate.json index 3e16ceb..574080e 100644 --- a/renovate.json +++ b/renovate.json @@ -41,6 +41,21 @@ "automerge": true, "automergeType": "pr" }, + { + "description": "Keep uv in sync: one PR for the dev dependency (pep621), the Docker image (Dockerfile) and the mise tool", + "groupName": "uv", + "matchPackageNames": ["uv", "ghcr.io/astral-sh/uv", "astral-sh/uv"] + }, + { + "description": "Python is pinned to 3.13.x: only allow 3.13 for the Docker base image, mise and .python-version", + "matchDepNames": ["python"], + "allowedVersions": "/^3\\.13([.-]|$)/" + }, + { + "description": "Production (Heroku) runs PostgreSQL 17: keep CI and docker-compose on the same major", + "matchDepNames": ["postgres"], + "allowedVersions": "/^17([.-]|$)/" + }, { "description": "Never automerge production dependencies ([project.dependencies]) - require manual review", "matchManagers": ["pep621"],