feat(client): show git-describe version next to the brand logo
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
This commit is contained in:
8
.github/workflows/develop.yml
vendored
8
.github/workflows/develop.yml
vendored
@@ -23,6 +23,8 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v3
|
||||||
@@ -34,11 +36,17 @@ jobs:
|
|||||||
username: ${{ github.repository_owner }}
|
username: ${{ github.repository_owner }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Resolve version
|
||||||
|
id: version
|
||||||
|
run: echo "value=$(git describe --tags --always)" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
- name: Build and push develop image
|
- name: Build and push develop image
|
||||||
uses: docker/build-push-action@v6
|
uses: docker/build-push-action@v6
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
platforms: linux/amd64
|
platforms: linux/amd64
|
||||||
|
build-args: |
|
||||||
|
APP_VERSION=${{ steps.version.outputs.value }}
|
||||||
push: true
|
push: true
|
||||||
tags: ${{ env.IMAGE }}:develop
|
tags: ${{ env.IMAGE }}:develop
|
||||||
cache-from: type=gha,scope=develop-amd64
|
cache-from: type=gha,scope=develop-amd64
|
||||||
|
|||||||
4
.github/workflows/release.yml
vendored
4
.github/workflows/release.yml
vendored
@@ -50,6 +50,8 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
platforms: ${{ matrix.platform }}
|
platforms: ${{ matrix.platform }}
|
||||||
|
build-args: |
|
||||||
|
APP_VERSION=${{ env.VERSION }}
|
||||||
outputs: type=image,name=${{ env.IMAGE }},push-by-digest=true,name-canonical=true,push=true
|
outputs: type=image,name=${{ env.IMAGE }},push-by-digest=true,name-canonical=true,push=true
|
||||||
cache-from: type=gha,scope=${{ matrix.suffix }}
|
cache-from: type=gha,scope=${{ matrix.suffix }}
|
||||||
cache-to: type=gha,scope=${{ matrix.suffix }},mode=max,ignore-error=true
|
cache-to: type=gha,scope=${{ matrix.suffix }},mode=max,ignore-error=true
|
||||||
@@ -76,6 +78,8 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
platforms: ${{ matrix.platform }}
|
platforms: ${{ matrix.platform }}
|
||||||
|
build-args: |
|
||||||
|
APP_VERSION=${{ env.VERSION }}
|
||||||
push: false
|
push: false
|
||||||
tags: |
|
tags: |
|
||||||
${{ env.IMAGE }}:latest
|
${{ env.IMAGE }}:latest
|
||||||
|
|||||||
@@ -10,6 +10,9 @@ WORKDIR /app
|
|||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
RUN pnpm install --frozen-lockfile
|
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
|
RUN pnpm build
|
||||||
|
|
||||||
FROM base AS installer
|
FROM base AS installer
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
Group,
|
Group,
|
||||||
|
Text,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
} from "@mantine/core";
|
} from "@mantine/core";
|
||||||
import classes from "./app-header.module.css";
|
import classes from "./app-header.module.css";
|
||||||
@@ -76,7 +77,20 @@ export function AppHeader() {
|
|||||||
</Box>
|
</Box>
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
<Group ml={50} gap={5} className={classes.links} visibleFrom="sm">
|
<Tooltip label={t("Version")}>
|
||||||
|
<Text
|
||||||
|
size="xs"
|
||||||
|
c="dimmed"
|
||||||
|
lh={1}
|
||||||
|
ml="md"
|
||||||
|
visibleFrom="sm"
|
||||||
|
style={{ userSelect: "text", whiteSpace: "nowrap" }}
|
||||||
|
>
|
||||||
|
{APP_VERSION}
|
||||||
|
</Text>
|
||||||
|
</Tooltip>
|
||||||
|
|
||||||
|
<Group ml="xl" gap={5} className={classes.links} visibleFrom="sm">
|
||||||
{items}
|
{items}
|
||||||
</Group>
|
</Group>
|
||||||
</Group>
|
</Group>
|
||||||
|
|||||||
@@ -1,9 +1,28 @@
|
|||||||
import { defineConfig, loadEnv } from "vite";
|
import { defineConfig, loadEnv } from "vite";
|
||||||
import react from "@vitejs/plugin-react";
|
import react from "@vitejs/plugin-react";
|
||||||
import * as path from "path";
|
import * as path from "path";
|
||||||
|
import { execSync } from "node:child_process";
|
||||||
|
|
||||||
const envPath = path.resolve(process.cwd(), "..", "..");
|
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 }) => {
|
export default defineConfig(({ mode }) => {
|
||||||
const {
|
const {
|
||||||
APP_URL,
|
APP_URL,
|
||||||
@@ -32,7 +51,7 @@ export default defineConfig(({ mode }) => {
|
|||||||
POSTHOG_HOST,
|
POSTHOG_HOST,
|
||||||
POSTHOG_KEY,
|
POSTHOG_KEY,
|
||||||
},
|
},
|
||||||
APP_VERSION: JSON.stringify(process.env.npm_package_version),
|
APP_VERSION: JSON.stringify(resolveAppVersion(envPath)),
|
||||||
},
|
},
|
||||||
plugins: [react()],
|
plugins: [react()],
|
||||||
build: {
|
build: {
|
||||||
|
|||||||
Reference in New Issue
Block a user