From 1c72a5009feff38f149da343307cee5034910a12 Mon Sep 17 00:00:00 2001 From: Joe Julian Date: Sun, 5 Apr 2026 23:56:58 -0700 Subject: [PATCH] Stamp app version into builds --- .gitea/workflows/ci.yml | 5 ++++- APK.md | 1 + Makefile | 3 +++ README.md | 7 +++++++ buildapk/config.go | 4 ++++ buildapk/config_test.go | 3 +++ main.go | 13 +++++++++++-- main_test.go | 19 +++++++++++++++++++ packaging/archlinux/keepassgo-git/PKGBUILD | 4 +++- 9 files changed, 55 insertions(+), 4 deletions(-) diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index 4f3c207..a0f4c41 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -107,6 +107,7 @@ jobs: shell: bash run: | set -euo pipefail + app_version="$(git describe --tags --always --dirty)" # Gio needs a Linux ARM64 cgo cross-toolchain for desktop builds. # Keep the CI matrix to targets this runner can build reproducibly. for target in \ @@ -126,13 +127,15 @@ jobs: ext=".exe" fi out="${DIST_DIR}/keepassgo-${goos}-${goarch}${ext}" - GOOS="${goos}" GOARCH="${goarch}" CGO_ENABLED="${cgo_enabled}" go build -o "${out}" . + GOOS="${goos}" GOARCH="${goarch}" CGO_ENABLED="${cgo_enabled}" \ + go build -ldflags "-X main.appVersion=${app_version}" -o "${out}" . done - name: Build APK shell: bash run: | set -euo pipefail + export APP_VERSION="$(git describe --tags --always --dirty)" make apk cp build/keepassgo.apk "${DIST_DIR}/keepassgo.apk" diff --git a/APK.md b/APK.md index 5fbb7d6..c6bf885 100644 --- a/APK.md +++ b/APK.md @@ -12,6 +12,7 @@ Environment: - `ANDROID_NDK_ROOT` defaults to `/opt/android-ndk`. - `JAVA_HOME` defaults to `/usr/lib/jvm/java-25-openjdk`. - `APP_ID` overrides the Android application id. +- `APP_VERSION` overrides the version shown inside KeePassGO itself. - `APK_OUT` overrides the output path. - `APK_VERSION` overrides the packaged app version. - `ANDROID_MIN_SDK` overrides the minimum supported Android SDK. diff --git a/Makefile b/Makefile index 58d8728..bf460eb 100644 --- a/Makefile +++ b/Makefile @@ -5,6 +5,8 @@ PATH := $(JAVA_HOME)/bin:$(ANDROID_SDK_ROOT)/cmdline-tools/latest/bin:$(ANDROID_ APP_ID ?= org.julianfamily.keepassgo APK_OUT ?= build/keepassgo.apk APK_VERSION ?= 0.1.0.1 +APP_VERSION ?= $(shell git describe --tags --always --dirty 2>/dev/null || echo dev) +GO_LDFLAGS ?= -X main.appVersion=$(APP_VERSION) ANDROID_MIN_SDK ?= 28 ANDROID_TARGET_SDK ?= 35 @@ -24,6 +26,7 @@ apk: android/keepassgo-android.jar go tool gogio -target android \ -buildmode exe \ -appid $(APP_ID) \ + -ldflags "$(GO_LDFLAGS)" \ -o $(APK_OUT) \ -version $(APK_VERSION) \ -minsdk $(ANDROID_MIN_SDK) \ diff --git a/README.md b/README.md index 13b8059..e6e5c99 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,13 @@ Desktop build: go build ./... ``` +By default, build outputs stamp the app version from `git describe --tags --always --dirty`. +You can override the version shown in KeePassGO with: + +```bash +go build -ldflags "-X main.appVersion=v0.0.1" ./... +``` + ## Arch Linux Package An AUR-style package definition for the Linux desktop client lives under: diff --git a/buildapk/config.go b/buildapk/config.go index 84cd13e..310bf47 100644 --- a/buildapk/config.go +++ b/buildapk/config.go @@ -13,6 +13,7 @@ const ( DefaultAppID = "org.julianfamily.keepassgo" DefaultAPKOut = "build/keepassgo.apk" DefaultVersion = "0.1.0.1" + DefaultLdflags = "-X main.appVersion=dev" DefaultMinSDK = "28" DefaultTargetSDK = "35" DefaultIconPath = "assets/keepassgo-icon.png" @@ -25,6 +26,7 @@ type Config struct { AppID string APKOut string Version string + Ldflags string MinSDK string TargetSDK string IconPath string @@ -38,6 +40,7 @@ func DefaultConfig() Config { AppID: DefaultAppID, APKOut: DefaultAPKOut, Version: DefaultVersion, + Ldflags: DefaultLdflags, MinSDK: DefaultMinSDK, TargetSDK: DefaultTargetSDK, IconPath: DefaultIconPath, @@ -49,6 +52,7 @@ func (c Config) GogioArgs() []string { "-target", "android", "-buildmode", "exe", "-appid", c.AppID, + "-ldflags", c.Ldflags, "-o", c.APKOut, "-version", c.Version, "-minsdk", c.MinSDK, diff --git a/buildapk/config_test.go b/buildapk/config_test.go index 91c2fd4..7d6d6b1 100644 --- a/buildapk/config_test.go +++ b/buildapk/config_test.go @@ -15,6 +15,7 @@ func TestDefaultConfigGogioArgs(t *testing.T) { "-target", "android", "-buildmode", "exe", "-appid", DefaultAppID, + "-ldflags", DefaultLdflags, "-o", DefaultAPKOut, "-version", DefaultVersion, "-minsdk", DefaultMinSDK, @@ -52,6 +53,7 @@ func TestValidateAcceptsCompleteAndroidToolchainLayout(t *testing.T) { AppID: DefaultAppID, APKOut: DefaultAPKOut, Version: DefaultVersion, + Ldflags: DefaultLdflags, MinSDK: DefaultMinSDK, TargetSDK: DefaultTargetSDK, IconPath: filepath.Join(root, "icon.png"), @@ -77,6 +79,7 @@ func TestValidateRejectsMissingPrerequisites(t *testing.T) { AppID: DefaultAppID, APKOut: DefaultAPKOut, Version: DefaultVersion, + Ldflags: DefaultLdflags, MinSDK: DefaultMinSDK, TargetSDK: DefaultTargetSDK, } diff --git a/main.go b/main.go index 9d9b9d5..afb5db1 100644 --- a/main.go +++ b/main.go @@ -43,6 +43,15 @@ import ( "golang.org/x/exp/shiny/materialdesign/icons" ) +var appVersion = "dev" + +func currentAppVersion() string { + if strings.TrimSpace(appVersion) == "" { + return "dev" + } + return strings.TrimSpace(appVersion) +} + type entry = vault.Entry const ( @@ -4246,12 +4255,12 @@ func (u *ui) aboutDetailPanel(gtx layout.Context) layout.Dimensions { aboutFact(u.theme, "Programmatic Access", "Secure local gRPC API", "Built for trusted clients such as browser extensions and automation."), layout.Spacer{Height: unit.Dp(14)}.Layout, func(gtx layout.Context) layout.Dimensions { - lbl := material.Label(u.theme, unit.Sp(12), "Runtime") + lbl := material.Label(u.theme, unit.Sp(12), "Version") lbl.Color = mutedColor return lbl.Layout(gtx) }, func(gtx layout.Context) layout.Dimensions { - lbl := material.Label(u.theme, unit.Sp(14), fmt.Sprintf("%s on %s/%s", runtime.Version(), runtime.GOOS, runtime.GOARCH)) + lbl := material.Label(u.theme, unit.Sp(14), currentAppVersion()) lbl.Color = u.theme.Palette.Fg return lbl.Layout(gtx) }, diff --git a/main_test.go b/main_test.go index 449d32b..470f58a 100644 --- a/main_test.go +++ b/main_test.go @@ -5517,6 +5517,25 @@ func TestShowAboutSection(t *testing.T) { } } +func TestCurrentAppVersion(t *testing.T) { + t.Parallel() + + previous := appVersion + t.Cleanup(func() { + appVersion = previous + }) + + appVersion = "" + if got := currentAppVersion(); got != "dev" { + t.Fatalf("currentAppVersion() with empty version = %q, want dev", got) + } + + appVersion = " v0.0.1 " + if got := currentAppVersion(); got != "v0.0.1" { + t.Fatalf("currentAppVersion() with linker version = %q, want v0.0.1", got) + } +} + func TestUIAPIPolicyTargetActionsUseCurrentContext(t *testing.T) { t.Parallel() diff --git a/packaging/archlinux/keepassgo-git/PKGBUILD b/packaging/archlinux/keepassgo-git/PKGBUILD index 6abb8ed..25c1b84 100644 --- a/packaging/archlinux/keepassgo-git/PKGBUILD +++ b/packaging/archlinux/keepassgo-git/PKGBUILD @@ -45,7 +45,9 @@ build() { cd "$(_repo_dir)" export CGO_ENABLED=1 export GOFLAGS="-trimpath" - go build -o keepassgo . + local app_version + app_version="$(git describe --tags --always --dirty)" + go build -ldflags "-X main.appVersion=${app_version}" -o keepassgo . } package() {