From a0a8d3c97f509ca18859fe4001b6654557e3fb2e Mon Sep 17 00:00:00 2001 From: vvzvlad Date: Thu, 18 Jun 2026 04:51:21 +0300 Subject: [PATCH] feat(client): show git-describe version next to the brand logo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Display the app version (output of `git describe --tags`) in the header beside the gitmost logo: a clean tag renders as `vX.Y.Z`, otherwise the tag plus commits-since and short hash (e.g. v0.90.1-56-g25975acd). - vite.config.ts: resolve APP_VERSION from env (Docker/CI) -> git describe (local) -> package.json version fallback - app-header.tsx: render APP_VERSION after the brand block (ml="md"), nudge the Home nav group (ml={50} -> "xl") - Dockerfile: accept APP_VERSION build-arg in the builder stage (.git is excluded from the build context) - CI: pass APP_VERSION build-arg — release.yml uses the tag, develop.yml computes git describe with fetch-depth: 0 - nx.json: add APP_VERSION to the build target inputs so the cache invalidates when the version changes --- .github/workflows/develop.yml | 8 +++++++ .github/workflows/release.yml | 4 ++++ Dockerfile | 3 +++ .../components/layouts/global/app-header.tsx | 16 +++++++++++++- apps/client/vite.config.ts | 21 ++++++++++++++++++- nx.json | 9 +++++++- 6 files changed, 58 insertions(+), 3 deletions(-) diff --git a/.github/workflows/develop.yml b/.github/workflows/develop.yml index 324f1a28..736040b7 100644 --- a/.github/workflows/develop.yml +++ b/.github/workflows/develop.yml @@ -23,6 +23,8 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 + with: + fetch-depth: 0 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 @@ -34,11 +36,17 @@ jobs: username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} + - name: Resolve version + id: version + run: echo "value=$(git describe --tags --always)" >> "$GITHUB_OUTPUT" + - name: Build and push develop image uses: docker/build-push-action@v6 with: context: . platforms: linux/amd64 + build-args: | + APP_VERSION=${{ steps.version.outputs.value }} push: true tags: ${{ env.IMAGE }}:develop cache-from: type=gha,scope=develop-amd64 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a4e6d154..7137d953 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -50,6 +50,8 @@ jobs: with: context: . platforms: ${{ matrix.platform }} + build-args: | + APP_VERSION=${{ env.VERSION }} outputs: type=image,name=${{ env.IMAGE }},push-by-digest=true,name-canonical=true,push=true cache-from: type=gha,scope=${{ matrix.suffix }} cache-to: type=gha,scope=${{ matrix.suffix }},mode=max,ignore-error=true @@ -76,6 +78,8 @@ jobs: with: context: . platforms: ${{ matrix.platform }} + build-args: | + APP_VERSION=${{ env.VERSION }} push: false tags: | ${{ env.IMAGE }}:latest diff --git a/Dockerfile b/Dockerfile index 41edfa9c..34e5b17f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,6 +10,9 @@ WORKDIR /app COPY . . RUN pnpm install --frozen-lockfile +# Version string shown in the UI (computed outside Docker because .git is not in the build context). +ARG APP_VERSION="" +ENV APP_VERSION=$APP_VERSION RUN pnpm build FROM base AS installer diff --git a/apps/client/src/components/layouts/global/app-header.tsx b/apps/client/src/components/layouts/global/app-header.tsx index c69f230e..dd829f9b 100644 --- a/apps/client/src/components/layouts/global/app-header.tsx +++ b/apps/client/src/components/layouts/global/app-header.tsx @@ -1,6 +1,7 @@ import { Box, Group, + Text, Tooltip, } from "@mantine/core"; import classes from "./app-header.module.css"; @@ -76,7 +77,20 @@ export function AppHeader() { - + + + {APP_VERSION} + + + + {items} diff --git a/apps/client/vite.config.ts b/apps/client/vite.config.ts index b230a29f..8b9994ce 100644 --- a/apps/client/vite.config.ts +++ b/apps/client/vite.config.ts @@ -1,9 +1,28 @@ import { defineConfig, loadEnv } from "vite"; import react from "@vitejs/plugin-react"; import * as path from "path"; +import { execSync } from "node:child_process"; const envPath = path.resolve(process.cwd(), "..", ".."); +// Resolve the version string shown in the UI. +// Priority: explicit APP_VERSION env (injected by Docker/CI, where .git is absent), +// then `git describe` for local builds, then the package.json version as a fallback. +function resolveAppVersion(cwd: string): string { + const fromEnv = process.env.APP_VERSION?.trim(); + if (fromEnv) return fromEnv; + try { + return execSync("git describe --tags --always", { + cwd, + stdio: ["ignore", "pipe", "ignore"], + }) + .toString() + .trim(); + } catch { + return `v${process.env.npm_package_version ?? "0.0.0"}`; + } +} + export default defineConfig(({ mode }) => { const { APP_URL, @@ -32,7 +51,7 @@ export default defineConfig(({ mode }) => { POSTHOG_HOST, POSTHOG_KEY, }, - APP_VERSION: JSON.stringify(process.env.npm_package_version), + APP_VERSION: JSON.stringify(resolveAppVersion(envPath)), }, plugins: [react()], build: { diff --git a/nx.json b/nx.json index 171d1146..56d063e7 100644 --- a/nx.json +++ b/nx.json @@ -4,7 +4,14 @@ "dependsOn": [ "^build" ], - "cache": true + "cache": true, + "inputs": [ + "default", + "^default", + { + "env": "APP_VERSION" + } + ] }, "start:dev": { "dependsOn": [