Spike: Renovate PR body formats, including batched PRs #2
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
The ★ Renovate view and the per-package display on PR rows ("postgres 16.4 → 17.0", bump type) depend on extracting package, from, to and update type from Renovate PRs. Renovate only exposes this inside the PR body's markdown, and our shared preset batches non-major updates into one PR per ecosystem ("Go non-major", "Docker images non-major"), so one PR can carry many packages.
Plan
Time-boxed investigation (half a day):
internal/core/testdata/renovate/.Plan-review additions (#17)
Deliverable
Fixtures committed, plus a comment here with the format notes and the recommended approach, decided by Opus via
engineering-decision(ADR if it ends up shaping the domain model, e.g.RenovateUpdatebecoming a list).Context
docs/design.md→ "Renovate features" and the ★ Renovate boxes.docs/architecture.md→RenovateUpdatein the domain model sketch is a single struct; batched PRs mean it likely needs to be a slice.deadstyle/forgejo→renovate/default.json(batches non-majors weekly, separates majors and breaking updates).Out of scope
Grouping logic and UI.
🤖 Spike result. Fixtures on
spike/2-renovate-bodies(a327569,83f13dc) ininternal/core/testdata/renovate/, with format notes in its README. MR to follow once SSH on :2222 is back.What exists: the bot is
renovate-bot(Renovate 44.115.13), with 17 PRs (all closed) and 13 dashboards. The fixtures cover docker-compose majors, github-actions majors, a one-member non-major group, and one PR with two rows from two managers. No PR exists yet for gomod, terraform, npm, custom.regex, digest/pin, or a batched multi-package group. The only evidence of batching is a pending dashboard entry in traefik.Format:
This PR contains the following updates:. There are two header shapes:Package | Update | Change, andPackage | Type | Update | Change, whereTypeis the dependency type (action,uses-with,final), not the manager.[name](homepage), optionally followed by([source](url)). The homepage isn't an identity, because two images both link forgejo.org.from` → `towith raw tags.<!--renovate-debug:…-->decodes to versions, target branch and configured labels only. It has no package data.renovate/<group-slug>vsrenovate/<slug>-N.x) reveals that the PR is a group.head.refbecomesrefs/pull/N/head, and the branch survives only inhead.label.Decided (Opus): parsing. Take the first table after the intro line, map cells by header name, and stop at the first non-table line. Reject the whole body on a missing intro, a column-count mismatch, an unknown column, or a change cell that isn't
x → y. A rejected PR shows with its plain title, outside grouping. A throwaway parser handled all 8 PR fixtures and rejected all 3 dashboards.Decided (Opus): shape for #4. Each PR gets a list of updates, one per table row: ecosystem, package, dep type, update type, from, to, and source URL. Ecosystem is inferred from the Type column or the title noun. If it's unknown, the row stays out of automatic grouping (the two
noderows in forgejo#9 show why the name alone is ambiguous). This lands in #4's ADR.Gap: there are no batched or digest fixtures. #10 should add hand-written fixtures from Renovate's documented format before relying on those paths, and the reject-on-doubt rule covers them until then.
Product question raised: should
actions/checkoutv3→v7 in one repo and v4→v7 in another be one row in Updates by dependency? Added as item 13 on #13.