added configuration.md

This commit is contained in:
Michael Hoennig
2026-06-09 17:04:07 +02:00
parent 117caf12a9
commit 02b08306e1
6 changed files with 344 additions and 2 deletions
@@ -1,5 +1,6 @@
package de.hoennig.gittally.commands
import de.hoennig.gittally.config.ConfigLoader
import org.springframework.stereotype.Component
import picocli.CommandLine.Command
import picocli.CommandLine.Option
@@ -10,11 +11,22 @@ import picocli.CommandLine.Option
description = ["Print the effective configuration"],
mixinStandardHelpOptions = true,
)
class ConfigPrintCommand : Runnable {
class ConfigPrintCommand(
private val configLoader: ConfigLoader,
) : Runnable {
@Option(names = ["--full"], description = ["Include all defaults"])
var full: Boolean = false
override fun run() {
println("config:print${if (full) " --full" else ""} not yet implemented")
if (full) {
print(configLoader.toYaml(configLoader.load()))
} else {
val raw = configLoader.loadRaw()
if (raw.isEmpty()) {
println("(no configuration files found)")
} else {
print(configLoader.toYaml(raw))
}
}
}
}
@@ -0,0 +1,78 @@
package de.hoennig.gittally.config
import com.fasterxml.jackson.databind.DeserializationFeature
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.SerializationFeature
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory
import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator
import com.fasterxml.jackson.module.kotlin.registerKotlinModule
import org.springframework.stereotype.Service
import java.io.File
import java.nio.file.Path
import java.nio.file.Paths
@Service
class ConfigLoader {
private val yaml =
ObjectMapper(YAMLFactory().disable(YAMLGenerator.Feature.WRITE_DOC_START_MARKER))
.registerKotlinModule()
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)
fun load(workingDir: Path = Paths.get(".")): GitTallyConfig {
val raw = loadRaw(workingDir)
return if (raw.isEmpty()) {
GitTallyConfig()
} else {
yaml.convertValue(mergeBranchDefaults(raw), GitTallyConfig::class.java)
}
}
fun loadRaw(workingDir: Path = Paths.get(".")): Map<String, Any?> {
val repoInstall = loadFile(workingDir.resolve(".git/gittally/config.yml").toFile())
val project = loadFile(workingDir.resolve(".gittally.yml").toFile())
return deepMerge(project, repoInstall)
}
fun toYaml(value: Any): String = yaml.writeValueAsString(value)
private fun loadFile(file: File): Map<String, Any?> {
if (!file.exists()) return emptyMap()
@Suppress("UNCHECKED_CAST")
return yaml.readValue(file, Map::class.java) as Map<String, Any?>
}
@Suppress("UNCHECKED_CAST")
private fun mergeBranchDefaults(raw: Map<String, Any?>): Map<String, Any?> {
val branches = raw["branches"] as? Map<String, Any?> ?: return raw
val default = branches["default"] as? Map<String, Any?> ?: return raw
if (default.isEmpty()) return raw
val merged =
branches.mapValues { (name, value) ->
if (name == "default") {
value
} else {
deepMerge(default, value as? Map<String, Any?> ?: emptyMap())
}
}
return raw + ("branches" to merged)
}
@Suppress("UNCHECKED_CAST")
private fun deepMerge(
base: Map<String, Any?>,
overlay: Map<String, Any?>,
): Map<String, Any?> {
val result = base.toMutableMap()
for ((key, value) in overlay) {
val existing = result[key]
result[key] =
if (existing is Map<*, *> && value is Map<*, *>) {
deepMerge(existing as Map<String, Any?>, value as Map<String, Any?>)
} else {
value
}
}
return result
}
}
@@ -0,0 +1,44 @@
package de.hoennig.gittally.config
data class GitTallyConfig(
val server: ServerConfig = ServerConfig(),
val gitea: GiteaConfig = GiteaConfig(),
val artifacts: ArtifactsConfig = ArtifactsConfig(),
val watcher: WatcherConfig = WatcherConfig(),
val branches: Map<String, BranchConfig> = mapOf("default" to BranchConfig()),
)
data class ServerConfig(
val publicBaseUrl: String = "",
)
data class GiteaConfig(
val baseUrl: String = "",
val owner: String = "",
val repo: String = "",
val gitUsername: String = "",
val token: String = "",
val statusContext: String = "GitTally",
)
data class ArtifactsConfig(
val retentionPerBranch: Int = 3,
)
data class WatcherConfig(
val newBranchMaxAge: String = "5d",
)
data class BranchConfig(
val buildCommand: String = "./gradlew --console=plain --no-daemon test",
val cleanCommand: String = "rm -rf build",
val artifactDirs: List<String> = listOf("build/reports"),
val stdoutLog: String = "build.stdout.log",
val stderrLog: String = "build.stderr.log",
val autoBuild: AutoBuildConfig = AutoBuildConfig(),
)
data class AutoBuildConfig(
val enabled: Boolean = false,
val times: List<String> = listOf("01:00"),
)