Skip to content

renovate-merge

A schedule-driven merge-sweep. One job enumerates a group's open merge requests, keeps the ones that are Renovate's, non-draft, and mergeable, and merges each with its head sha. Run it from one pipeline schedule on one repo and it drains the whole group — new repos need no wiring.

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

renovate-group renovate-merge
Does runs Renovate to open MRs merges the green ones
Schedule var RENOVATE_TASK=scan RENOVATE_TASK=merge
Cadence daily/weekly frequent (e.g. hourly)

Why it exists

Every phpboyscout project uses GitLab's fast-forward (ff) merge method for linear, merge-commit-free history. GitLab's merge API requires a sha to perform an FF merge, and Renovate's automerge call does not send one — so every Renovate automerge returns 400 {"message":"SHA must be provided when merging"} and the MR sits open indefinitely (a known upstream limitation, renovatebot/renovate #26972). After a cicd release that means one green phpboyscout/cicd pin-bump MR per repo that never merges, piling up until a manual sweep.

renovate-merge does the merge Renovate can't: it re-fetches each candidate's head sha and PUT …/merges with it — the call that succeeds under FF. It is belt-and-braces behind Renovate's own (FF-broken) automerge, not a replacement for it; the preset still correctly marks these MRs automerge: true. See the design spec.

What it merges

For every open MR in the group, an MR is merged only if all hold:

  • its source branch starts with branch_prefix (default renovate/) — the hard guard that keeps the sweep inside Renovate's namespace, so it can never merge a human's MR;
  • it is not a draft — Renovate drafts every major, so majors (and anything Renovate is holding) are excluded automatically;
  • its detailed_merge_status is mergeable — green, up to date, no conflicts.

A red, behind-base, or conflicted MR is left alone. The sweep never rebases — that is Renovate's job; a behind-base MR is rebased by Renovate on its next scan and merged by a later sweep. Per-MR merge failures (a repo that just went red, a moved head) are logged and skipped, never fatal. Only an enumeration/auth failure exits non-zero.

Token scope

Uses $RENOVATE_TOKEN by default — the same group-wide token renovate-group uses, which must have api scope and merge permission on every project swept. On GitLab Free use a fine-grained personal access token. The token is aliased internally to a non-colliding variable name (SWEEP_TOKEN) so the default never self-references — see Explanation: renovate automation.

Jobs

Job What it runs
renovate-merge A stdlib-only python3 sweep on the ci-base image: GET /groups/<group>/merge_requests?state=opened (paginated) → filter → GET each candidate for its head sha → PUT …/merge with sha=<head_sha>.

Inputs

Input Type Default Description
image_version string "v0.1.1" phpboyscout/images/ci-base tag. The sweep is a stdlib-only python3 script, so ci-base is all it needs.
stage string renovate GitLab CI stage. Consumers must declare it in stages:.
group string (required) Group path to sweep, e.g. phpboyscout (subgroups included). No default — a sweep bot must state its scope. The token needs merge rights on every project under it.
branch_prefix string "renovate/" Only MRs whose source branch starts with this are eligible. The safety guard keeping the sweep inside Renovate's namespace.
exclude string "" Comma-separated substrings of a project's full path to skip (e.g. phpboyscout/krites). Empty = sweep everything eligible. For holding a repo out of the sweep.
dry_run boolean false List the MRs that would be merged (with head sha) and merge nothing. Use for the first validation and for previews.
token string "$RENOVATE_TOKEN" Token used to enumerate and merge. Needs group-wide api + merge permission. Aliased internally to avoid self-reference.
if string '$CI_PIPELINE_SOURCE == "schedule" && $RENOVATE_TASK == "merge"' Gating rules:if:. Fires on a schedule with $RENOVATE_TASK=merge, so a merge schedule coexists with the renovate-group scan schedule.

Usage

The merge-sweep bot, dogfooded in the cicd repo (whose phpboyscout scope includes cicd itself):

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

Driven by a separate, frequent renovate-merge pipeline schedule that sets RENOVATE_TASK=merge — distinct from the renovate-group scan schedule so the two never collide on one repo.

Preview before arming the schedule

Run one pipeline with dry_run: true (or a one-off with the input overridden) first — it lists the green renovate/* candidates and merges nothing, so you can confirm the scope and token before the hourly schedule starts merging for real.