Debounce Renovate and exclude from CI #32

Closed
opened 2026-11-09 13:59:13 +01:00 by lucas · 1 comment
Owner

Problem

Renovate opens pull requests to update its own runner image far too often. The
renovate/renovate container tag pinned in .forgejo/workflows/renovate.yml moved four
times in three days (PRs #10 → 44.222.0, #21 → 44.222.1, #26 → 44.222.5, #31 → 44.223.1),
making it the single loudest source of dependency PRs in the repository. Nothing about
that image needs to be current: it is the tool that opens the PRs, it never ships in the
product, and a release-per-day cadence buys nothing.

Renovate should propose its own updates roughly once a week. Every other package keeps its
current behaviour — Rust crates, the bun and curl images, the pinned action digests and the
stylelint group all continue to arrive as they land.

The issue title also mentions excluding Renovate from CI workflows. That half is
deliberately not implemented. master has branch protection with required status
checks, and the five contexts a pull request must produce are pr / assets, pr / lint,
pr / check, pr / test and pr / image. A workflow-level paths-ignore filter stops
the workflow from being created at all, so those contexts never appear and the pull request
becomes unmergeable — the symptom in gitea#36895.
A synthetic skipped status for filtered-out workflows exists in Gitea but its presence in
this Forgejo is unverified. The alternative, per-job if: guards on all five jobs, is
disproportionate machinery once the self-update PR arrives only once a week. The CI jobs
stay exactly as they are.

Plan

Step 0 — start from origin/master

The working tree in this workspace may be behind. Branch from origin/master, which is at
50a02e6 or later, and confirm before editing that .renovaterc contains a
packageRules array with exactly two entries: an automerge rule matching
cgr.dev/chainguard/static, docker.io/curlimages/curl, docker.io/oven/bun and
oven-sh/bun, and a groupName: "stylelint" rule.

If .renovaterc has no packageRules key at all, the checkout is stale (that is the
pre-50a02e6 shape of the file) — fetch and rebase before continuing, do not add the array
from scratch.

Step 1 — add the renovate/renovate schedule rule

Append one entry to the packageRules array in .renovaterc, after the existing stylelint
grouping rule, so the array has three entries in total. Verbatim content, 2-space indent to
match the rest of the file:

    {
      "matchPackageNames": ["renovate/renovate"],
      "schedule": ["* 0-5 * * 1"]
    }

This is the entire code change. No other file is touched.

Decisions already made, so they are not re-opened during execution:

  • The match string is the bare renovate/renovate, not a registry-qualified form.
    Renovate's dep name mirrors the literal container.image: value in
    .forgejo/workflows/renovate.yml, which is renovate/renovate:<tag>@<digest>. The
    existing rule entries use qualified names (docker.io/oven/bun) because those images are
    written qualified at their use sites. Confirmed by PR titles: #31 is "update
    renovate/renovate docker tag" while #19 is "update docker.io/oven/bun docker
    tag".
  • A literal cron window, not the schedule:weekly preset. schedule:weekly expands to
    ["* 0-3 * * 1"]; the wider ["* 0-5 * * 1"] (Mondays 00:00–05:59) keeps the behaviour
    readable in the file itself and tolerates a delayed or drifting run. .renovaterc sets no
    timezone, so Renovate evaluates this in UTC, and the hourly workflow cron puts six runs
    inside the window.
  • No automerge on this rule. The four automerged packages keep their settings; the
    weekly Renovate self-update PR is merged by hand like any other.
  • Position matters only for precedence, and there is none here: no other
    packageRules entry matches renovate/renovate. Append rather than reorder.

Step 2 — leave the workflow triggers alone

.forgejo/workflows/renovate.yml is not modified. Its cron: "0 * * * *", its push
trigger on master filtered to Cargo.toml, Cargo.lock, .renovaterc and
.forgejo/workflows/**, and its workflow_dispatch inputs all stay as they are. Renovate
keeps running hourly; the new rule only stops it from creating or updating a branch for
its own image outside the Monday window. Existing branches are still refreshed between
windows, because Renovate's updateNotScheduled defaults to true.

.forgejo/workflows/pr.yaml is not modified either — no paths, no paths-ignore, no
per-job if: guards. See ## Problem for why.

Verification

1. The config parses

Prerequisite: Docker with network access to Docker Hub. From the repository root:

docker run --rm -v "$PWD/.renovaterc:/tmp/.renovaterc:ro" \
  renovate/renovate:44.223.1 \
  renovate-config-validator /tmp/.renovaterc

Expected: exits 0 and reports the config as valid. A malformed schedule string is
rejected here rather than silently ignored at runtime, which is the failure mode this guards
against.

2. Renovate actually honours the rule

Trigger the Renovate workflow out of schedule from the Forgejo UI
(Actions → Renovate → Run workflow) with inputs logLevel: debug and
dryRun: full. A dry run creates no branches and no PRs, so this is safe to run on the
branch before merge.

Then read the job log and confirm both of:

  • The renovate/renovate dependency is extracted and evaluated, and is reported as not
    within its schedule
    , so no branch is created for it. Do not grep for a specific
    sentence — Renovate's wording varies by version; look for the renovate/renovate
    dependency and the schedule decision logged alongside it.
  • Other dependencies are unaffected: Cargo and npm dependencies are still evaluated
    normally and are not reported as out of schedule. This is the check that catches an
    over-broad matchPackageNames, which is the realistic way to get this wrong.

Timing contingency: this check only reads cleanly when run outside Mondays
00:00–05:59 UTC. If the dispatch necessarily lands inside the window, accept the complement
instead: the log must show the renovate/renovate dependency evaluated with its schedule
satisfied, while other dependencies show no schedule at all. Either direction proves
the rule is attached to the right dependency and to nothing else, which is what is being
verified.

3. Open pull requests are undisturbed

PRs #14 (reqwest 0.13) and #11 (asserting 0.17.0) are open at the time of writing.
After the change is merged and the next hourly Renovate run completes, confirm they are
still open and still being rebased — the new rule must not have altered handling of any
package other than renovate/renovate.

Assumptions & contingencies

  • master has branch protection with required status checks. Stated by the repository
    owner; not readable with the tools available in this session, so it remains unverified — confirm first. It is the reason the CI-exclusion half of the issue is dropped. If it
    turns out no status checks are required, the dropped work becomes safe to do, but it is
    still out of scope for this change and belongs in a separate issue.
  • Renovate evaluates schedule per package rule, letting one package be throttled while
    the repository default stays "at any time".
    This is the documented behaviour of
    packageRules and the whole basis of the change. If the dry run in Verification step 2
    shows the schedule being applied repository-wide instead of to renovate/renovate alone,
    stop and report it rather than compensating — compensating would mean adding an
    explicit "schedule": ["* * * * *"] default, which silently changes behaviour for every
    other package and is exactly what this issue excludes.
## Problem Renovate opens pull requests to update its own runner image far too often. The `renovate/renovate` container tag pinned in `.forgejo/workflows/renovate.yml` moved four times in three days (PRs #10 → 44.222.0, #21 → 44.222.1, #26 → 44.222.5, #31 → 44.223.1), making it the single loudest source of dependency PRs in the repository. Nothing about that image needs to be current: it is the tool that opens the PRs, it never ships in the product, and a release-per-day cadence buys nothing. Renovate should propose its own updates roughly once a week. Every other package keeps its current behaviour — Rust crates, the bun and curl images, the pinned action digests and the stylelint group all continue to arrive as they land. The issue title also mentions excluding Renovate from CI workflows. That half is deliberately **not** implemented. `master` has branch protection with required status checks, and the five contexts a pull request must produce are `pr / assets`, `pr / lint`, `pr / check`, `pr / test` and `pr / image`. A workflow-level `paths-ignore` filter stops the workflow from being created at all, so those contexts never appear and the pull request becomes unmergeable — the symptom in [gitea#36895](https://github.com/go-gitea/gitea/issues/36895). A synthetic `skipped` status for filtered-out workflows exists in Gitea but its presence in this Forgejo is `unverified`. The alternative, per-job `if:` guards on all five jobs, is disproportionate machinery once the self-update PR arrives only once a week. The CI jobs stay exactly as they are. ## Plan ### Step 0 — start from `origin/master` The working tree in this workspace may be behind. Branch from `origin/master`, which is at `50a02e6` or later, and confirm before editing that `.renovaterc` contains a `packageRules` array with exactly two entries: an automerge rule matching `cgr.dev/chainguard/static`, `docker.io/curlimages/curl`, `docker.io/oven/bun` and `oven-sh/bun`, and a `groupName: "stylelint"` rule. If `.renovaterc` has no `packageRules` key at all, the checkout is stale (that is the pre-`50a02e6` shape of the file) — fetch and rebase before continuing, do not add the array from scratch. ### Step 1 — add the `renovate/renovate` schedule rule Append one entry to the `packageRules` array in `.renovaterc`, after the existing stylelint grouping rule, so the array has three entries in total. Verbatim content, 2-space indent to match the rest of the file: ```json { "matchPackageNames": ["renovate/renovate"], "schedule": ["* 0-5 * * 1"] } ``` This is the entire code change. No other file is touched. Decisions already made, so they are not re-opened during execution: - **The match string is the bare `renovate/renovate`**, not a registry-qualified form. Renovate's dep name mirrors the literal `container.image:` value in `.forgejo/workflows/renovate.yml`, which is `renovate/renovate:<tag>@<digest>`. The existing rule entries use qualified names (`docker.io/oven/bun`) because those images are written qualified at their use sites. Confirmed by PR titles: #31 is "update **renovate/renovate** docker tag" while #19 is "update **docker.io/oven/bun** docker tag". - **A literal cron window, not the `schedule:weekly` preset.** `schedule:weekly` expands to `["* 0-3 * * 1"]`; the wider `["* 0-5 * * 1"]` (Mondays 00:00–05:59) keeps the behaviour readable in the file itself and tolerates a delayed or drifting run. `.renovaterc` sets no `timezone`, so Renovate evaluates this in UTC, and the hourly workflow cron puts six runs inside the window. - **No `automerge` on this rule.** The four automerged packages keep their settings; the weekly Renovate self-update PR is merged by hand like any other. - **Position matters only for precedence**, and there is none here: no other `packageRules` entry matches `renovate/renovate`. Append rather than reorder. ### Step 2 — leave the workflow triggers alone `.forgejo/workflows/renovate.yml` is not modified. Its `cron: "0 * * * *"`, its `push` trigger on `master` filtered to `Cargo.toml`, `Cargo.lock`, `.renovaterc` and `.forgejo/workflows/**`, and its `workflow_dispatch` inputs all stay as they are. Renovate keeps running hourly; the new rule only stops it from *creating or updating a branch* for its own image outside the Monday window. Existing branches are still refreshed between windows, because Renovate's `updateNotScheduled` defaults to true. `.forgejo/workflows/pr.yaml` is not modified either — no `paths`, no `paths-ignore`, no per-job `if:` guards. See `## Problem` for why. ## Verification ### 1. The config parses Prerequisite: Docker with network access to Docker Hub. From the repository root: ```sh docker run --rm -v "$PWD/.renovaterc:/tmp/.renovaterc:ro" \ renovate/renovate:44.223.1 \ renovate-config-validator /tmp/.renovaterc ``` Expected: exits 0 and reports the config as valid. A malformed `schedule` string is rejected here rather than silently ignored at runtime, which is the failure mode this guards against. ### 2. Renovate actually honours the rule Trigger the Renovate workflow out of schedule from the Forgejo UI (`Actions` → `Renovate` → `Run workflow`) with inputs `logLevel: debug` and `dryRun: full`. A dry run creates no branches and no PRs, so this is safe to run on the branch before merge. Then read the job log and confirm both of: - The `renovate/renovate` dependency is extracted and evaluated, and is reported as **not within its schedule**, so no branch is created for it. Do not grep for a specific sentence — Renovate's wording varies by version; look for the `renovate/renovate` dependency and the schedule decision logged alongside it. - Other dependencies are **unaffected**: Cargo and npm dependencies are still evaluated normally and are not reported as out of schedule. This is the check that catches an over-broad `matchPackageNames`, which is the realistic way to get this wrong. **Timing contingency:** this check only reads cleanly when run *outside* Mondays 00:00–05:59 UTC. If the dispatch necessarily lands inside the window, accept the complement instead: the log must show the `renovate/renovate` dependency evaluated with its schedule **satisfied**, while other dependencies show no schedule at all. Either direction proves the rule is attached to the right dependency and to nothing else, which is what is being verified. ### 3. Open pull requests are undisturbed PRs #14 (`reqwest` 0.13) and #11 (`asserting` 0.17.0) are open at the time of writing. After the change is merged and the next hourly Renovate run completes, confirm they are still open and still being rebased — the new rule must not have altered handling of any package other than `renovate/renovate`. ## Assumptions & contingencies - **`master` has branch protection with required status checks.** Stated by the repository owner; not readable with the tools available in this session, so it remains `unverified — confirm first`. It is the reason the CI-exclusion half of the issue is dropped. If it turns out no status checks are required, the dropped work becomes safe to do, but it is still out of scope for this change and belongs in a separate issue. - **Renovate evaluates `schedule` per package rule, letting one package be throttled while the repository default stays "at any time".** This is the documented behaviour of `packageRules` and the whole basis of the change. If the dry run in Verification step 2 shows the schedule being applied repository-wide instead of to `renovate/renovate` alone, stop and report it rather than compensating — compensating would mean adding an explicit `"schedule": ["* * * * *"]` default, which silently changes behaviour for every other package and is exactly what this issue excludes.
Collaborator

omp-deck: the implementer session failed: the agent's turn failed.

Details are in omp-deck session 01a1c10f-3f23-7000-984a-19572b155e0d.

omp-deck: the implementer session failed: the agent's turn failed. Details are in omp-deck session `01a1c10f-3f23-7000-984a-19572b155e0d`.
lucas closed this issue 2026-11-09 17:21:36 +01:00
Sign in to join this conversation.
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
lucas/logview#32
No description provided.