From b92e71fa0e254b34d850d19c63471f0ed499e732 Mon Sep 17 00:00:00 2001 From: Kpa-clawbot <259247574+Kpa-clawbot@users.noreply.github.com> Date: Fri, 27 Mar 2026 09:54:53 -0700 Subject: [PATCH] refine version badge: clickable links, version only on prod - Commit hash is now an linking to GitHub commit (full hash in URL, 7-char display) - Version tag only shown on prod (port 80/443 or no port), linked to GitHub release - Staging (non-standard port) shows commit + engine only, no version noise - Detect prod vs staging via location.port - Updated tests: 16 cases covering prod/staging/links/edge cases - Bumped cache busters Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- public/app.js | 13 +++++- public/index.html | 54 ++++++++++++------------ test-frontend-helpers.js | 91 ++++++++++++++++++++++++++++++++-------- 3 files changed, 111 insertions(+), 47 deletions(-) diff --git a/public/app.js b/public/app.js index dad7bfd6..d0845008 100644 --- a/public/app.js +++ b/public/app.js @@ -107,9 +107,18 @@ function formatEngineBadge(engine) { function formatVersionBadge(version, commit, engine) { if (!version && !commit && !engine) return ''; + var port = (typeof location !== 'undefined' && location.port) || ''; + var isProd = !port || port === '80' || port === '443'; + var GH = 'https://github.com/Kpa-clawbot/meshcore-analyzer'; var parts = []; - if (version) parts.push(version.charAt(0) === 'v' ? version : 'v' + version); - if (commit && commit !== 'unknown') parts.push(commit.length > 7 ? commit.slice(0, 7) : commit); + if (version && isProd) { + var vTag = version.charAt(0) === 'v' ? version : 'v' + version; + parts.push('' + vTag + ''); + } + if (commit && commit !== 'unknown') { + var short = commit.length > 7 ? commit.slice(0, 7) : commit; + parts.push('' + short + ''); + } if (engine) parts.push('[' + engine + ']'); if (parts.length === 0) return ''; return ' ' + parts.join(' · ') + ''; diff --git a/public/index.html b/public/index.html index da96d3d5..15f20a9e 100644 --- a/public/index.html +++ b/public/index.html @@ -22,9 +22,9 @@ - - - + + + @@ -81,29 +81,29 @@
- - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test-frontend-helpers.js b/test-frontend-helpers.js index 87c09261..02ec51e3 100644 --- a/test-frontend-helpers.js +++ b/test-frontend-helpers.js @@ -1166,54 +1166,109 @@ console.log('\n=== app.js: formatEngineBadge ==='); // ===== APP.JS: formatVersionBadge ===== console.log('\n=== app.js: formatVersionBadge ==='); { - const ctx = makeSandbox(); - loadInCtx(ctx, 'public/roles.js'); - loadInCtx(ctx, 'public/app.js'); - const formatVersionBadge = ctx.formatVersionBadge; + function makeBadgeSandbox(port) { + const ctx = makeSandbox(); + ctx.location.port = port || ''; + loadInCtx(ctx, 'public/roles.js'); + loadInCtx(ctx, 'public/app.js'); + return ctx; + } + const GH = 'https://github.com/Kpa-clawbot/meshcore-analyzer'; test('returns empty string when all args missing', () => { + const { formatVersionBadge } = makeBadgeSandbox(''); assert.strictEqual(formatVersionBadge(null, null, null), ''); assert.strictEqual(formatVersionBadge(undefined, undefined, undefined), ''); assert.strictEqual(formatVersionBadge('', '', ''), ''); }); - test('shows version + commit + engine', () => { - const result = formatVersionBadge('2.6.0', 'abc1234def', 'go'); + + // --- Prod tests (no port / port 80 / port 443) --- + test('prod: shows version + commit + engine with links', () => { + const { formatVersionBadge } = makeBadgeSandbox(''); + const result = formatVersionBadge('2.6.0', 'abc1234def5678', 'node'); assert.ok(result.includes('version-badge'), 'should have version-badge class'); - assert.ok(result.includes('v2.6.0'), 'should show version with v prefix'); - assert.ok(result.includes('abc1234'), 'should show truncated commit'); - assert.ok(!result.includes('abc1234d'), 'should truncate commit to 7 chars'); - assert.ok(result.includes('[go]'), 'should show engine in brackets'); + assert.ok(result.includes(`href="${GH}/releases/tag/v2.6.0"`), 'version links to release'); + assert.ok(result.includes('>v2.6.0'), 'version text has v prefix'); + assert.ok(result.includes(`href="${GH}/commit/abc1234def5678"`), 'commit links to full hash'); + assert.ok(result.includes('>abc1234'), 'commit display is truncated to 7'); + assert.ok(result.includes('[node]'), 'should show engine'); }); - test('version already has v prefix', () => { + test('prod port 80: shows version', () => { + const { formatVersionBadge } = makeBadgeSandbox('80'); + const result = formatVersionBadge('2.6.0', null, 'node'); + assert.ok(result.includes('>v2.6.0'), 'port 80 is prod — shows version'); + }); + test('prod port 443: shows version', () => { + const { formatVersionBadge } = makeBadgeSandbox('443'); + const result = formatVersionBadge('2.6.0', null, 'node'); + assert.ok(result.includes('>v2.6.0'), 'port 443 is prod — shows version'); + }); + test('prod: version already has v prefix', () => { + const { formatVersionBadge } = makeBadgeSandbox(''); const result = formatVersionBadge('v2.6.0', null, null); - assert.ok(result.includes('v2.6.0'), 'should not double the v prefix'); + assert.ok(result.includes('>v2.6.0'), 'should not double the v prefix'); assert.ok(!result.includes('vv'), 'should not have vv'); }); + + // --- Staging tests (non-standard port) --- + test('staging: hides version, shows commit + engine', () => { + const { formatVersionBadge } = makeBadgeSandbox('3000'); + const result = formatVersionBadge('2.6.0', 'abc1234def5678', 'go'); + assert.ok(!result.includes('v2.6.0'), 'staging should NOT show version'); + assert.ok(result.includes('>abc1234'), 'should show commit hash'); + assert.ok(result.includes(`href="${GH}/commit/abc1234def5678"`), 'commit is linked'); + assert.ok(result.includes('[go]'), 'should show engine'); + }); + test('staging port 81: hides version', () => { + const { formatVersionBadge } = makeBadgeSandbox('81'); + const result = formatVersionBadge('2.6.0', 'abc1234', 'go'); + assert.ok(!result.includes('v2.6.0'), 'port 81 is staging — no version'); + assert.ok(result.includes('>abc1234'), 'commit shown'); + }); + + // --- Shared behavior --- + test('commit link uses full hash', () => { + const { formatVersionBadge } = makeBadgeSandbox(''); + const result = formatVersionBadge(null, 'abc1234def567890123456789abcdef012345678', 'node'); + assert.ok(result.includes(`href="${GH}/commit/abc1234def567890123456789abcdef012345678"`), 'link uses full hash'); + assert.ok(result.includes('>abc1234'), 'display is truncated to 7'); + }); test('skips commit when "unknown"', () => { + const { formatVersionBadge } = makeBadgeSandbox(''); const result = formatVersionBadge('2.6.0', 'unknown', 'node'); - assert.ok(result.includes('v2.6.0'), 'should show version'); + assert.ok(result.includes('>v2.6.0'), 'should show version'); assert.ok(!result.includes('unknown'), 'should not show unknown commit'); assert.ok(result.includes('[node]'), 'should show engine'); }); test('skips commit when missing', () => { + const { formatVersionBadge } = makeBadgeSandbox(''); const result = formatVersionBadge('2.6.0', null, 'go'); - assert.ok(result.includes('v2.6.0'), 'should show version'); + assert.ok(result.includes('>v2.6.0'), 'should show version'); assert.ok(result.includes('[go]'), 'should show engine'); }); test('shows only engine when version/commit missing', () => { + const { formatVersionBadge } = makeBadgeSandbox('3000'); const result = formatVersionBadge(null, null, 'go'); assert.ok(result.includes('[go]'), 'should show engine'); assert.ok(result.includes('version-badge'), 'should use version-badge class'); }); - test('short commit not truncated', () => { + test('short commit not truncated in display', () => { + const { formatVersionBadge } = makeBadgeSandbox(''); const result = formatVersionBadge('1.0.0', 'abc1234', 'node'); - assert.ok(result.includes('abc1234'), 'should show full short commit'); + assert.ok(result.includes('>abc1234'), 'should show full short commit'); }); - test('version only', () => { + test('version only on prod', () => { + const { formatVersionBadge } = makeBadgeSandbox(''); const result = formatVersionBadge('2.6.0', null, null); - assert.ok(result.includes('v2.6.0'), 'should show version'); + assert.ok(result.includes('>v2.6.0'), 'should show version'); assert.ok(!result.includes('·'), 'should not have separator for single part'); }); + test('staging: only engine when no commit', () => { + const { formatVersionBadge } = makeBadgeSandbox('8080'); + const result = formatVersionBadge('2.6.0', null, 'go'); + assert.ok(!result.includes('2.6.0'), 'no version on staging'); + assert.ok(result.includes('[go]'), 'engine shown'); + }); } // ===== SUMMARY =====