fix(version): read CI_COMMIT_TAG as source of truth, package.json as fallback
Previously: vite read package.json.version only, requiring manual bump before each tag pipeline (manual sync ломалось — MR !44 пример костыля). Now: vite reads CI_COMMIT_TAG (passed via Dockerfile ARG GIT_TAG from .gitlab-ci.yml .docker_base) → strips 'v' prefix → exposes как __APP_TAG__. 'none' sentinel filtered → empty string → fallback к package.json. VersionBadge priority chain: 1. serverTag (что прод RUNS, через /api/v1/version) 2. clientTag (что build'илось на tag pipeline) 3. v${clientVersion} (package.json fallback floor для local / branch) Dockerfile: add ARG GIT_TAG=none, ENV CI_COMMIT_TAG=$GIT_TAG (mirrors существующий pattern с GIT_COMMIT → CI_COMMIT_SHORT_SHA). Revert package.json 1.3.1 → 1.2.0 (manual bump из MR !44). Версия теперь follows tag, не наоборот.
This commit is contained in:
@@ -1,13 +1,16 @@
|
|||||||
FROM repo.nstart.cloud/library/node:22-alpine AS build
|
FROM repo.nstart.cloud/library/node:22-alpine AS build
|
||||||
# Git commit для VersionBadge / UpdateBanner (vite.config.ts читает
|
# Build identity для VersionBadge / UpdateBanner. Внутри Docker build context
|
||||||
# process.env.CI_COMMIT_SHORT_SHA на build time). Внутри Docker build
|
# нет .git/ (BUILD_CONTEXT=ordinis-admin-ui/), vite execSync падает →
|
||||||
# context нет .git/ (BUILD_CONTEXT=ordinis-admin-ui/), vite
|
# fallback "unknown" / package.json. CI передаёт реальные значения через
|
||||||
# execSync('git rev-parse') падает → fallback "unknown".
|
# --build-arg (см. .gitlab-ci.yml publish_script .docker_base).
|
||||||
# CI передаёт реальный SHA через --build-arg GIT_COMMIT (см. .gitlab-ci.yml
|
#
|
||||||
# publish_script). ENV exposes его vite-процессу через CI_COMMIT_SHORT_SHA
|
# GIT_TAG — "none" sentinel когда CI_COMMIT_TAG не set (branch pipeline).
|
||||||
# (тот же ключ что vite.config.ts проверяет первым).
|
# Фильтруем "none" → пустая строка чтобы vite.config.ts видел falsy и
|
||||||
|
# fallback'ил к package.json.
|
||||||
ARG GIT_COMMIT=unknown
|
ARG GIT_COMMIT=unknown
|
||||||
|
ARG GIT_TAG=none
|
||||||
ENV CI_COMMIT_SHORT_SHA=$GIT_COMMIT
|
ENV CI_COMMIT_SHORT_SHA=$GIT_COMMIT
|
||||||
|
ENV CI_COMMIT_TAG=$GIT_TAG
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
# .npmrc нужен ДО pnpm install, иначе @nstart/* резолвятся в public npm и 404.
|
# .npmrc нужен ДО pnpm install, иначе @nstart/* резолвятся в public npm и 404.
|
||||||
# pnpm-lock.yaml — для воспроизводимости (frozen lockfile в CI).
|
# pnpm-lock.yaml — для воспроизводимости (frozen lockfile в CI).
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "ordinis-admin-ui",
|
"name": "ordinis-admin-ui",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "1.3.1",
|
"version": "1.2.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import { useAppVersion } from './useAppVersion'
|
|||||||
export function VersionBadge() {
|
export function VersionBadge() {
|
||||||
const {
|
const {
|
||||||
clientVersion,
|
clientVersion,
|
||||||
|
clientTag,
|
||||||
clientCommit,
|
clientCommit,
|
||||||
clientBuiltAt,
|
clientBuiltAt,
|
||||||
serverVersion,
|
serverVersion,
|
||||||
@@ -21,8 +22,18 @@ export function VersionBadge() {
|
|||||||
updateAvailable,
|
updateAvailable,
|
||||||
} = useAppVersion()
|
} = useAppVersion()
|
||||||
|
|
||||||
|
// Priority: serverTag (что прод RUNS) → clientTag (что build'илось на tag
|
||||||
|
// pipeline) → v${clientVersion} (package.json fallback для local / branch).
|
||||||
|
// 'none' — Spring Boot build-info sentinel когда tag отсутствует.
|
||||||
|
const displayVersion =
|
||||||
|
serverTag && serverTag !== 'none'
|
||||||
|
? serverTag
|
||||||
|
: clientTag
|
||||||
|
? `v${clientTag}`
|
||||||
|
: `v${clientVersion}`
|
||||||
|
|
||||||
const tooltip = [
|
const tooltip = [
|
||||||
`client: ${clientVersion} (${clientCommit})`,
|
`client: ${clientTag ? `v${clientTag}` : `v${clientVersion}`} (${clientCommit})`,
|
||||||
`server: ${serverTag || serverVersion} (${serverCommit ?? '...'})`,
|
`server: ${serverTag || serverVersion} (${serverCommit ?? '...'})`,
|
||||||
`built: ${clientBuiltAt}`,
|
`built: ${clientBuiltAt}`,
|
||||||
].join('\n')
|
].join('\n')
|
||||||
@@ -38,9 +49,7 @@ export function VersionBadge() {
|
|||||||
className="inline-block w-1.5 h-1.5 rounded-full bg-accent animate-pulse"
|
className="inline-block w-1.5 h-1.5 rounded-full bg-accent animate-pulse"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{/* Prefer server tag (v1.2.0 etc.) над package.json clientVersion (0.1.0).
|
<span>{displayVersion}</span>
|
||||||
serverTag только при tag build'е — на branch builds показываем clientVersion. */}
|
|
||||||
<span>{serverTag && serverTag !== 'none' ? serverTag : `v${clientVersion}`}</span>
|
|
||||||
<span className="text-mute/70">·</span>
|
<span className="text-mute/70">·</span>
|
||||||
<span>{(serverCommit || clientCommit).substring(0, 8)}</span>
|
<span>{(serverCommit || clientCommit).substring(0, 8)}</span>
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -20,6 +20,9 @@ export function useAppVersion() {
|
|||||||
|
|
||||||
const clientCommit = __APP_COMMIT__
|
const clientCommit = __APP_COMMIT__
|
||||||
const clientVersion = __APP_VERSION__
|
const clientVersion = __APP_VERSION__
|
||||||
|
// Empty string when build wasn't на tag pipeline. VersionBadge / UpdateBanner
|
||||||
|
// решают priority: serverTag → clientTag → fallback v${clientVersion}.
|
||||||
|
const clientTag = __APP_TAG__
|
||||||
const clientBuiltAt = __APP_BUILT_AT__
|
const clientBuiltAt = __APP_BUILT_AT__
|
||||||
|
|
||||||
const knownClient = clientCommit !== 'unknown' && clientCommit !== ''
|
const knownClient = clientCommit !== 'unknown' && clientCommit !== ''
|
||||||
@@ -29,6 +32,7 @@ export function useAppVersion() {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
clientVersion,
|
clientVersion,
|
||||||
|
clientTag,
|
||||||
clientCommit,
|
clientCommit,
|
||||||
clientBuiltAt,
|
clientBuiltAt,
|
||||||
serverVersion: server?.version,
|
serverVersion: server?.version,
|
||||||
|
|||||||
Vendored
+9
@@ -13,7 +13,16 @@ interface ImportMeta {
|
|||||||
* Build identity injected via Vite {@code define} (см. vite.config.ts).
|
* Build identity injected via Vite {@code define} (см. vite.config.ts).
|
||||||
* Используются {@code useAppVersion} hook + {@code UpdateBanner} component
|
* Используются {@code useAppVersion} hook + {@code UpdateBanner} component
|
||||||
* для server-vs-client comparison.
|
* для server-vs-client comparison.
|
||||||
|
*
|
||||||
|
* <ul>
|
||||||
|
* <li>__APP_VERSION__ — package.json.version (fallback floor).</li>
|
||||||
|
* <li>__APP_TAG__ — CI_COMMIT_TAG без 'v' префикса. Пустая строка для
|
||||||
|
* branch / local builds. Authoritative для release builds.</li>
|
||||||
|
* <li>__APP_COMMIT__ — 8-char short SHA.</li>
|
||||||
|
* <li>__APP_BUILT_AT__ — ISO timestamp когда vite собирал bundle.</li>
|
||||||
|
* </ul>
|
||||||
*/
|
*/
|
||||||
declare const __APP_VERSION__: string
|
declare const __APP_VERSION__: string
|
||||||
|
declare const __APP_TAG__: string
|
||||||
declare const __APP_COMMIT__: string
|
declare const __APP_COMMIT__: string
|
||||||
declare const __APP_BUILT_AT__: string
|
declare const __APP_BUILT_AT__: string
|
||||||
|
|||||||
@@ -7,15 +7,27 @@ import path from 'path'
|
|||||||
import { execSync } from 'node:child_process'
|
import { execSync } from 'node:child_process'
|
||||||
import { readFileSync } from 'node:fs'
|
import { readFileSync } from 'node:fs'
|
||||||
|
|
||||||
// Build identity injected at compile time. Used by /update banner — client
|
// Build identity injected at compile time. Used by VersionBadge / UpdateBanner.
|
||||||
// сравнивает свой commit с server's /api/v1/version и показывает "Доступна
|
|
||||||
// новая версия" если различаются.
|
|
||||||
//
|
//
|
||||||
// Fallbacks для CI / sandboxed builds где git unavailable: env var override,
|
// Priority chain (most authoritative first):
|
||||||
// затем "unknown".
|
// 1. CI_COMMIT_TAG → set ONLY on tag pipelines (e.g. "v1.3.1"). Это source
|
||||||
|
// of truth для release builds. Strip leading 'v' → "1.3.1".
|
||||||
|
// 2. package.json.version → fallback floor для local dev и branch builds.
|
||||||
|
// НЕ обновляется вручную — release flow добавит автоматический bump
|
||||||
|
// позже (release script tag + npm version в одном commit'е).
|
||||||
|
//
|
||||||
|
// __APP_TAG__ — пустая строка если не tag build. VersionBadge решает что
|
||||||
|
// показать (приоритет: serverTag → clientTag → v${clientVersion}).
|
||||||
|
//
|
||||||
|
// __APP_COMMIT__ — 8-char short SHA. CI передаёт через CI_COMMIT_SHORT_SHA
|
||||||
|
// (GitLab default 8 chars), local через `git rev-parse --short=8`.
|
||||||
const APP_VERSION: string = JSON.parse(
|
const APP_VERSION: string = JSON.parse(
|
||||||
readFileSync(path.resolve(__dirname, 'package.json'), 'utf-8'),
|
readFileSync(path.resolve(__dirname, 'package.json'), 'utf-8'),
|
||||||
).version
|
).version
|
||||||
|
// 'none' — Dockerfile default ARG value (см. .gitlab-ci.yml passes
|
||||||
|
// --build-arg GIT_TAG="${CI_COMMIT_TAG:-none}"). Filter → пустая строка.
|
||||||
|
const RAW_TAG = process.env.CI_COMMIT_TAG ?? ''
|
||||||
|
const APP_TAG: string = RAW_TAG === 'none' ? '' : RAW_TAG.replace(/^v/, '')
|
||||||
const APP_COMMIT: string =
|
const APP_COMMIT: string =
|
||||||
process.env.CI_COMMIT_SHORT_SHA ??
|
process.env.CI_COMMIT_SHORT_SHA ??
|
||||||
(() => {
|
(() => {
|
||||||
@@ -32,6 +44,7 @@ const APP_BUILT_AT: string = new Date().toISOString()
|
|||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
define: {
|
define: {
|
||||||
__APP_VERSION__: JSON.stringify(APP_VERSION),
|
__APP_VERSION__: JSON.stringify(APP_VERSION),
|
||||||
|
__APP_TAG__: JSON.stringify(APP_TAG),
|
||||||
__APP_COMMIT__: JSON.stringify(APP_COMMIT),
|
__APP_COMMIT__: JSON.stringify(APP_COMMIT),
|
||||||
__APP_BUILT_AT__: JSON.stringify(APP_BUILT_AT),
|
__APP_BUILT_AT__: JSON.stringify(APP_BUILT_AT),
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user