diff --git a/pom.xml b/pom.xml index 4169ad1..a1d4228 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ alfred web - 0.0.1-SNAPSHOT + 0.0.2-SNAPSHOT web Alfred CI diff --git a/src/main/kotlin/alfred/web/WebApplication.kt b/src/main/kotlin/alfred/web/WebApplication.kt index d5c276e..f2e88dd 100644 --- a/src/main/kotlin/alfred/web/WebApplication.kt +++ b/src/main/kotlin/alfred/web/WebApplication.kt @@ -2,8 +2,10 @@ package alfred.web import org.springframework.boot.autoconfigure.SpringBootApplication import org.springframework.boot.runApplication +import org.springframework.scheduling.annotation.EnableScheduling @SpringBootApplication +@EnableScheduling open class WebApplication fun main(args: Array) { diff --git a/src/main/kotlin/alfred/web/core/AlfredHome.kt b/src/main/kotlin/alfred/web/core/AlfredHome.kt index 6b77174..8b4a3bb 100644 --- a/src/main/kotlin/alfred/web/core/AlfredHome.kt +++ b/src/main/kotlin/alfred/web/core/AlfredHome.kt @@ -1,9 +1,22 @@ package alfred.web.core import alfred.web.core.build.BuildId +import alfred.web.core.build.LogFile +import org.slf4j.Logger +import org.slf4j.LoggerFactory import org.springframework.beans.factory.annotation.Value +import org.springframework.scheduling.annotation.Scheduled import org.springframework.stereotype.Service +import java.nio.file.Files +import java.nio.file.Files.createFile import java.nio.file.Paths +import java.time.Instant +import java.time.LocalDateTime +import java.time.format.DateTimeFormatter +import java.time.temporal.ChronoUnit +import java.util.concurrent.TimeUnit +import kotlin.io.path.deleteIfExists +import kotlin.io.path.getLastModifiedTime @Service class AlfredHome( @@ -13,10 +26,33 @@ class AlfredHome( val homePath = Paths.get(home) - fun logsDir() = - homePath.resolve("logs") + val logsDir = homePath.resolve("logs") fun buildConfig(buildId: BuildId) = homePath.resolve("builds/${buildId}.properties") + fun newLogFile(build: BuildId): LogFile { + val nowStr = LocalDateTime.now().format(DateTimeFormatter.ISO_DATE_TIME) + val fileName = "$build.$nowStr.log" + + logsDir.toFile().mkdir() + + val logFilePath = logsDir.resolve(fileName) + return LogFile(createFile(logFilePath).toFile()) + } + + @Scheduled(fixedRate = 1, initialDelay = 1, timeUnit = TimeUnit.HOURS) + fun cleanup() { + val maxAge = Instant.now().minus(7L, ChronoUnit.DAYS) + + Files.list(logsDir) + .filter { it.getLastModifiedTime().toInstant().isBefore(maxAge) } + .forEach { + logger.info("log file $it gets old, deleting") + it.deleteIfExists() + } + } + + val logger: Logger = LoggerFactory.getLogger(this::class.java) + } diff --git a/src/main/kotlin/alfred/web/core/Handles.kt b/src/main/kotlin/alfred/web/core/Handles.kt index 96c3a7a..b5f3acb 100644 --- a/src/main/kotlin/alfred/web/core/Handles.kt +++ b/src/main/kotlin/alfred/web/core/Handles.kt @@ -1,9 +1,12 @@ package alfred.web.core import alfred.web.core.build.BuildId +import org.slf4j.Logger +import org.slf4j.LoggerFactory import org.springframework.scheduling.annotation.Scheduled import org.springframework.stereotype.Service import java.time.Instant +import java.util.concurrent.TimeUnit @Service class Handles { @@ -25,11 +28,18 @@ class Handles { ) } - @Scheduled(fixedDelay = 60_000) + @Scheduled(fixedRate = 1, initialDelay = 1, timeUnit = TimeUnit.MINUTES) fun cleanup() { - handles.removeIf { !it.handle.isAlive } + handles + .filter { !it.handle.isAlive } + .forEach { + logger.info("handle for command '${it.command}' is not alive and too old, removing") + } + handles + .removeIf { !it.handle.isAlive } } + val logger: Logger = LoggerFactory.getLogger(this::class.java) } data class Handle( diff --git a/src/main/kotlin/alfred/web/core/build/Builds.kt b/src/main/kotlin/alfred/web/core/build/Builds.kt index 082eedb..6a2856b 100644 --- a/src/main/kotlin/alfred/web/core/build/Builds.kt +++ b/src/main/kotlin/alfred/web/core/build/Builds.kt @@ -7,9 +7,6 @@ import org.slf4j.LoggerFactory import org.springframework.http.HttpStatus import org.springframework.stereotype.Service import org.springframework.web.bind.annotation.ResponseStatus -import java.nio.file.Files.createFile -import java.time.LocalDateTime -import java.time.format.DateTimeFormatter import java.util.* @Service @@ -41,17 +38,6 @@ class Builds( return props.toBuildConfig(env) } - fun createLogFile(build: BuildId): LogFile { - val nowStr = LocalDateTime.now().format(DateTimeFormatter.ISO_DATE_TIME) - val fileName = "$build.$nowStr.log" - - val logsDir = alfredHome.logsDir() - logsDir.toFile().mkdir() - - val logFilePath = logsDir.resolve(fileName) - return LogFile(createFile(logFilePath).toFile()) - } - } private fun Properties.toBuildConfig(env: Map) = diff --git a/src/main/kotlin/alfred/web/core/build/LogFile.kt b/src/main/kotlin/alfred/web/core/build/LogFile.kt index 97e55b9..34ac3d9 100644 --- a/src/main/kotlin/alfred/web/core/build/LogFile.kt +++ b/src/main/kotlin/alfred/web/core/build/LogFile.kt @@ -11,7 +11,7 @@ import kotlin.text.lines import kotlin.text.trim class LogFile( - val backingFile: File + val backingFile: File, ) { val logger: Logger = LoggerFactory.getLogger(this::class.java) diff --git a/src/main/kotlin/alfred/web/core/runner/GitRunner.kt b/src/main/kotlin/alfred/web/core/runner/GitRunner.kt index 4401a5a..497ea26 100644 --- a/src/main/kotlin/alfred/web/core/runner/GitRunner.kt +++ b/src/main/kotlin/alfred/web/core/runner/GitRunner.kt @@ -1,5 +1,6 @@ package alfred.web.core.runner +import alfred.web.core.AlfredHome import alfred.web.core.build.BuildContext import alfred.web.core.build.BuildId import alfred.web.core.build.Builds @@ -23,7 +24,8 @@ class GitRunner( val workspaces: Workspaces, val eventPublisher: ApplicationEventPublisher, val git: Git, - val script: Script + val script: Script, + val alfredHome: AlfredHome ) { val scriptsDir = ".alfred" @@ -32,7 +34,7 @@ class GitRunner( fun run(buildId: BuildId, rev: String): ProcessInfo { val config = builds.buildConfig(buildId) - val logFile = builds.createLogFile(buildId) + val logFile = alfredHome.newLogFile(buildId) logger.info("preparing process for build $buildId") logger.info("log file: ${logFile.backingFile.absolutePath}") diff --git a/src/main/kotlin/alfred/web/core/runner/ScriptRunner.kt b/src/main/kotlin/alfred/web/core/runner/ScriptRunner.kt index 8d2beba..c0f43e4 100644 --- a/src/main/kotlin/alfred/web/core/runner/ScriptRunner.kt +++ b/src/main/kotlin/alfred/web/core/runner/ScriptRunner.kt @@ -1,5 +1,6 @@ package alfred.web.core.runner +import alfred.web.core.AlfredHome import alfred.web.core.build.* import alfred.web.core.event.BuildFinished import alfred.web.core.process.Script @@ -14,12 +15,13 @@ class ScriptRunner( val builds: Builds, val workspaces: Workspaces, val eventPublisher: ApplicationEventPublisher, - val script: Script + val script: Script, + val alfredHome: AlfredHome ) { fun run(buildId: BuildId, rev: String?): ProcessInfo { val config = builds.buildConfig(buildId) - val logFile = builds.createLogFile(buildId) + val logFile = alfredHome.newLogFile(buildId) logger.info("preparing process for build $buildId") logger.info("log file: ${logFile.backingFile.absolutePath}") diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index ef539f0..47cf918 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -14,3 +14,5 @@ spring.mail.password=${ALFRED_MAIL_PASSWORD} spring.mail.properties.mail.smtp.auth=${ALFRED_MAIL_SMTP_AUTH : true} spring.mail.properties.mail.smtp.starttls.enable=${ALFRED_MAIL_STARTTLS : true} ALFRED_MAIL_FROM=alfred@your.service + +management.endpoints.web.exposure.include=scheduledtasks,health diff --git a/src/test/kotlin/alfred/web/core/runner/GitRunnerTest.kt b/src/test/kotlin/alfred/web/core/runner/GitRunnerTest.kt index c6eeeef..4d9a696 100644 --- a/src/test/kotlin/alfred/web/core/runner/GitRunnerTest.kt +++ b/src/test/kotlin/alfred/web/core/runner/GitRunnerTest.kt @@ -17,7 +17,6 @@ import io.mockk.verify import org.junit.jupiter.api.Test import org.junit.jupiter.api.io.TempDir import java.nio.file.Path -import java.nio.file.Paths class GitRunnerTest { @@ -36,12 +35,10 @@ class GitRunnerTest { val workspacesSpy = spyk(Workspaces()) - val home = mockk() - every { home.buildConfig(any()) } returns homeDir.resolve("simple-git.properties") - every { home.logsDir() } returns homeDir.resolve("logs") - every { home.homePath } returns homeDir + val home = AlfredHome(homeDir.toString()) + homeDir.resolve("builds").toFile().mkdir() homeDir - .resolve("simple-git.properties") + .resolve("builds/simple-git.properties") .toFile() .writeText(buildProperties()) @@ -51,7 +48,8 @@ class GitRunnerTest { workspaces = workspacesSpy, eventPublisher = eventPublisher, git = git, - script = script + script = script, + alfredHome = home ) // When diff --git a/src/test/kotlin/alfred/web/core/runner/ScriptRunnerTest.kt b/src/test/kotlin/alfred/web/core/runner/ScriptRunnerTest.kt index 4833c3d..f0e7cb3 100644 --- a/src/test/kotlin/alfred/web/core/runner/ScriptRunnerTest.kt +++ b/src/test/kotlin/alfred/web/core/runner/ScriptRunnerTest.kt @@ -17,12 +17,10 @@ class ScriptRunnerTest { @Test fun runs(@TempDir homeDir: Path) { // Given - val home = mockk() - every { home.buildConfig(any()) } returns homeDir.resolve("simple-script.properties") - every { home.logsDir() } returns homeDir.resolve("logs") - every { home.homePath } returns homeDir + val home = AlfredHome(homeDir.toString()) + homeDir.resolve("builds").toFile().mkdir() homeDir - .resolve("simple-script.properties") + .resolve("builds/simple-script.properties") .toFile() .writeText(buildProperties()) @@ -39,7 +37,8 @@ class ScriptRunnerTest { builds = Builds(home), workspaces = workspaces, eventPublisher = eventPublisher, - script = script + script = script, + alfredHome = home ) // When