diff --git a/.gitea/workflows/renovate.yml b/.gitea/workflows/renovate.yml index 2889d7a..39ddf8d 100644 --- a/.gitea/workflows/renovate.yml +++ b/.gitea/workflows/renovate.yml @@ -2,7 +2,9 @@ name: Renovate on: schedule: - - cron: "0 4 * * 1" # Weekly Monday 4am + # Daily: with automergeType=branch, Renovate merges a branch whose CI is + # green on its *next* run, so a weekly run took two weeks per update. + - cron: "0 4 * * *" workflow_dispatch: jobs: @@ -24,5 +26,10 @@ jobs: RENOVATE_ENDPOINT: http://git:3000/api/v1 RENOVATE_REPOSITORIES: homelab/stack RENOVATE_TOKEN: ${{ secrets.RENOVATE_TOKEN }} + # github.com lookups (github-tags/-releases pins, action pins, the + # uv/node tools Renovate installs to update lock files). Without it + # the anonymous 60/h API limit fails them all ("Package lookup + # failures", artifactErrors). A read-only token is enough. + GITHUB_COM_TOKEN: ${{ secrets.GITHUB_COM_TOKEN }} RENOVATE_GIT_AUTHOR: "Renovate Bot " LOG_LEVEL: "info" diff --git a/dev/scripts/marimo_latest.py b/dev/scripts/marimo_latest.py index ed6819a..b361be1 100644 --- a/dev/scripts/marimo_latest.py +++ b/dev/scripts/marimo_latest.py @@ -231,7 +231,14 @@ def preflight() -> None: raise Failed("preflight", f"uncommitted changes in {', '.join(IMAGE_INPUTS)}") git("fetch", "-q", "gitea", "main") if git("rev-list", "--count", "HEAD..gitea/main") != "0": - raise Failed("preflight", "main is behind gitea/main; pull first") + # Renovate automerges onto the server's main. Fast-forward only: git + # refuses if that would touch files someone has modified here. + r = run(["git", "merge", "--ff-only", "gitea/main"], check=False) + if r.returncode: + raise Failed( + "preflight", f"can't fast-forward to gitea/main: {r.stderr[-300:]}" + ) + log(f"fast-forwarded main to {git('rev-parse', '--short=7', 'HEAD')}") def upgrade(old: str, new: str) -> None: diff --git a/renovate.json b/renovate.json index b1983f2..b71bcba 100644 --- a/renovate.json +++ b/renovate.json @@ -3,7 +3,21 @@ "extends": ["config:recommended"], "labels": ["dependencies"], "automerge": false, + "automergeType": "branch", + "automergeStrategy": "fast-forward", + "prHourlyLimit": 0, "minimumReleaseAge": "7 days", + "ignorePaths": [ + "**/node_modules/**", + "**/bower_components/**", + "**/vendor/**", + "**/examples/**", + "**/__tests__/**", + "**/test/**", + "**/tests/**", + "**/__fixtures__/**", + "infra/traefik/plugins/src/**" + ], "osvVulnerabilityAlerts": true, "vulnerabilityAlerts": { "labels": ["dependencies", "security"] @@ -27,6 +41,16 @@ "matchPackageNames": ["pymupdf"], "allowedVersions": "<2" }, + { + "description": "Every service shares the same .duckdb files; a new duckdb major is a coordinated migration, not a bump (see pyproject's notebooks extra).", + "matchPackageNames": ["duckdb"], + "allowedVersions": "<2" + }, + { + "description": "dev/scripts/marimo_latest.py (nightly timer) owns the notebooks image's marimo pin end to end: bump, build, gate, roll. A Renovate bump would land the pin without rolling, and the timer would then see it as current.", + "matchDepNames": ["marimo-team/marimo"], + "enabled": false + }, { "description": "Generated-workflow tool pins: gen_config.py must re-emit .gitea/workflows after the bump, so a human merges these.", "matchFileNames": ["dev/scripts/backends/gitea.py"],