Show the command a build actually runs on its artifact page

The artifact page read `branches.<branch>.buildCommand` from the primary
config only, so for a named build on a branch with its own config it showed
a command that build never ran — on vm4006 it showed the host config's
command for a build that ran the branch definition's `pitestFull`.

Resolving "what does this build run" now has one implementation,
`GitTallyConfig.buildSettings(branch, build)`: the branch entry with the
build definition's overrides applied last. The executor uses it, and the
page resolves it against the branch layer committed at the build's own
commit — the same inputs the executor had.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
mhoennig
2026-08-29 07:52:22 +02:00
co-authored by Claude Opus 5
parent 939d8eeb9c
commit 1a84b1fc1b
6 changed files with 81 additions and 12 deletions
@@ -474,12 +474,10 @@ class BuildExecutor(
runningBuild: RunningBuild,
workingDir: Path,
worktree: Path,
): BranchConfig {
val config = configLoader.loadForWorktree(workingDir, worktree)
val branchConfig = config.branches[runningBuild.branch] ?: config.branches["default"] ?: BranchConfig()
val definition = config.effectiveBuildDefinitions()[runningBuild.build] ?: return branchConfig
return definition.applyTo(branchConfig)
}
): BranchConfig =
configLoader
.loadForWorktree(workingDir, worktree)
.buildSettings(runningBuild.branch, runningBuild.build)
private class ActiveBuild(
val runningBuild: RunningBuild,
@@ -21,6 +21,22 @@ data class GitTallyConfig(
/** The configured [buildDefinitions] plus the implicit `default` build unless overridden. */
fun effectiveBuildDefinitions(): Map<String, BuildDefinition> =
mapOf(BuildDefinition.DEFAULT to BuildDefinition(onPush = true)) + buildDefinitions
/**
* The settings one build of [build] on [branch] runs with: the branch entry (falling
* back to `branches.default`) with the build definition's overrides applied last.
* A build name without a definition — a job removed from the config since the run —
* falls back to the plain branch settings.
* This must stay the single answer to "what does this build run", used by the
* executor and by everything that displays it.
*/
fun buildSettings(
branch: String,
build: String,
): BranchConfig {
val branchConfig = branches[branch] ?: branches["default"] ?: BranchConfig()
return effectiveBuildDefinitions()[build]?.applyTo(branchConfig) ?: branchConfig
}
}
data class ServerConfig(
@@ -6,7 +6,9 @@ import de.hoennig.gittally.build.BuildResult
import de.hoennig.gittally.build.BuildResultRepository
import de.hoennig.gittally.build.BuildStatus
import de.hoennig.gittally.config.ConfigLoader
import de.hoennig.gittally.git.GitService
import de.hoennig.gittally.metrics.SystemMetricsCollector
import de.hoennig.gittally.watcher.Watcher
import jakarta.servlet.http.HttpServletRequest
import org.springframework.beans.factory.ObjectProvider
import org.springframework.boot.info.BuildProperties
@@ -36,6 +38,7 @@ class UiController(
private val buildExecutor: BuildExecutor,
private val artifactStore: ArtifactStore,
private val configLoader: ConfigLoader,
private val gitService: GitService,
private val metricsCollector: SystemMetricsCollector,
private val branchListing: BranchListing,
private val branchPermalinks: BranchPermalinks,
@@ -189,7 +192,7 @@ class UiController(
model.addAttribute("filesBase", filesBase)
model.addAttribute("result", result?.let { BuildRowView.from(it, links) })
model.addAttribute("hasArtifacts", artifactDir != null)
model.addAttribute("buildCommand", result?.let { branchBuildCommand(it.branch) })
model.addAttribute("buildCommand", result?.let { buildCommandOf(it) })
model.addAttribute(
"logs",
artifactDir?.let { logFiles(it, scanForFailure = result != null && result.status != BuildStatus.SUCCESS) }
@@ -220,10 +223,24 @@ class UiController(
return links
}
/** The currently configured build command — the command actually used at build time is not persisted. */
private fun branchBuildCommand(branch: String): String {
val branches = configLoader.load(workingDir).branches
return (branches[branch] ?: branches["default"])?.buildCommand ?: ""
/**
* The command this build runs, resolved exactly like the executor resolves it: the
* branch layer committed at the build's own commit, plus the overrides of the build
* definition it belongs to. Reading only the primary config would show a command no
* build of this pool ever ran — the branch and its job usually override it.
* The command used by a past run is not persisted, so this is the current answer.
*/
private fun buildCommandOf(result: BuildResult): String {
val config =
try {
configLoader.loadWithBranchLayer(
workingDir,
gitService.showFileAtCommit(result.commit, Watcher.CONFIG_FILE, workingDir),
)
} catch (_: Exception) {
configLoader.load(workingDir)
}
return config.buildSettings(result.branch, result.build).buildCommand
}
/**
+1 -1
View File
@@ -39,7 +39,7 @@
<li>Started: <span th:text="${result.startedAt}">2026-07-07 12:00</span>
<th:block th:if="${result.duration != ''}">— Duration: <span th:text="${result.duration}">1:23</span></th:block>
</li>
<li th:if="${buildCommand != null}">Build command (as currently configured):<br>
<li th:if="${buildCommand != null}">Build command (as configured for this build):<br>
<code th:text="${buildCommand}">./gradlew test</code>
</li>
</ul>