added permanent artifact links for latest green builds: /branches/<branch-key>/... serves the latest green build's artifacts (green-only, resolved per request), keepLatestGreen retention protection, permanent artifact-index page, and latestGreenUrl links in the branches view

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Michael Hoennig
2026-07-08 15:35:16 +02:00
co-authored by Claude Fable 5
parent 83e70e73c3
commit bb06c8b731
25 changed files with 820 additions and 18 deletions
@@ -8,6 +8,7 @@ import de.hoennig.gittally.build.BuildStatus
import de.hoennig.gittally.build.FileBuildResultRepository
import de.hoennig.gittally.build.GitWorktreeWorkspaces
import de.hoennig.gittally.build.RunningBuild
import de.hoennig.gittally.config.ArtifactsConfig
import de.hoennig.gittally.config.AutoBuildConfig
import de.hoennig.gittally.config.BranchConfig
import de.hoennig.gittally.config.ConfigLoader
@@ -379,6 +380,28 @@ class WatcherTest : FunSpec() {
verify { harness.gitService.worktreePrune(any()) }
}
test("poll keeps the latest green build beyond retention unless keepLatestGreen is disabled") {
val keeping = Harness(GitTallyConfig(artifacts = ArtifactsConfig(retentionPerBranch = 1)))
keeping.seed("main", BuildStatus.SUCCESS, commit = "commit-1")
keeping.seed("main", BuildStatus.FAILED, commit = "commit-2")
every { keeping.gitService.originBranches(any()) } returns listOf("main")
keeping.watcher.poll(keeping.workingDir)
keeping.repository.history().map { it.status } shouldContainExactly
listOf(BuildStatus.FAILED, BuildStatus.SUCCESS)
val dropping =
Harness(GitTallyConfig(artifacts = ArtifactsConfig(retentionPerBranch = 1, keepLatestGreen = false)))
dropping.seed("main", BuildStatus.SUCCESS, commit = "commit-1")
dropping.seed("main", BuildStatus.FAILED, commit = "commit-2")
every { dropping.gitService.originBranches(any()) } returns listOf("main")
dropping.watcher.poll(dropping.workingDir)
dropping.repository.history().map { it.status } shouldContainExactly listOf(BuildStatus.FAILED)
}
test("worktrees of queued or running builds are never pruned") {
val harness = Harness()
harness.seed("busy", BuildStatus.RUNNING, commit = "commit-1")