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:
co-authored by
Claude Fable 5
parent
f292badac1
commit
8aee3190ea
@@ -0,0 +1,62 @@
|
||||
package de.hoennig.gittally.config
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator
|
||||
import com.fasterxml.jackson.core.JsonParser
|
||||
import com.fasterxml.jackson.databind.DeserializationContext
|
||||
import com.fasterxml.jackson.databind.JsonDeserializer
|
||||
import com.fasterxml.jackson.databind.JsonNode
|
||||
import com.fasterxml.jackson.databind.JsonSerializer
|
||||
import com.fasterxml.jackson.databind.SerializerProvider
|
||||
|
||||
/**
|
||||
* Accepts both YAML forms of an [AutoBuildSlot] entry: a plain `HH:MM` string, or an
|
||||
* object with `time` and optional `buildCommand` and `name`.
|
||||
*/
|
||||
class AutoBuildSlotDeserializer : JsonDeserializer<AutoBuildSlot>() {
|
||||
override fun deserialize(
|
||||
parser: JsonParser,
|
||||
context: DeserializationContext,
|
||||
): AutoBuildSlot {
|
||||
val node = parser.readValueAsTree<JsonNode>()
|
||||
if (node.isTextual) {
|
||||
return AutoBuildSlot(time = node.asText())
|
||||
}
|
||||
if (node.isObject) {
|
||||
val time =
|
||||
node.get("time")?.takeIf { it.isTextual }?.asText()
|
||||
?: throw context.instantiationException(AutoBuildSlot::class.java, "auto-build slot object needs a 'time' (HH:MM)")
|
||||
return AutoBuildSlot(
|
||||
time = time,
|
||||
buildCommand = node.get("buildCommand")?.asText() ?: "",
|
||||
name = node.get("name")?.asText() ?: "",
|
||||
)
|
||||
}
|
||||
throw context.instantiationException(
|
||||
AutoBuildSlot::class.java,
|
||||
"auto-build slot must be an HH:MM string or an object with 'time' and optional 'buildCommand' and 'name'",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** Writes the compact form back: a plain string unless the slot carries its own command or name. */
|
||||
class AutoBuildSlotSerializer : JsonSerializer<AutoBuildSlot>() {
|
||||
override fun serialize(
|
||||
slot: AutoBuildSlot,
|
||||
generator: JsonGenerator,
|
||||
provider: SerializerProvider,
|
||||
) {
|
||||
if (slot.buildCommand.isBlank() && slot.name.isBlank()) {
|
||||
generator.writeString(slot.time)
|
||||
return
|
||||
}
|
||||
generator.writeStartObject()
|
||||
generator.writeStringField("time", slot.time)
|
||||
if (slot.buildCommand.isNotBlank()) {
|
||||
generator.writeStringField("buildCommand", slot.buildCommand)
|
||||
}
|
||||
if (slot.name.isNotBlank()) {
|
||||
generator.writeStringField("name", slot.name)
|
||||
}
|
||||
generator.writeEndObject()
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,8 @@
|
||||
package de.hoennig.gittally.config
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize
|
||||
|
||||
data class GitTallyConfig(
|
||||
val server: ServerConfig = ServerConfig(),
|
||||
val git: GitConfig = GitConfig(),
|
||||
@@ -148,5 +151,30 @@ data class DockerConfig(
|
||||
|
||||
data class AutoBuildConfig(
|
||||
val enabled: Boolean = false,
|
||||
val times: List<String> = listOf("01:00"),
|
||||
/**
|
||||
* Daily UTC slots. Each entry is either a plain `HH:MM` time or an object with
|
||||
* `time` and its own `buildCommand` — so a nightly slot can run a fuller check
|
||||
* than the on-commit builds of the same branch.
|
||||
*/
|
||||
val times: List<AutoBuildSlot> = listOf(AutoBuildSlot("01:00")),
|
||||
)
|
||||
|
||||
/**
|
||||
* One scheduled auto-build slot; in YAML either a plain `HH:MM` string or an object
|
||||
* (`time` plus optional `buildCommand` and `name`) — see [AutoBuildSlotDeserializer].
|
||||
*/
|
||||
@JsonDeserialize(using = AutoBuildSlotDeserializer::class)
|
||||
@JsonSerialize(using = AutoBuildSlotSerializer::class)
|
||||
data class AutoBuildSlot(
|
||||
/** UTC time of day, `HH:MM`. */
|
||||
val time: String,
|
||||
/** Command this slot's build runs; empty runs the branch's [BranchConfig.buildCommand]. */
|
||||
val buildCommand: String = "",
|
||||
/**
|
||||
* Build name this slot's builds are recorded under (e.g. `master@nightly`); empty
|
||||
* records them under the branch name. A named slot gets its own history, retention
|
||||
* pool, latest status, and permanent latest-green artifact link, so its builds are
|
||||
* not displaced by the branch's regular builds.
|
||||
*/
|
||||
val name: String = "",
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user