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
+