feat(versioning): show runtime version and git hash in app footers
This commit is contained in:
@@ -10,5 +10,7 @@ CMS_SUPPORT_EMAIL="support@cms.local"
|
|||||||
CMS_SUPPORT_PASSWORD="change-me-support-password"
|
CMS_SUPPORT_PASSWORD="change-me-support-password"
|
||||||
CMS_SUPPORT_NAME="Technical Support"
|
CMS_SUPPORT_NAME="Technical Support"
|
||||||
CMS_SUPPORT_LOGIN_KEY="support-access-change-me"
|
CMS_SUPPORT_LOGIN_KEY="support-access-change-me"
|
||||||
|
NEXT_PUBLIC_APP_VERSION="0.1.0-dev"
|
||||||
|
NEXT_PUBLIC_GIT_SHA="local"
|
||||||
# Optional dev bypass role for admin middleware. Leave empty to require auth login.
|
# Optional dev bypass role for admin middleware. Leave empty to require auth login.
|
||||||
# CMS_DEV_ROLE="admin"
|
# CMS_DEV_ROLE="admin"
|
||||||
|
|||||||
19
TODO.md
19
TODO.md
@@ -85,12 +85,12 @@ This file is the single source of truth for roadmap and delivery progress.
|
|||||||
- [x] [P2] Bun-based Dockerfiles for public and admin apps
|
- [x] [P2] Bun-based Dockerfiles for public and admin apps
|
||||||
- [x] [P2] Staging and production docker-compose templates
|
- [x] [P2] Staging and production docker-compose templates
|
||||||
- [x] [P1] Registry credentials and image push strategy
|
- [x] [P1] Registry credentials and image push strategy
|
||||||
- [x] [P1] Staging deployment automation against real host
|
- [~] [P1] Staging deployment automation against real host
|
||||||
- [x] [P1] Production promotion and rollback procedure
|
- [~] [P1] Production promotion and rollback procedure
|
||||||
|
|
||||||
### Git Flow And Branching
|
### Git Flow And Branching
|
||||||
|
|
||||||
- [x] [P1] Protect `main` and `staging` branches in Gitea
|
- [~] [P1] Protect `main` and `staging` branches in Gitea
|
||||||
- [x] [P1] Define PR gates: lint + typecheck + unit + e2e list minimum
|
- [x] [P1] Define PR gates: lint + typecheck + unit + e2e list minimum
|
||||||
- [x] [P1] Enforce one todo item per branch naming convention
|
- [x] [P1] Enforce one todo item per branch naming convention
|
||||||
- [x] [P2] Add PR template requiring linked TODO step
|
- [x] [P2] Add PR template requiring linked TODO step
|
||||||
@@ -101,10 +101,19 @@ This file is the single source of truth for roadmap and delivery progress.
|
|||||||
- [x] [P1] Source of truth for version (`package.json` root) and release tagging rules (`vX.Y.Z`)
|
- [x] [P1] Source of truth for version (`package.json` root) and release tagging rules (`vX.Y.Z`)
|
||||||
- [x] [P1] Build metadata policy for git hash (`+sha.<short>`) in app runtime footer
|
- [x] [P1] Build metadata policy for git hash (`+sha.<short>`) in app runtime footer
|
||||||
- [x] [P1] App footer implementation plan for version + commit hash (admin + web)
|
- [x] [P1] App footer implementation plan for version + commit hash (admin + web)
|
||||||
- [x] [P2] Automated version injection in CI (stamping build from tag + commit hash)
|
- [~] [P2] Automated version injection in CI (stamping build from tag + commit hash)
|
||||||
- [x] [P2] Validation tests for displayed version/hash consistency per deployment
|
- [ ] [P2] Validation tests for displayed version/hash consistency per deployment
|
||||||
- [x] [P1] Release tagging and changelog publication policy in CI
|
- [x] [P1] Release tagging and changelog publication policy in CI
|
||||||
|
|
||||||
|
### MVP0 Close-Out Checklist
|
||||||
|
|
||||||
|
- [ ] [P1] Verify and document protected branch rules in Gitea (`main`, `staging`)
|
||||||
|
- [ ] [P1] Run first staging deployment against a real host with deploy workflow and document result
|
||||||
|
- [ ] [P1] Replace release workflow placeholders with real release-notes and rollback execution steps
|
||||||
|
- [x] [P1] Expose runtime version + short git hash in admin and public app footer
|
||||||
|
- [ ] [P2] Add CI build stamping for version/hash values consumed by app footers
|
||||||
|
- [ ] [P2] Add automated tests validating displayed version/hash format and consistency
|
||||||
|
|
||||||
## MVP 1: Core CMS Business Features
|
## MVP 1: Core CMS Business Features
|
||||||
|
|
||||||
### Admin App (Primary Focus)
|
### Admin App (Primary Focus)
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import type { ReactNode } from "react"
|
|||||||
|
|
||||||
import { LogoutButton } from "@/app/logout-button"
|
import { LogoutButton } from "@/app/logout-button"
|
||||||
import { AdminLocaleSwitcher } from "@/components/admin-locale-switcher"
|
import { AdminLocaleSwitcher } from "@/components/admin-locale-switcher"
|
||||||
|
import { getBuildInfo } from "@/lib/build-info"
|
||||||
|
|
||||||
type AdminShellProps = {
|
type AdminShellProps = {
|
||||||
role: Role
|
role: Role
|
||||||
@@ -57,6 +58,8 @@ export function AdminShell({
|
|||||||
actions,
|
actions,
|
||||||
children,
|
children,
|
||||||
}: AdminShellProps) {
|
}: AdminShellProps) {
|
||||||
|
const buildInfo = getBuildInfo()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mx-auto flex min-h-screen w-full max-w-7xl gap-8 px-6 py-10">
|
<div className="mx-auto flex min-h-screen w-full max-w-7xl gap-8 px-6 py-10">
|
||||||
<aside className="sticky top-0 hidden h-fit w-64 shrink-0 space-y-4 lg:block">
|
<aside className="sticky top-0 hidden h-fit w-64 shrink-0 space-y-4 lg:block">
|
||||||
@@ -111,6 +114,10 @@ export function AdminShell({
|
|||||||
</header>
|
</header>
|
||||||
|
|
||||||
{children}
|
{children}
|
||||||
|
|
||||||
|
<footer className="border-t border-neutral-200 pt-4 text-xs text-neutral-500">
|
||||||
|
Build v{buildInfo.version} +sha.{buildInfo.sha}
|
||||||
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
21
apps/admin/src/lib/build-info.ts
Normal file
21
apps/admin/src/lib/build-info.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
const FALLBACK_VERSION = "0.0.1-dev"
|
||||||
|
const FALLBACK_SHA = "local"
|
||||||
|
|
||||||
|
function shortenSha(input: string): string {
|
||||||
|
const value = input.trim()
|
||||||
|
if (!value) {
|
||||||
|
return FALLBACK_SHA
|
||||||
|
}
|
||||||
|
|
||||||
|
return value.slice(0, 7)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getBuildInfo() {
|
||||||
|
const version = process.env.NEXT_PUBLIC_APP_VERSION?.trim() || FALLBACK_VERSION
|
||||||
|
const sha = shortenSha(process.env.NEXT_PUBLIC_GIT_SHA ?? "")
|
||||||
|
|
||||||
|
return {
|
||||||
|
version,
|
||||||
|
sha,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,9 +2,12 @@
|
|||||||
|
|
||||||
import { useTranslations } from "next-intl"
|
import { useTranslations } from "next-intl"
|
||||||
|
|
||||||
|
import { getBuildInfo } from "@/lib/build-info"
|
||||||
|
|
||||||
export function PublicSiteFooter() {
|
export function PublicSiteFooter() {
|
||||||
const t = useTranslations("Layout")
|
const t = useTranslations("Layout")
|
||||||
const year = new Date().getFullYear()
|
const year = new Date().getFullYear()
|
||||||
|
const buildInfo = getBuildInfo()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<footer className="border-t border-neutral-200 bg-neutral-50">
|
<footer className="border-t border-neutral-200 bg-neutral-50">
|
||||||
@@ -15,6 +18,9 @@ export function PublicSiteFooter() {
|
|||||||
})}
|
})}
|
||||||
</p>
|
</p>
|
||||||
<p>{t("footer.tagline")}</p>
|
<p>{t("footer.tagline")}</p>
|
||||||
|
<p className="font-mono text-xs text-neutral-500">
|
||||||
|
Build v{buildInfo.version} +sha.{buildInfo.sha}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
)
|
)
|
||||||
|
|||||||
21
apps/web/src/lib/build-info.ts
Normal file
21
apps/web/src/lib/build-info.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
const FALLBACK_VERSION = "0.0.1-dev"
|
||||||
|
const FALLBACK_SHA = "local"
|
||||||
|
|
||||||
|
function shortenSha(input: string): string {
|
||||||
|
const value = input.trim()
|
||||||
|
if (!value) {
|
||||||
|
return FALLBACK_SHA
|
||||||
|
}
|
||||||
|
|
||||||
|
return value.slice(0, 7)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getBuildInfo() {
|
||||||
|
const version = process.env.NEXT_PUBLIC_APP_VERSION?.trim() || FALLBACK_VERSION
|
||||||
|
const sha = shortenSha(process.env.NEXT_PUBLIC_GIT_SHA ?? "")
|
||||||
|
|
||||||
|
return {
|
||||||
|
version,
|
||||||
|
sha,
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user