implemented 05-artifact-store.md: filesystem artifact store with legacy-compatible naming, atomic persist from concurrent builds, retention pruning, and artifacts.rootDir config
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
b379bc0a6b
commit
3c9eeda5da
@@ -1,5 +1,6 @@
|
||||
package de.hoennig.gittally.build
|
||||
|
||||
import java.nio.file.Path
|
||||
import java.security.MessageDigest
|
||||
import java.time.Instant
|
||||
|
||||
@@ -16,6 +17,9 @@ object ArtifactKeys {
|
||||
startedAt: Instant,
|
||||
): String = "${branchKey(branch)}-${sanitize(startedAt.toString())}-${sha256Prefix("$branch\t$startedAt")}"
|
||||
|
||||
/** Legacy `repository_key`: the sanitized absolute repository path. */
|
||||
fun repoKey(repoDir: Path): String = sanitize(repoDir.toAbsolutePath().normalize().toString())
|
||||
|
||||
private fun sanitize(value: String): String = value.replace(Regex("[^A-Za-z0-9._-]"), "_")
|
||||
|
||||
private fun sha256Prefix(value: String): String =
|
||||
|
||||
@@ -1,29 +1,31 @@
|
||||
package de.hoennig.gittally.build
|
||||
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.stereotype.Component
|
||||
import java.nio.file.Path
|
||||
|
||||
/**
|
||||
* Takes over the staging directory of a finished build.
|
||||
* The real store (naming, retention, serving) arrives in step 05.
|
||||
* Persists the artifacts of finished builds (logs plus configured report directories)
|
||||
* and prunes them together with the result retention.
|
||||
* Implemented by `de.hoennig.gittally.artifacts.FileArtifactStore`.
|
||||
*/
|
||||
interface ArtifactStore {
|
||||
/**
|
||||
* Takes over the staging directory of the finished [build] (log files) plus the
|
||||
* configured `artifactDirs` from [workspace] and stores them under the build's
|
||||
* artifact key. [workspace] is null when the build crashed before its workspace
|
||||
* was prepared; only the logs are stored then.
|
||||
*/
|
||||
fun persist(
|
||||
build: BuildResult,
|
||||
stagingDir: Path,
|
||||
workspace: Path?,
|
||||
)
|
||||
}
|
||||
|
||||
/** Placeholder until step 05: logs and leaves the staging directory untouched. */
|
||||
@Component
|
||||
class NoOpArtifactStore : ArtifactStore {
|
||||
private val log = LoggerFactory.getLogger(NoOpArtifactStore::class.java)
|
||||
/**
|
||||
* Deletes all stored artifact directories whose keys are not in [keptResults];
|
||||
* call after repository retention pruning. Returns the removed artifact keys.
|
||||
*/
|
||||
fun prune(keptResults: Collection<BuildResult>): List<String>
|
||||
|
||||
override fun persist(
|
||||
build: BuildResult,
|
||||
stagingDir: Path,
|
||||
) {
|
||||
log.info("artifact store not implemented yet; leaving build output of {} in {}", build.artifactKey, stagingDir)
|
||||
}
|
||||
/** The stored artifact directory for [artifactKey], or null if none exists. */
|
||||
fun artifactDir(artifactKey: String): Path?
|
||||
}
|
||||
|
||||
@@ -111,6 +111,7 @@ class BuildExecutor(
|
||||
private fun execute(build: ActiveBuild) {
|
||||
var slot: Semaphore? = null
|
||||
var finalStatus = BuildStatus.FAILED
|
||||
var workspace: Path? = null
|
||||
try {
|
||||
slot = slotsFor(build.workingDir)
|
||||
slot.acquire()
|
||||
@@ -120,13 +121,14 @@ class BuildExecutor(
|
||||
}
|
||||
build.running = true
|
||||
transition(build, BuildStatus.RUNNING, duration = null)
|
||||
val workspace =
|
||||
val preparedWorkspace =
|
||||
workspaces.prepare(
|
||||
branch = build.runningBuild.branch,
|
||||
commit = build.runningBuild.commit,
|
||||
repoDir = build.workingDir,
|
||||
)
|
||||
val exitCode = runBuildCommands(build, workspace)
|
||||
workspace = preparedWorkspace
|
||||
val exitCode = runBuildCommands(build, preparedWorkspace)
|
||||
finalStatus =
|
||||
when {
|
||||
build.cancelled.get() -> BuildStatus.CANCELLED
|
||||
@@ -141,7 +143,7 @@ class BuildExecutor(
|
||||
val duration = Duration.between(build.runningBuild.startedAt, Instant.now())
|
||||
val result = transition(build, finalStatus, duration)
|
||||
try {
|
||||
artifactStore.persist(result, build.runningBuild.stagingDir)
|
||||
artifactStore.persist(result, build.runningBuild.stagingDir, workspace)
|
||||
} catch (e: Exception) {
|
||||
log.warn("could not persist artifacts of {}: {}", result.artifactKey, e.message)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user