> **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. ## The Problem Every row of the build tables carries a ×, and on a running row it read as "cancel". It meant "Delete stored build": the result was removed, and the build ran on. Nothing showed it any more, but it still held its branch, so a deploy queued behind a mutation build waited for hours. The cancel endpoint looked the build up in the stored results, so with the row gone it could not be stopped either. When the build finished, the executor found no result to update and recorded a new one, so the deleted build turned up again. This happened twice on werkator.javagil.de. ## The Scenarios ### Feature: A queued or running build is cancelled, never deleted #### Scenario#95.01: Deleting a queued or running build is refused So that no build runs on without a row to show and stop it. - **Given** a build that is queued or running - **When** its result is deleted through the API - **Then** the answer is 409, naming the build and saying to cancel it first - **And** the result and its artifacts stay ##### Verified by - [BuildsApiControllerRestTest](../../src/test/kotlin/de/hoennig/werkator/server/BuildsApiControllerRestTest.kt) — Scenario#95.01 #### Scenario#95.02: A build whose result is gone can still be cancelled So that a build orphaned by an earlier version can be stopped without a restart. - **Given** a running build whose stored result was deleted - **When** it is cancelled through the route of its repository - **Then** the executor cancels it - **And** the route of another repository still does not reach it ##### Verified by - [BuildsApiControllerRestTest](../../src/test/kotlin/de/hoennig/werkator/server/BuildsApiControllerRestTest.kt) — Scenario#95.02 - [BuildExecutorIntegrationTest](../../src/test/kotlin/de/hoennig/werkator/build/BuildExecutorIntegrationTest.kt) — Scenario#95.02 #### Scenario#95.03: A queued or running row offers Cancel So that the × does what it looks like it does. - **Given** a history with a pending, a running and a finished build - **When** the page is rendered - **Then** the pending and the running row carry a cancel button, the finished row the delete button ##### Verified by - [UiControllerRestTest](../../src/test/kotlin/de/hoennig/werkator/server/UiControllerRestTest.kt) — Scenario#95.03 ## The Solution - `BuildExecutor.isActive(repo, artifactKey)` says whether a build is queued or executing in that repository. It asks the executor, not the stored results, because a result can be gone while its build runs. - `cancel` uses it in place of the lookup in the history; that also keeps a route from reaching another repository's build. - `DELETE /api/builds/` answers 409 for an active build. - `builds.html` and `werkator.js` render the × of a pending or running row as "Cancel build", like the card on the current-builds page. ## Additional Changes - Scenario#65.04 waits for the draining flag: it is set after the result is stored, and a slow CI read it too early. - Version 1.30.1 with its release note. ## Follow-up PRs - A queued build that is cancelled stays PENDING until its branch's worker reaches it, which can be hours behind a long build. It could be recorded as CANCELLED at once.