implemented 12-deployment.md: added systemd service generation (init --systemd) and migration guide from legacy script; introduced JSON-file persistence, server-rendered UI with polling, and reverse-proxy-based deployment; updated documentation
This commit is contained in:
@@ -82,6 +82,62 @@ class InitCommandTest : FunSpec() {
|
||||
projectConfig.toFile().readText() shouldBe "existing: content"
|
||||
}
|
||||
|
||||
test("--systemd generates unit and environment file with install instructions") {
|
||||
val tempDir = Files.createTempDirectory("gittally-init-test")
|
||||
initCommand.workingDir = tempDir
|
||||
initCommand.systemd = true
|
||||
initCommand.jarPathResolver = { Paths.get("/home/ci/bin/gittally.jar") }
|
||||
initCommand.javaExecutableResolver = { Paths.get("/usr/bin/java") }
|
||||
|
||||
every { gitService.getTopLevel(tempDir) } returns tempDir
|
||||
every { gitService.getOriginUrl(tempDir) } returns "https://git.example.org/my-org/my-repo.git"
|
||||
|
||||
initCommand.run()
|
||||
|
||||
val unitName = SystemdServiceFiles.unitName(tempDir)
|
||||
val unitFile = tempDir.resolve(".git/gittally/$unitName")
|
||||
unitFile.toFile().shouldExist()
|
||||
val unitContent = unitFile.toFile().readText()
|
||||
unitContent shouldContain "WorkingDirectory=$tempDir"
|
||||
unitContent shouldContain """ExecStart="/usr/bin/java" ${'$'}JAVA_OPTS -jar "/home/ci/bin/gittally.jar" server"""
|
||||
|
||||
tempDir.resolve(".git/gittally/gittally.env").toFile().shouldExist()
|
||||
}
|
||||
|
||||
test("--systemd keeps an existing environment file") {
|
||||
val tempDir = Files.createTempDirectory("gittally-init-test")
|
||||
initCommand.workingDir = tempDir
|
||||
initCommand.systemd = true
|
||||
initCommand.jarPathResolver = { Paths.get("/home/ci/bin/gittally.jar") }
|
||||
initCommand.javaExecutableResolver = { Paths.get("/usr/bin/java") }
|
||||
|
||||
val envFile = tempDir.resolve(".git/gittally/gittally.env")
|
||||
Files.createDirectories(envFile.parent)
|
||||
envFile.toFile().writeText("JAVA_OPTS=-Xmx1g\n")
|
||||
|
||||
every { gitService.getTopLevel(tempDir) } returns tempDir
|
||||
every { gitService.getOriginUrl(tempDir) } returns "https://git.example.org/my-org/my-repo.git"
|
||||
|
||||
initCommand.run()
|
||||
|
||||
envFile.toFile().readText() shouldBe "JAVA_OPTS=-Xmx1g\n"
|
||||
}
|
||||
|
||||
test("--systemd without a resolvable jar path generates no unit file") {
|
||||
val tempDir = Files.createTempDirectory("gittally-init-test")
|
||||
initCommand.workingDir = tempDir
|
||||
initCommand.systemd = true
|
||||
initCommand.jarPathResolver = { null }
|
||||
|
||||
every { gitService.getTopLevel(tempDir) } returns tempDir
|
||||
every { gitService.getOriginUrl(tempDir) } returns "https://git.example.org/my-org/my-repo.git"
|
||||
|
||||
initCommand.run()
|
||||
|
||||
val unitFile = tempDir.resolve(".git/gittally/${SystemdServiceFiles.unitName(tempDir)}")
|
||||
unitFile.toFile().exists() shouldBe false
|
||||
}
|
||||
|
||||
test("reproduces path root mismatch issue") {
|
||||
val tempDir = Files.createTempDirectory("gittally-init-test").toAbsolutePath().normalize()
|
||||
initCommand.workingDir = Paths.get(".") // Set to relative path as in real app
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
package de.hoennig.gittally.commands
|
||||
|
||||
import io.kotest.core.spec.style.FunSpec
|
||||
import io.kotest.matchers.shouldBe
|
||||
import io.kotest.matchers.string.shouldContain
|
||||
import java.nio.file.Paths
|
||||
|
||||
class SystemdServiceFilesTest : FunSpec() {
|
||||
init {
|
||||
test("unit name is derived from the sanitized repository directory name") {
|
||||
SystemdServiceFiles.unitName(Paths.get("/srv/repos/my-repo")) shouldBe "gittally-my-repo.service"
|
||||
SystemdServiceFiles.unitName(Paths.get("/srv/repos/my repo!")) shouldBe "gittally-my-repo-.service"
|
||||
}
|
||||
|
||||
test("unit file runs the server jar in the repository with restart and environment file") {
|
||||
val content =
|
||||
SystemdServiceFiles.unitFileContent(
|
||||
repoRoot = Paths.get("/srv/repos/my-repo"),
|
||||
javaExecutable = Paths.get("/usr/lib/jvm/java-21/bin/java"),
|
||||
jarPath = Paths.get("/home/ci/bin/gittally.jar"),
|
||||
envFile = Paths.get("/srv/repos/my-repo/.git/gittally/gittally.env"),
|
||||
)
|
||||
|
||||
content shouldContain "Description=GitTally CI for my-repo"
|
||||
content shouldContain "After=network-online.target docker.service"
|
||||
content shouldContain "WorkingDirectory=/srv/repos/my-repo"
|
||||
content shouldContain "EnvironmentFile=-/srv/repos/my-repo/.git/gittally/gittally.env"
|
||||
content shouldContain
|
||||
"""ExecStart="/usr/lib/jvm/java-21/bin/java" ${'$'}JAVA_OPTS -jar "/home/ci/bin/gittally.jar" server"""
|
||||
content shouldContain "Restart=always"
|
||||
content shouldContain "RestartSec=30"
|
||||
content shouldContain "WantedBy=default.target"
|
||||
}
|
||||
|
||||
test("percent signs in paths are escaped for systemd") {
|
||||
val content =
|
||||
SystemdServiceFiles.unitFileContent(
|
||||
repoRoot = Paths.get("/srv/100%-repo"),
|
||||
javaExecutable = Paths.get("/usr/bin/java"),
|
||||
jarPath = Paths.get("/srv/100%-repo/gittally.jar"),
|
||||
envFile = Paths.get("/srv/100%-repo/gittally.env"),
|
||||
)
|
||||
|
||||
content shouldContain "WorkingDirectory=/srv/100%%-repo"
|
||||
content shouldContain "EnvironmentFile=-/srv/100%%-repo/gittally.env"
|
||||
content shouldContain """-jar "/srv/100%%-repo/gittally.jar" server"""
|
||||
}
|
||||
|
||||
test("environment file template only tunes the JVM") {
|
||||
val content = SystemdServiceFiles.envFileContent()
|
||||
|
||||
content shouldContain "#JAVA_OPTS="
|
||||
content shouldContain ".gittally.yml"
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user