Files
werkator/docs/prs/2026-10-10-PR#150-two-restarts.md
claude-code d95b7e6b20
werkator build succeeded after 04:20
werkator/deploy build succeeded after 00:08
werkator/mutation build failed after 38:45
Two restarts on every build row: same commit and newest commit (v1.41.0) (#150)
Co-authored-by: claude-code <claude-code@javagil.de>
2026-10-10 23:59:51 +02:00

7.5 KiB

WARNING: This document describes only the change applied in this PR. It may already be outdated once the next PR is merged. Historic PR-documentation is not maintained along with new PRs — treat it as a snapshot, not as current documentation.

Problem

A build row offered one restart, and what it built depended on the page. Latest rebuilt the recorded commit, Branches built the origin head, History and the artifact page offered none. Which commit a click built was therefore a matter of where the user stood, and easy to get wrong. The restart also took a build name only: a "same commit" from an older History row would have repeated the newest run of that name.

Non-Goals

  • A follow-up build never starts at the newest commit: without its predecessor's green run it would, e.g., deploy untested code.
  • A pull-request target build does not ask the forge for the newest head of its pull request; the watcher builds every new head.
  • The Current page keeps its cards without restarts; a running build is cancelled there, not restarted.

Specification

Feature: Two restarts on every build row

Scenario#150.01: Every view offers both restarts on every row

So that the button, not the page, says which commit is built.

  • Given a recorded build of main
  • When Latest, Branches or History is shown
  • Then its row has a button Build commit <abbrev> again and a button Build the newest commit of main
Verified by
  • UiBuildListsRestTest — Scenario#150.01
  • werkator.js (restartButtons) renders the same two buttons; checked in the browser against a demo instance

Scenario#150.02: The same commit builds the run of its row

So that an older History row repeats that run, not the newest run of its name.

  • Given two runs of main@pitest, an older one at commit older1 and a newer one
  • When the same commit of the older run is restarted
  • Then commit older1 is built with the pitest definition
Verified by

Scenario#150.03: A refused restart stays visible, disabled, with its reason

So that the user sees why a restart is not offered, and the columns stay aligned.

  • Given a run whose branch is gone, a follow-up run, a branch never built, and a viewer without the control token
  • When the rows are shown
  • Then the buttons that cannot run are disabled with Branch deleted from origin, Runs after a green default; restart that one, Never built or Needs the control token as title
Verified by

Scenario#150.04: The newest commit is refused for a follow-up, a pull-request target and a gone branch

So that no restart deploys a commit its predecessor has not passed, or hands the host's secrets to a stale pull request.

  • Given the follow-up main@deploy of default, a pull-request target run, and a run whose branch is gone
  • When the newest commit of each is requested
  • Then each is refused with its reason, and no build starts
Verified by

Scenario#150.05: The artifact page offers both restarts of its build

So that a build can be repeated from the page that shows why it failed.

  • Given the artifact page of a recorded build
  • When it is shown
  • Then it has a line Restart: with both buttons
Verified by

Scenario#150.06: A private repository hides the name in a follow-up's refusal

So that a refusal does not reveal a build-definition name, which is content (RFC 0003, D8).

  • Given the refusal Runs after a green secret-deploy; restart that one of a private repository
  • When the row is redacted
  • Then the refusal reads Runs after a green n/a; restart that one
Verified by

Scenario#150.07: The API refuses the same commit of a gone branch with the reason

So that a script gets the same answer the disabled button gives.

  • Given a run whose branch is gone from origin
  • When POST /api/builds/<artifactKey>/restart is sent for it
  • Then the answer is 409 with Branch deleted from origin in error, and no build starts
Verified by

Scenario#150.08: The same commit of a pull-request target re-runs its pull request

So that a target build is repeated with the pull request it judged, never with a branch build.

  • Given a recorded pull-request target run of pull request 7
  • When its same commit is restarted
  • Then pull request 7 is built again as a pull-request target
Verified by

Scenario#150.09: A follow-up of a branch refuses the newest commit

So that a follow-up never starts before its predecessor is green.

  • Given branch feature/x defines the follow-up report of default in its own .werkator.yml
  • When the newest commit of report on feature/x is asked for
  • Then it is refused
Verified by

Solution

  • BuildRestarts decides why a restart cannot run: sameCommitRefusal and newestCommitRefusal. RestartPolicy reads the follow-ups of each branch at its origin head, its own layer included, as the watcher does. It reads them once per branch and head commit, since the pages poll every few seconds; a branch gone from origin, or one whose configuration cannot be read, falls back to the primary configuration.
  • BuildResultDto and BranchDto carry both refusals; the rows, the template and werkator.js only show them.
  • POST /api/builds/<artifactKey>/restart builds a run again by its key. The existing POST /api/builds/restart?atOriginHead=true is the newest commit and now refuses with 409. A pull-request target used to re-run its recorded pull request even at origin head (Scenario#117.07); now it is refused there.
  • The fragment restartButtons renders the two buttons for the build tables and the artifact page. The page flags allowRestart and restartAtOriginHead are gone.
  • The newest commit gets an icon of its own, an arrow to a line; the actions column is wider for the third button.
  • BuildsApiController.restart stood at Mutation-CRAP 14.07; the start and the answer moved into start and accepted, which rebuild shares.

Additional Changes

  • docs/deployment.md names both forms of the restart and the 409 answer.
  • Version 1.41.0 with its release note.