Skip to content

renovate-group

A schedule-driven Renovate run in autodiscover mode. One job asks the GitLab API "what can this token see?", enumerates a group filter (e.g. phpboyscout/**), and manages every discovered project that already carries a Renovate config — opening MRs for available upgrades. Run it from one pipeline schedule on one repo and a newly-created repo is picked up on the next nightly run with zero manual wiring.

renovate-group is a sibling of renovate-self, not a replacement:

renovate-self renovate-group
Scope the repos you name (repositories) the repos it finds (autodiscover_filter)
Schedules one per repo one, for the whole group
New repo needs its own schedule added discovered automatically
Best for a single repo, or an external consumer Renovating just itself the group-wide bot

Designed for a daily/weekly GitLab pipeline schedule that sets RENOVATE_TASK=scan (anything else is skipped, so one schedule can drive multiple tasks if a consumer ever needs that).

Pair each managed repo with the bundled Renovate preset at the cicd repo root — in its renovate.json / renovate.json5:

{ "extends": ["gitlab>phpboyscout/cicd"] }

That preset ships a custom manager that tracks the gitlab.com/phpboyscout/cicd/<component>@vX.Y.Z pins in each repo's .gitlab-ci.yml — so this one job keeps every component pin across the whole group current.

Image version floor

image_version must be ≥ 39: the bundled preset's custom managers use managerFilePatterns (introduced in Renovate 39, replacing fileMatch), which older images reject with a config error that halts MR creation.

Config-gated discovery

A group filter sees every project the token can reach — including ones with no Renovate config (a landing site, a repo with no CI). This component sets RENOVATE_ONBOARDING=false and requireConfig: "required", so a discovered repo without a Renovate config is skipped silently — no "Configure Renovate" onboarding MR. Only already-onboarded repos (those carrying a renovate.json that extends the preset) are managed.

This is trigger-and-discovery only. It does not change per-repo Renovate policy — cadence, automerge, minimumReleaseAge, the first-party soak exemption. Those live in each repo's renovate.json plus the shared gitlab>phpboyscout/cicd preset and behave exactly as they would under a self run. Per-repo PR limits (prHourlyLimit, prConcurrentLimit) likewise stay per-repo, so a first run over a drifted group opens a bounded burst of MRs per project rather than one unbounded flood.

Token scope

On GitLab Free, project/group access tokens are Premium-only — use a fine-grained personal access token with group-wide api + write_repository scope, in $RENOVATE_TOKEN. Unlike renovate-self, the token must reach every project the filter discovers: autodiscover branches and opens MRs across all of them, so a token scoped to a single project silently under-covers the group.

The token is aliased internally to a non-colliding variable name before being handed to Renovate via --token. A job variable RENOVATE_TOKEN: "$RENOVATE_TOKEN" (same name on both sides) collides with a group variable of that name and resolves to a broken value, authenticating with junk — see Explanation: renovate automation.

Jobs

Job What it runs
renovate-group renovate --token="$RENOVATE_TOKEN_RUNTIME", with RENOVATE_PLATFORM=gitlab, RENOVATE_AUTODISCOVER=true, RENOVATE_AUTODISCOVER_FILTER=$[[ inputs.autodiscover_filter ]], RENOVATE_ONBOARDING=false, RENOVATE_REQUIRE_CONFIG=required.

Inputs

Input Type Default Description
image_version string "43" renovate/renovate image tag. Must be ≥ 39 (see note above).
stage string renovate GitLab CI stage. Consumers must declare it in stages:.
timeout string "2 hours" Job timeout for the whole-group scan. The run is sequential, so time scales with group size; the default lifts the ceiling above GitLab's 60-minute project default so a growing group is not cut off mid-scan. See run headroom.
autodiscover_filter string (required) Group glob(s) to autodiscover, e.g. phpboyscout/** or phpboyscout/go/**; comma-separate for multiple. Required, no default — a group bot must state its scope.
if string '($CI_PIPELINE_SOURCE == "schedule" && $RENOVATE_TASK == "scan") \|\| $RENOVATE_TARGET_FILTER' Gating rules:if:. Fires on the nightly schedule, or on any pipeline where $RENOVATE_TARGET_FILTER is set — see targeted runs.
token string "$RENOVATE_TOKEN" Token Renovate uses to discover, clone, branch, and open MRs. Needs group-wide api + write_repository.
log_level string info Renovate log level — debug when triaging.
log_file string renovate-run.log Path Renovate also writes the run to, kept as a job artifact (when: always, 1 week). GitLab stops collecting a job trace at 4 MB and this job has passed it, losing the end of a failing run — see reading a failed run. Empty string writes no file.
log_file_level string info Level for log_file. Renovate's own default is debug; this defaults to info because the artifact uploads on every run. Raise to debug for a triage run.
terraform_docs_version string "" Install this terraform-docs version into the Renovate image before the run (e.g. 0.24.0, no v). Empty = not installed. A group run spans the tofu repos, so set it whenever any discovered repo declares the terraform-docs hook. See terraform-docs regeneration.
allowed_commands string '["^terraform-docs --output-mode=inject --output-file=README\\.md markdown table [\\w./-]+$"]' JSON array of anchored regexes for RENOVATE_ALLOWED_COMMANDS — the commands postUpgradeTasks may run. [] allows nothing. See the renovate-self security warning.

Usage

The group bot, dogfooded in the cicd repo (whose phpboyscout/** filter includes cicd itself, so it keeps Renovating its own image pins as a subset of the group run):

include:
  - component: gitlab.com/phpboyscout/cicd/[email protected]
    inputs:
      autodiscover_filter: "phpboyscout/**"

Driven by a single renovate-daily pipeline schedule (RENOVATE_TASK=scan).

Targeted / canary runs

The nightly schedule manages the whole autodiscover_filter scope. To run Renovate against only a subset — e.g. to test a preset-migration canary without touching the rest of the group — trigger a one-off pipeline with RENOVATE_TARGET_FILTER set to the repos you want:

RENOVATE_TARGET_FILTER = phpboyscout/go/config-json,phpboyscout/go/output

Set it as a variable when running a pipeline (the Run pipeline button, the pipelines API, or a schedule play). When present, it satisfies the default gate (so the run does not need $RENOVATE_TASK=scan) and overrides the autodiscover_filter scope for that run only — the scheduled bot is unaffected. It accepts the same glob/comma-separated syntax as autodiscover_filter.

Don't delete a throwaway schedule before the canary job runs

If you inject RENOVATE_TARGET_FILTER through a throwaway pipeline schedule, do not delete that schedule until the canary job has actually run. GitLab evaluates rules:if: at pipeline creation but resolves a schedule's variables lazily at job-execution time — so deleting the schedule while the pipeline is still queued (e.g. behind a busy runner) strips RENOVATE_TARGET_FILTER from the job. The if: gate already matched, so the job still runs, but with the variable gone it silently falls back to the full autodiscover_filter scope — a targeted run quietly becomes a whole-group run.

The schedule play uses source == "schedule", which is what keeps renovate-group the only job on the pipeline (an API/Run pipeline trigger is source == "api"/"web", which on the cicd repo also fires the release + docs-deploy jobs). To get that isolation without the footgun, keep a permanent, inactive canary schedule (far-future cron) carrying the variable — edit and play it when needed, and never delete it.

Run headroom

The whole group is scanned in one sequential job, so total run time grows with the group. GitLab's default project job timeout is 60 minutes; a first-pass run over ~70 repos can approach that. If a run is ever cut off at the timeout, it does not drop a random repo — Renovate processes autodiscovered repos in a deterministic order, so the same tail of the group is dropped every run, silently.

timeout (default "2 hours") lifts the job's ceiling above the 60-minute project default so the scan has room to grow. This only works if the runner sets no lower maximum_timeout — a runner cap re-caps the run regardless of this input. The durable follow-on (keeping the run fast, not merely un-capped) is persisting Renovate's repositoryCache between runs; see the run-headroom spec (D5).

Reading a failed run

A cut-off run and a failed run are different problems. Run headroom above covers the first. This covers the second.

GitLab stops collecting a job trace at 4 MB:

Job's log exceeded limit of 4194304 bytes.
Job execution will continue but no more output will be collected.

A whole-group scan has exceeded that — on 2026-08-13 by 122 bytes. Because the overflow happens at the end, the part that is lost is the part that says why the job failed. That run had already logged Repository finished for all 110 repos, so nothing was skipped; Renovate simply exited non-zero for a reason nobody could read.

Most of the budget goes on transient upstream failures: 32 getChangeLogJSON error records, each serialising a full HTTP response and stack trace, all from GitHub returning 502/504 while fetching release notes for a large monorepo. They are honest reports and are deliberately not suppressed — losing release notes from every dependency MR would be a worse trade.

Instead the run is also written to log_file, kept as an artifact on every run (when: always, expiring after a week). An artifact is not subject to the trace cap, and Renovate's file stream writes synchronously, so the tail survives the process exit that ends a failing run. When a nightly scan goes red, download the artifact rather than reading the truncated trace.

For a deeper run, re-run with log_file_level: debug. See the log-cap spec.

See also