diff --git a/Dockerfile b/Dockerfile index 35923cd..30325e7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,7 @@ FROM maven:3.9-eclipse-temurin-17 AS build WORKDIR /app COPY pom.xml ./ +COPY .git ./.git RUN mvn -B dependency:go-offline COPY src ./src RUN mvn -B package -DskipTests diff --git a/pom.xml b/pom.xml index 8547536..4a3f8ad 100644 --- a/pom.xml +++ b/pom.xml @@ -152,6 +152,27 @@ + + pl.project13.maven + git-commit-id-plugin + 4.9.10 + + + + revision + + + + + false + true + ${project.build.outputDirectory}/git.properties + + git.commit.id + git.commit.id.abbrev + + + diff --git a/src/main/java/dev/kruhlmann/imgfloat/controller/ViewController.java b/src/main/java/dev/kruhlmann/imgfloat/controller/ViewController.java index a027472..f703d97 100644 --- a/src/main/java/dev/kruhlmann/imgfloat/controller/ViewController.java +++ b/src/main/java/dev/kruhlmann/imgfloat/controller/ViewController.java @@ -10,6 +10,7 @@ import dev.kruhlmann.imgfloat.util.LogSanitizer; import dev.kruhlmann.imgfloat.service.AuthorizationService; import dev.kruhlmann.imgfloat.service.ChannelDirectoryService; import dev.kruhlmann.imgfloat.service.SettingsService; +import dev.kruhlmann.imgfloat.service.GitInfoService; import dev.kruhlmann.imgfloat.service.VersionService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -25,6 +26,7 @@ public class ViewController { private final ChannelDirectoryService channelDirectoryService; private final VersionService versionService; private final SettingsService settingsService; + private final GitInfoService gitInfoService; private final ObjectMapper objectMapper; private final AuthorizationService authorizationService; private final long uploadLimitBytes; @@ -33,6 +35,7 @@ public class ViewController { ChannelDirectoryService channelDirectoryService, VersionService versionService, SettingsService settingsService, + GitInfoService gitInfoService, ObjectMapper objectMapper, AuthorizationService authorizationService, long uploadLimitBytes @@ -40,6 +43,7 @@ public class ViewController { this.channelDirectoryService = channelDirectoryService; this.versionService = versionService; this.settingsService = settingsService; + this.gitInfoService = gitInfoService; this.objectMapper = objectMapper; this.authorizationService = authorizationService; this.uploadLimitBytes = uploadLimitBytes; @@ -129,5 +133,7 @@ public class ViewController { private void addVersionAttributes(Model model) { model.addAttribute("version", versionService.getVersion()); model.addAttribute("releaseVersion", versionService.getReleaseVersion()); + model.addAttribute("buildCommitShort", gitInfoService.getShortCommitSha()); + model.addAttribute("buildCommitUrl", gitInfoService.getCommitUrl()); } } diff --git a/src/main/java/dev/kruhlmann/imgfloat/service/GitInfoService.java b/src/main/java/dev/kruhlmann/imgfloat/service/GitInfoService.java new file mode 100644 index 0000000..7d2086b --- /dev/null +++ b/src/main/java/dev/kruhlmann/imgfloat/service/GitInfoService.java @@ -0,0 +1,126 @@ +package dev.kruhlmann.imgfloat.service; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.Properties; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +@Component +public class GitInfoService { + + private static final Logger LOG = LoggerFactory.getLogger(GitInfoService.class); + private static final String COMMIT_URL_PREFIX = "https://github.com/Kruhlmann/imgfloat-j/commit/"; + + private final String commitSha; + private final String shortCommitSha; + + public GitInfoService() { + CommitInfo commitInfo = resolveFromGitProperties(); + if (commitInfo == null) { + commitInfo = resolveFromGitBinary(); + } + + String full = commitInfo != null ? commitInfo.fullSha() : null; + String abbreviated = commitInfo != null ? commitInfo.shortSha() : null; + + if (abbreviated == null && full != null) { + abbreviated = abbreviate(full); + } else if (full == null && abbreviated != null) { + full = abbreviated; + } + + this.commitSha = defaultValue(full); + this.shortCommitSha = defaultValue(abbreviated); + } + + public String getCommitSha() { + return commitSha; + } + + public String getShortCommitSha() { + return shortCommitSha; + } + + public String getCommitUrl() { + if (commitSha == null || commitSha.isBlank() || "unknown".equalsIgnoreCase(commitSha)) { + return null; + } + return COMMIT_URL_PREFIX + commitSha; + } + + private CommitInfo resolveFromGitProperties() { + try (InputStream inputStream = getClass().getClassLoader().getResourceAsStream("git.properties")) { + if (inputStream == null) { + return null; + } + Properties properties = new Properties(); + properties.load(inputStream); + String fullSha = normalize(properties.getProperty("git.commit.id")); + String shortSha = normalize(properties.getProperty("git.commit.id.abbrev")); + if (fullSha == null && shortSha == null) { + return null; + } + return new CommitInfo(fullSha, shortSha); + } catch (IOException e) { + LOG.warn("Unable to read git.properties from classpath", e); + return null; + } + } + + private CommitInfo resolveFromGitBinary() { + String fullSha = runGitCommand("rev-parse", "HEAD"); + String shortSha = runGitCommand("rev-parse", "--short", "HEAD"); + if (fullSha == null && shortSha == null) { + return null; + } + return new CommitInfo(fullSha, shortSha); + } + + private String runGitCommand(String... command) { + try { + Process process = new ProcessBuilder(command).redirectErrorStream(true).start(); + try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) { + String output = reader.readLine(); + int exitCode = process.waitFor(); + if (exitCode == 0 && output != null && !output.isBlank()) { + return output.trim(); + } + LOG.debug("Git command {} failed with exit code {}", String.join(" ", command), exitCode); + return null; + } + } catch (InterruptedException e) { + LOG.debug("Git command interrupted {}", String.join(" ", command), e); + return null; + } catch (IOException e) { + LOG.debug("Git command IO error command {}", String.join(" ", command), e); + return null; + } + } + + private String abbreviate(String value) { + if (value == null) { + return null; + } + return value.length() > 7 ? value.substring(0, 7) : value; + } + + private String normalize(String value) { + if (value == null || value.isBlank()) { + return null; + } + return value.trim(); + } + + private String defaultValue(String value) { + if (value == null || value.isBlank()) { + return "unknown"; + } + return "unknown".equalsIgnoreCase(value) ? "unknown" : value; + } + + private record CommitInfo(String fullSha, String shortSha) {} +} diff --git a/src/main/resources/static/css/styles.css b/src/main/resources/static/css/styles.css index a65c876..f10403e 100644 --- a/src/main/resources/static/css/styles.css +++ b/src/main/resources/static/css/styles.css @@ -58,6 +58,13 @@ body { letter-spacing: 0.2px; font-size: 13px; } +.version-link { + color: inherit; + text-decoration: none; +} +.version-link:hover { + text-decoration: underline; +} .channels-body, .settings-body { diff --git a/src/main/resources/templates/index.html b/src/main/resources/templates/index.html index 3c9d418..7ffdc95 100644 --- a/src/main/resources/templates/index.html +++ b/src/main/resources/templates/index.html @@ -39,9 +39,22 @@ MIT
- Build + Version unknown
+
+ Build + unknown + unknown +