feat: run Renovate now for one repo or all (N) #122

Merged
deadstyle merged 20 commits from feature/120-run-renovate-now into develop 2026-10-10 09:31:58 -05:00
Owner

Summary

N starts a Renovate run from lazyforge: for the repo in context or for all repos. It works on the repo list, inside a repo, and in ★ Renovate. A small dialog offers this repo (default) or all repos; host-wide ★ rows confirm a run on all repos. The status bar says Renovate run started for <owner/name> (or for all repos), and a failure shows the forge's reason. N appears in hints and help only where it can work: the host has a configured renovate_workflow and the user has write access to that workflow's repo.

Changes

  • Forge: new optional capability WorkflowDispatcher with action ActDispatchWorkflow (needs write access), implemented for Forgejo/Gitea and GitHub (POST /repos/{o}/{r}/actions/workflows/{file}/dispatches), the Fake, and the shared contract suite. domain.Repo gains DefaultBranch, filled by both adapters' ListRepos, so the dispatch needs no extra request.
  • Config: per-host renovate_workflow = "owner/repo/file.yml", validated at load with the field path in the error.
  • Core: CanRunRenovate (no I/O, from the cached repo list) and RunRenovate.
  • UI: N binding and run dialog, status messages, the workflow field on the host add/edit Renovate step (so editing a host keeps it), and App wiring.
  • Docs: docs/design.md keymap row, onboarding step and Renovate bullet; docs/architecture.md interface, API mapping and config; README.

Decisions

  • Decided: optional-capability interface per ADR 0006, so no new ADR.
  • Decided: dispatch ref is the workflow repo's default branch.
  • Decided: a run for all repos sends no inputs; a run for one repo sends {"repo": "owner/name"}. This keeps today's bare workflow_dispatch working, and GitHub rejects undeclared inputs.
  • Decided: N is hidden until the repo list loads, when the workflow repo is missing from it (matched case-insensitively), when its default branch is empty, or at read-only access.
  • Decided: renovate_workflow has exactly three /-separated parts with no whitespace; load and onboarding both reject anything else.
  • Decided: no in-flight guard; each confirm sends one dispatch.
  • Assumed: "Settings shows it beside renovate_user" means the Renovate step of the host add/edit flow, the only place renovate_user is shown or edited.

Test plan

  • make check exits 0 at the head commit (fmt, lint, go test -race, vuln, build, install-test, Windows vet).
  • Forge: exact request path and body per adapter, no inputs key when empty, 404 → ErrNotFound, 422 message passes through, Can cases, Fake semantics, contract cases.
  • Config: SplitWorkflow table (including whitespace) and the load error path.
  • Core: gating (unconfigured, unloaded, absent, read-only, empty default branch, no capability) and dispatch (one repo, all repos, forge failure wrapped).
  • UI: N enabled/disabled at every level, dialog keys, host-wide vs repo rows, failure reason in the status bar, App wiring, onboarding prefill/clear/tab/validation.

Follow-ups

  • The runner workflow in deadstyle/forgejo (.forgejo/workflows/renovate.yml) still needs an optional workflow_dispatch input repo that limits the run (RENOVATE_AUTODISCOVER_FILTER). Until then, "this repo" runs aren't limited to one repo: the runner either ignores the undeclared input and runs everything, or the forge rejects the dispatch. Separate MR in that repo.
  • After merge, set renovate_workflow = "deadstyle/forgejo/renovate.yml" on the host.

Refs #120

🤖 Generated with Claude Code

https://claude.ai/code/session_01KAW1xJdQBS2JvDpPykgRv1

## Summary `N` starts a Renovate run from lazyforge: for the repo in context or for all repos. It works on the repo list, inside a repo, and in ★ Renovate. A small dialog offers **this repo** (default) or **all repos**; host-wide ★ rows confirm a run on all repos. The status bar says `Renovate run started for <owner/name>` (or `for all repos`), and a failure shows the forge's reason. `N` appears in hints and help only where it can work: the host has a configured `renovate_workflow` and the user has write access to that workflow's repo. ## Changes - **Forge:** new optional capability `WorkflowDispatcher` with action `ActDispatchWorkflow` (needs write access), implemented for Forgejo/Gitea and GitHub (`POST /repos/{o}/{r}/actions/workflows/{file}/dispatches`), the `Fake`, and the shared contract suite. `domain.Repo` gains `DefaultBranch`, filled by both adapters' `ListRepos`, so the dispatch needs no extra request. - **Config:** per-host `renovate_workflow = "owner/repo/file.yml"`, validated at load with the field path in the error. - **Core:** `CanRunRenovate` (no I/O, from the cached repo list) and `RunRenovate`. - **UI:** `N` binding and run dialog, status messages, the workflow field on the host add/edit Renovate step (so editing a host keeps it), and App wiring. - **Docs:** `docs/design.md` keymap row, onboarding step and Renovate bullet; `docs/architecture.md` interface, API mapping and config; README. ## Decisions - Decided: optional-capability interface per ADR 0006, so no new ADR. - Decided: dispatch `ref` is the workflow repo's default branch. - Decided: a run for all repos sends no `inputs`; a run for one repo sends `{"repo": "owner/name"}`. This keeps today's bare `workflow_dispatch` working, and GitHub rejects undeclared inputs. - Decided: `N` is hidden until the repo list loads, when the workflow repo is missing from it (matched case-insensitively), when its default branch is empty, or at read-only access. - Decided: `renovate_workflow` has exactly three `/`-separated parts with no whitespace; load and onboarding both reject anything else. - Decided: no in-flight guard; each confirm sends one dispatch. - Assumed: "Settings shows it beside renovate_user" means the Renovate step of the host add/edit flow, the only place `renovate_user` is shown or edited. ## Test plan - `make check` exits 0 at the head commit (fmt, lint, `go test -race`, vuln, build, install-test, Windows vet). - Forge: exact request path and body per adapter, no `inputs` key when empty, 404 → `ErrNotFound`, 422 message passes through, `Can` cases, `Fake` semantics, contract cases. - Config: `SplitWorkflow` table (including whitespace) and the load error path. - Core: gating (unconfigured, unloaded, absent, read-only, empty default branch, no capability) and dispatch (one repo, all repos, forge failure wrapped). - UI: `N` enabled/disabled at every level, dialog keys, host-wide vs repo rows, failure reason in the status bar, App wiring, onboarding prefill/clear/tab/validation. ## Follow-ups - The runner workflow in `deadstyle/forgejo` (`.forgejo/workflows/renovate.yml`) still needs an optional `workflow_dispatch` input `repo` that limits the run (`RENOVATE_AUTODISCOVER_FILTER`). Until then, "this repo" runs aren't limited to one repo: the runner either ignores the undeclared input and runs everything, or the forge rejects the dispatch. Separate MR in that repo. - After merge, set `renovate_workflow = "deadstyle/forgejo/renovate.yml"` on the host. Refs #120 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01KAW1xJdQBS2JvDpPykgRv1
Adds the WorkflowDispatcher capability and ActDispatchWorkflow. The action needs write access and is hidden when the adapter lacks the capability. Gitea and GitHub adapters POST to the workflow dispatches endpoint. Repo gains DefaultBranch so the Run Renovate dialog can default its ref.

Refs #120

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KAW1xJdQBS2JvDpPykgRv1
Each host can name the workflow that runs Renovate, as owner/repo/file.
Validate rejects a malformed value at load with its field path, so a typo
cannot silently hide N.

Refs #120

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KAW1xJdQBS2JvDpPykgRv1
CanRunRenovate gates the run without I/O: the host has a workflow, the forge
can dispatch it, and the cached repo list holds its repo with write access and
a default branch. RunRenovate dispatches on that default branch, sending
repo=owner/name for one repo and no inputs for all.

Refs #120

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KAW1xJdQBS2JvDpPykgRv1
N opens a dialog that runs the host's renovate_workflow for the repo in context or for all repos. The key is enabled only when the workflow's repo is cached with write access and a default branch. The status bar reports the start, or the forge's reason when the dispatch fails.

Onboarding gets an optional workflow field (owner/repo/file) after the Renovate username. Blank hides N.

Refs #120

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KAW1xJdQBS2JvDpPykgRv1
design.md gets the N keymap row, the optional onboarding workflow field and a Renovate features bullet. architecture.md gets DefaultBranch on Repo, the WorkflowDispatcher interface, the Dispatch workflow API row (unverified on every forge), renovate_workflow in the config example and the CanRunRenovate/RunRenovate note. README lists the workflow field in onboarding.

Refs #120

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KAW1xJdQBS2JvDpPykgRv1
Refs #120

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KAW1xJdQBS2JvDpPykgRv1
Refs #120

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KAW1xJdQBS2JvDpPykgRv1
Refs #120

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KAW1xJdQBS2JvDpPykgRv1
Refs #120

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KAW1xJdQBS2JvDpPykgRv1
Refs #120

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KAW1xJdQBS2JvDpPykgRv1
Refs #120

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KAW1xJdQBS2JvDpPykgRv1
Refs #120

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KAW1xJdQBS2JvDpPykgRv1
Refs #120

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KAW1xJdQBS2JvDpPykgRv1
Refs #120

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KAW1xJdQBS2JvDpPykgRv1
Refs #120

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KAW1xJdQBS2JvDpPykgRv1
Refs #120

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KAW1xJdQBS2JvDpPykgRv1
Refs #120

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KAW1xJdQBS2JvDpPykgRv1
docs: cut restating comments on the Renovate run code
All checks were successful
ci / check (pull_request) Successful in 1m23s
8421ba22f5
Refs #120

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KAW1xJdQBS2JvDpPykgRv1
deadstyle merged commit d19de86760 into develop 2026-10-10 09:31:58 -05:00
deadstyle deleted branch feature/120-run-renovate-now 2026-10-10 09:31:58 -05:00
Sign in to join this conversation.
No description provided.