From c17b27b2406d4d4e66466d4081d6f3acae76df69 Mon Sep 17 00:00:00 2001 From: cyph3rasi Date: Wed, 15 Jul 2026 00:17:28 -0700 Subject: [PATCH] Display repository commit count as the Synapsis version Hop-State: A_06FP98T1AFPC938R80XJ3J0 Hop-Proposal: R_06FP98S721MFZV1BVBVDTK8 Hop-Task: T_06FP98D0VF530A9XJ2HHHWR Hop-Attempt: AT_06FP98D0VFKNWCN4EJD46YR --- README.md | 2 +- next.config.ts | 14 ++++++++++++++ src/components/RightSidebar.tsx | 7 ++++--- src/lib/swarm/discovery.ts | 4 +++- src/lib/version.test.ts | 20 ++++++++++++++++++++ src/lib/version.ts | 6 ++++++ 6 files changed, 48 insertions(+), 5 deletions(-) create mode 100644 src/lib/version.test.ts diff --git a/README.md b/README.md index 195729d..44d662a 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ The installer creates: - Service: `synapsis.service` - Mandatory update timer: `synapsis-update.timer` -Every node checks `origin/main` about once per minute. When a new commit is available, Synapsis fast-forwards the checkout, replaces the single `backups/latest` database snapshot, installs dependencies, runs migrations, builds, and restarts automatically. The currently deployed commit is shown in the Network Info card and exposed by `/api/version`. +Every node checks `origin/main` about once per minute. When a new commit is available, Synapsis fast-forwards the checkout, replaces the single `backups/latest` database snapshot, installs dependencies, runs migrations, builds, and restarts automatically. The repository commit count is shown in the Network Info card; `/api/version` exposes both that number and the full deployed commit hash. For a node installed before automatic updates existed, bootstrap the timer once with: diff --git a/next.config.ts b/next.config.ts index 95f8d79..7eb05d7 100644 --- a/next.config.ts +++ b/next.config.ts @@ -14,9 +14,23 @@ function getBuildCommit(): string { } } +function getBuildCommitCount(): string { + if (process.env.APP_COMMIT_COUNT) return process.env.APP_COMMIT_COUNT; + + try { + return execFileSync('git', ['rev-list', '--count', 'HEAD'], { + cwd: process.cwd(), + encoding: 'utf8', + }).trim(); + } catch { + return 'unknown'; + } +} + const nextConfig: NextConfig = { env: { APP_COMMIT: getBuildCommit(), + APP_COMMIT_COUNT: getBuildCommitCount(), APP_BUILD_DATE: process.env.APP_BUILD_DATE || new Date().toISOString(), }, diff --git a/src/components/RightSidebar.tsx b/src/components/RightSidebar.tsx index b6299ff..1d797fe 100644 --- a/src/components/RightSidebar.tsx +++ b/src/components/RightSidebar.tsx @@ -32,6 +32,7 @@ export function RightSidebar() { const [version, setVersion] = useState<{ version: string; commit: string | null; + commitCount: number | null; buildDate: string | null; } | null>(null); @@ -80,7 +81,7 @@ export function RightSidebar() { fetch('/api/version') .then(res => res.json()) .then(data => setVersion(data)) - .catch(() => setVersion({ version: 'unknown', commit: null, buildDate: null })); + .catch(() => setVersion({ version: 'unknown', commit: null, commitCount: null, buildDate: null })); return () => window.removeEventListener('synapsis:node-updated', handleNodeUpdated); }, []); @@ -154,8 +155,8 @@ export function RightSidebar() {

Running{' '} Synapsis - {version?.commit - ? ` ${version.commit.slice(0, 7)}` + {version?.commitCount !== null && version?.commitCount !== undefined + ? ` ${version.commitCount}` : version?.version ? ` ${version.version}` : ''} diff --git a/src/lib/swarm/discovery.ts b/src/lib/swarm/discovery.ts index 9146edc..14a2d33 100644 --- a/src/lib/swarm/discovery.ts +++ b/src/lib/swarm/discovery.ts @@ -63,7 +63,9 @@ export async function buildAnnouncement(): Promise { description, logoUrl, publicKey, - softwareVersion: buildInfo.commit || buildInfo.version, + softwareVersion: buildInfo.commitCount !== null + ? String(buildInfo.commitCount) + : buildInfo.version, userCount, postCount, capabilities, diff --git a/src/lib/version.test.ts b/src/lib/version.test.ts new file mode 100644 index 0000000..d71597e --- /dev/null +++ b/src/lib/version.test.ts @@ -0,0 +1,20 @@ +import { afterEach, describe, expect, it, vi } from 'vitest'; +import { getCurrentBuildInfo } from './version'; + +afterEach(() => { + vi.unstubAllEnvs(); +}); + +describe('build information', () => { + it('exposes the repository commit count as a number', () => { + vi.stubEnv('APP_COMMIT_COUNT', '288'); + + expect(getCurrentBuildInfo().commitCount).toBe(288); + }); + + it('ignores an unavailable commit count', () => { + vi.stubEnv('APP_COMMIT_COUNT', 'unknown'); + + expect(getCurrentBuildInfo().commitCount).toBeNull(); + }); +}); diff --git a/src/lib/version.ts b/src/lib/version.ts index ec9a3cf..e8179da 100644 --- a/src/lib/version.ts +++ b/src/lib/version.ts @@ -3,13 +3,19 @@ import packageJson from '../../package.json'; export interface BuildInfo { version: string; commit: string | null; + commitCount: number | null; buildDate: string | null; } export function getCurrentBuildInfo(): BuildInfo { + const parsedCommitCount = Number.parseInt(process.env.APP_COMMIT_COUNT || '', 10); + return { version: process.env.APP_VERSION || packageJson.version || 'dev', commit: process.env.APP_COMMIT || null, + commitCount: Number.isSafeInteger(parsedCommitCount) && parsedCommitCount >= 0 + ? parsedCommitCount + : null, buildDate: process.env.APP_BUILD_DATE || null, }; }