feat: expose deploy version (git SHA) on CMS and health endpoint
CI Pipeline with Test Management / 🧪 Run Tests & Generate Reports (push) Waiting to run
CI Pipeline with Test Management / 🐳 Docker Integration Tests (push) Blocked by required conditions
CI Pipeline with Test Management / 🏗️ Build Docker Image (push) Blocked by required conditions
CI Pipeline with Test Management / 📊 Generate Test Summary (push) Blocked by required conditions
Test Reporting & Gherkin Analysis / 🧪 Run Tests & Generate Reports (push) Waiting to run
Test Reporting & Gherkin Analysis / 📊 Analyze Test Coverage (push) Blocked by required conditions
Test Reporting & Gherkin Analysis / 🔄 Sync with Linear (push) Blocked by required conditions
Test Reporting & Gherkin Analysis / ⚡ Performance Monitoring (push) Blocked by required conditions
CI Pipeline with Test Management / 🧪 Run Tests & Generate Reports (push) Waiting to run
CI Pipeline with Test Management / 🐳 Docker Integration Tests (push) Blocked by required conditions
CI Pipeline with Test Management / 🏗️ Build Docker Image (push) Blocked by required conditions
CI Pipeline with Test Management / 📊 Generate Test Summary (push) Blocked by required conditions
Test Reporting & Gherkin Analysis / 🧪 Run Tests & Generate Reports (push) Waiting to run
Test Reporting & Gherkin Analysis / 📊 Analyze Test Coverage (push) Blocked by required conditions
Test Reporting & Gherkin Analysis / 🔄 Sync with Linear (push) Blocked by required conditions
Test Reporting & Gherkin Analysis / ⚡ Performance Monitoring (push) Blocked by required conditions
'Is the fix live?' becomes a single check instead of an SSH session: - CMS: git short SHA read at startup, shown in the bottom bar (v<sha>), served by the public GET /version endpoint, recorded in a startup audit entry - Website: deploy.sh exports DEPLOY_VERSION (git SHA), Dockerfile bakes it via build ARG into the runtime env, /api/health reports it as deployVersion, smoke test asserts a non-'unversioned' stamp Closes MITHOME-63
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
const isStaging = () => process.env.CMS_DEPLOY_ENV === 'staging';
|
||||
|
||||
// FILE_LABELS is injected to avoid a circular dependency with the main file.
|
||||
const HTML = (activeFile, jsonData, message, csrfToken, fileLabels, clientJs, contentHash) => `<!DOCTYPE html>
|
||||
const HTML = (activeFile, jsonData, message, csrfToken, fileLabels, clientJs, contentHash, deployVersion) => `<!DOCTYPE html>
|
||||
<html lang="hu">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
@@ -68,6 +68,7 @@ const HTML = (activeFile, jsonData, message, csrfToken, fileLabels, clientJs, co
|
||||
.bottom-bar { position: fixed; bottom: 0; left: 0; right: 0; background: #0f1117; border-top: 1px solid #2d3748; padding: 14px 32px; display: flex; gap: 14px; align-items: center; z-index: 50; }
|
||||
.btn-logout { margin-left: auto; background: #1f2937; color: #e2e8f0; border: 1px solid #374151; border-radius: 8px; padding: 9px 16px; font-size: 14px; cursor: pointer; }
|
||||
.btn-logout:hover { background: #374151; }
|
||||
.version-tag { color: #475569; font-size: 12px; font-family: monospace; }
|
||||
.btn-save { background: linear-gradient(135deg,#3b82f6,#6366f1); color: #fff; border: none; padding: 11px 26px; border-radius: 8px; font-size: 14px; font-weight: 600; cursor: pointer; transition: opacity .2s, transform .1s; }
|
||||
.btn-save:hover { opacity: .9; transform: translateY(-1px); }
|
||||
.btn-save:active { transform: translateY(0); }
|
||||
@@ -112,6 +113,7 @@ ${message ? `<div class="toast ${message.type === 'ok' ? 'ok' : 'err'}">${messag
|
||||
<span class="save-status" id="saveStatus"></span>
|
||||
<a href="${isStaging() ? 'https://stage.mozdit.hu' : 'http://localhost:3000'}" target="_blank" class="preview-link">🔗 Előnézet →</a>
|
||||
<a href="/guide" target="_blank" class="preview-link">❓ Súgó</a>
|
||||
<span class="version-tag" title="Futó kód verziója (git SHA)">v${deployVersion}</span>
|
||||
<button class="btn-logout" onclick="logout()">🚪 Kilépés</button>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Integration test for CMS deploy versioning (MITHOME-63):
|
||||
* 1. GET /version is public and reports the git SHA of the checked-out commit
|
||||
* 2. the editor page displays the same version in the bottom bar
|
||||
* 3. a startup audit entry records the version
|
||||
*/
|
||||
const assert = require('assert/strict');
|
||||
const { execFileSync, spawn } = require('child_process');
|
||||
const fs = require('fs');
|
||||
const os = require('os');
|
||||
const path = require('path');
|
||||
|
||||
const ROOT = path.join(__dirname, '..');
|
||||
const PORT = 4129;
|
||||
const BASE = `http://127.0.0.1:${PORT}`;
|
||||
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'cms-version-'));
|
||||
const auditFile = path.join(tmp, 'audit.jsonl');
|
||||
|
||||
const expectedVersion = execFileSync('git', ['-C', ROOT, 'rev-parse', '--short', 'HEAD'], { encoding: 'utf8' }).trim();
|
||||
|
||||
const child = spawn('node', ['content-editor.js'], {
|
||||
cwd: ROOT,
|
||||
env: {
|
||||
...process.env,
|
||||
CONTENT_EDITOR_PORT: String(PORT),
|
||||
CONTENT_EDITOR_AUDIT_FILE: auditFile,
|
||||
CMS_USER: 'version-test-user',
|
||||
CMS_PASS: 'version-test-pass',
|
||||
CMS_DEPLOY_ENV: 'staging',
|
||||
},
|
||||
stdio: 'ignore',
|
||||
});
|
||||
|
||||
async function waitForServer(timeoutMs = 10000) {
|
||||
const deadline = Date.now() + timeoutMs;
|
||||
while (Date.now() < deadline) {
|
||||
try {
|
||||
await fetch(`${BASE}/version`);
|
||||
return;
|
||||
} catch {
|
||||
await new Promise(r => setTimeout(r, 200));
|
||||
}
|
||||
}
|
||||
throw new Error('server did not start');
|
||||
}
|
||||
|
||||
async function main() {
|
||||
await waitForServer();
|
||||
|
||||
// 1. public /version
|
||||
const res = await fetch(`${BASE}/version`);
|
||||
assert.equal(res.status, 200);
|
||||
const body = await res.json();
|
||||
assert.equal(body.version, expectedVersion);
|
||||
assert.equal(body.env, 'staging');
|
||||
|
||||
// 2. footer shows the same version
|
||||
const login = await fetch(`${BASE}/login`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ user: 'version-test-user', pass: 'version-test-pass' }),
|
||||
});
|
||||
const cookie = (login.headers.get('set-cookie') || '').split(';')[0];
|
||||
const page = await (await fetch(`${BASE}/`, { headers: { Cookie: cookie, Accept: 'text/html' } })).text();
|
||||
assert.ok(page.includes(`v${expectedVersion}`), 'bottom bar must show the deploy version');
|
||||
|
||||
// 3. startup audit entry
|
||||
const audit = fs.readFileSync(auditFile, 'utf8').trim().split('\n').map(l => JSON.parse(l));
|
||||
const startup = audit.find(e => e.event === 'startup');
|
||||
assert.ok(startup, 'startup audit entry exists');
|
||||
assert.equal(startup.version, expectedVersion);
|
||||
|
||||
console.log('Content Editor deploy version test: OK');
|
||||
}
|
||||
|
||||
main()
|
||||
.catch(err => { console.error('❌', err.message); process.exitCode = 1; })
|
||||
.finally(() => {
|
||||
child.kill('SIGTERM');
|
||||
try { fs.rmSync(tmp, { recursive: true, force: true }); } catch { /* best effort */ }
|
||||
});
|
||||
Reference in New Issue
Block a user