Build definitions with onPush/atTimes replace branch-owned schedules

ADR 0007: the YAML builds section (next to the reserved maxConcurrent
key) defines named builds (jobs) with onPush/atTimes triggers, branch
selectors (name globs, activeWithin age filter), and build-setting
overrides applied last over the merged branch config. The implicit
default build (onPush over all branches) preserves the previous
behavior; the section is pinned against the worktree layer.

Results record the job name; restart, retry, and startup recovery
re-run by it, resolving settings from the current config. A non-default
build records under the <branch>@<build> pool with its own row,
retention count, and permanent latest-green link.

branches.*.autoBuild stays as a deprecated alias (plain times only);
the unreleased-in-practice v0.9.13 per-slot buildCommand/name syntax is
removed again.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
mhoennig
2026-08-28 20:06:02 +02:00
co-authored by Claude Fable 5
parent 5051c7bb99
commit 0e8db18e69
23 changed files with 595 additions and 405 deletions
@@ -5,6 +5,7 @@ import de.hoennig.gittally.build.BuildExecutor
import de.hoennig.gittally.build.BuildResult
import de.hoennig.gittally.build.BuildResultRepository
import de.hoennig.gittally.build.BuildStatus
import de.hoennig.gittally.config.BuildDefinition
import de.hoennig.gittally.git.GitService
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
@@ -103,13 +104,12 @@ class BuildsApiController(
latest?.commit
?: gitService.originHeadCommit(branch, workingDir)
?: return notFound("branch '$branch' has no recorded build and no origin counterpart")
// a restarted build repeats what it originally ran: same branch, name, and command
// a restarted build re-runs its recorded build definition (settings from the current config)
val running =
buildExecutor.startBuild(
branch = latest?.branch ?: branch,
commit = commit,
buildCommandOverride = latest?.buildCommandOverride,
name = latest?.name ?: branch,
build = latest?.build ?: BuildDefinition.DEFAULT,
)
return ResponseEntity.accepted().body(
BuildResultDto(