Let auto-build slots run their own build command under their own name

A branches.<name>.autoBuild.times entry is now either a plain HH:MM
string or an object with time, its own buildCommand, and a name, so a
nightly slot can run a fuller check than the on-commit builds. The
watcher passes the slot's command and name to the executor, persisted in
the build result — UI restarts, gittally retry, and the startup recovery
repeat a build with the command and name it originally ran under.

A named slot (e.g. master@nightly) gets its own pool: repository
grouping, retention count, branches-view row (sorted after its branch),
latest status, and permanent latest-green artifact link are keyed by the
build name, while origin lookups, gone-branch pruning, worktrees, and
Gitea links/statuses stay keyed by the real branch. Without a name,
slot builds share the branch's pool as before.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
mhoennig
2026-08-28 19:11:35 +02:00
co-authored by Claude Fable 5
parent f292badac1
commit 8aee3190ea
35 changed files with 702 additions and 158 deletions
@@ -37,8 +37,10 @@ class ConsoleBuildRunner(
branch: String,
commit: String,
workingDir: Path = Paths.get("."),
buildCommandOverride: String? = null,
name: String = branch,
): BuildStatus {
val build = buildExecutor.startBuild(branch, commit, workingDir)
val build = buildExecutor.startBuild(branch, commit, workingDir, buildCommandOverride, name)
var printed = 0L
var result: BuildResult? = null
while (result?.status?.isTerminal != true) {
@@ -199,7 +199,12 @@ class InitCommand(
requirePullRequest: false
autoBuild:
enabled: false # whether to rebuild on schedule
times: ["01:00"] # UTC times HH:MM for scheduled builds
# UTC times HH:MM for scheduled builds; an entry may carry its own
# command and a name for a separate history/artifact pool:
# - time: "01:00"
# buildCommand: ./gradlew fullCheck
# name: main@nightly
times: ["01:00"]
docker:
enabled: false # run clean/build commands in a Docker container instead of natively
image: "" # image for the build container; required when enabled
@@ -34,7 +34,7 @@ class RetryCommand(
val failed: List<BuildResult>
try {
fetchBestEffort()
failed = repository.latestPerBranch().filter { it.status == BuildStatus.FAILED }
failed = repository.latestPerName().filter { it.status == BuildStatus.FAILED }
} catch (e: Exception) {
System.err.println("error: ${e.message}")
return ExitCode.USAGE
@@ -51,7 +51,8 @@ class RetryCommand(
continue
}
println("retrying branch ${result.branch} at commit ${commit.take(12)}")
val status = consoleBuildRunner.buildAndStream(result.branch, commit, workingDir)
// a failed auto-slot build retries with its recorded command, under its name
val status = consoleBuildRunner.buildAndStream(result.branch, commit, workingDir, result.buildCommandOverride, result.name)
if (status != BuildStatus.SUCCESS) {
anyFailed = true
}
@@ -26,7 +26,7 @@ class StatusCommand(
var history: Boolean = false
override fun call(): Int {
val results = if (history) repository.history() else repository.latestPerBranch()
val results = if (history) repository.history() else repository.latestPerName()
if (results.isEmpty()) {
println("(no builds recorded)")
} else {
@@ -40,7 +40,7 @@ class StatusCommand(
val rows =
results.map {
listOf(
it.branch,
it.name,
it.status.name.lowercase(),
it.commit.take(12),
UiFormats.timestamp(it.startedAt),