fix(cms): robust git publish workflow and untracked env handling
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

- add .env.staging and .env.production patterns to .gitignore so local env files are ignored
- use robust publish command: git add . && (git diff --cached --quiet || git commit ...) && git pull --rebase origin main && git push origin main
- expand no-changes detection in publish response handling

Closes MITHOME-59
This commit is contained in:
Do Siki
2026-08-18 20:17:35 +02:00
parent c2cc701032
commit 84a4527838
3 changed files with 25 additions and 14 deletions
+7
View File
@@ -28,6 +28,13 @@ yarn-error.log*
# local env files # local env files
.env*.local .env*.local
.env .env
.env.staging
.env.production
.env.staging.*
.env.production.*
.env.*
!.env.staging.example
!.env.production.example
# vercel # vercel
.vercel .vercel
+16 -13
View File
@@ -291,7 +291,7 @@ const server = http.createServer(async (req, res) => {
return; return;
} }
// POST /publish — Git Commit & Push // POST /publish — Git Commit, Pull Rebase & Push
if (req.method === 'POST' && u.pathname === '/publish') { if (req.method === 'POST' && u.pathname === '/publish') {
if (exceedsRateLimit(`publish:${clientAddress}`, PUBLISH_MAX_ATTEMPTS)) { if (exceedsRateLimit(`publish:${clientAddress}`, PUBLISH_MAX_ATTEMPTS)) {
writeAudit('publish_rate_limited', { clientAddress, user: CMS_USER }); writeAudit('publish_rate_limited', { clientAddress, user: CMS_USER });
@@ -299,22 +299,25 @@ const server = http.createServer(async (req, res) => {
res.end(JSON.stringify({ ok: false, error: 'Túl sok publikálási kísérlet' })); res.end(JSON.stringify({ ok: false, error: 'Túl sok publikálási kísérlet' }));
return; return;
} }
exec('git add . && git commit -m "content: frissítve a CMS-ből" && git push', { cwd: CONTENT_DIR }, (error, stdout, stderr) => {
// WHY: (git diff --cached --quiet || git commit) ensures we only commit when
// staged changes exist. git pull --rebase origin main integrates remote changes
// (or unpushed local commits) cleanly before git push origin main.
const publishCmd = 'git add . && (git diff --cached --quiet || git commit -m "content: frissítve a CMS-ből") && git pull --rebase origin main && git push origin main';
exec(publishCmd, { cwd: CONTENT_DIR }, (error, stdout, stderr) => {
res.writeHead(200, { 'Content-Type': 'application/json' }); res.writeHead(200, { 'Content-Type': 'application/json' });
if (error) { const combinedOutput = `${stdout}\n${stderr}`;
// If there's nothing to commit, it's fine const isNoChanges = /nothing to commit|nothing added to commit|working tree clean|everything up-to-date|already up to date/i.test(combinedOutput);
if (stdout.includes('nothing to commit') || stdout.includes('working tree clean')) {
writeAudit('publish_finished', { clientAddress, user: CMS_USER, result: 'no_changes' }); if (error && !isNoChanges) {
res.end(JSON.stringify({ ok: true, output: 'No changes to commit' })); writeAudit('publish_finished', { clientAddress, user: CMS_USER, result: 'error' });
} else { res.end(JSON.stringify({ ok: false, error: stderr || stdout || error.message }));
writeAudit('publish_finished', { clientAddress, user: CMS_USER, result: 'error' });
res.end(JSON.stringify({ ok: false, error: stderr || stdout || error.message }));
}
} else { } else {
// Deploy only the explicitly configured environment; never default to production. // Deploy only the explicitly configured environment; never default to production.
exec(`cd ../../../ && ./deploy.sh ${CMS_DEPLOY_ENV} > deploy.log 2>&1 &`); exec(`cd ../../../ && ./deploy.sh ${CMS_DEPLOY_ENV} > deploy.log 2>&1 &`);
writeAudit('publish_finished', { clientAddress, user: CMS_USER, result: 'ok' }); writeAudit('publish_finished', { clientAddress, user: CMS_USER, result: isNoChanges ? 'no_changes' : 'ok' });
res.end(JSON.stringify({ ok: true, output: stdout })); res.end(JSON.stringify({ ok: true, output: stdout || 'Sikeres publikálás' }));
} }
}); });
return; return;
+2 -1
View File
@@ -24,7 +24,8 @@ const fixture = {
limit: 42, limit: 42,
sections: [{ id: 'first', items: ['egy', 'kettő'], settings: { visible: false, weight: 1 } }], sections: [{ id: 'first', items: ['egy', 'kettő'], settings: { visible: false, weight: 1 } }],
}; };
const html = serverContext.globalThis.renderContentEditor('home', JSON.stringify(fixture), null); const clientJs = fs.readFileSync('scripts/cms-editor-client.js', 'utf8');
const html = serverContext.globalThis.renderContentEditor('home', JSON.stringify(fixture), null, 'csrf-test-token', { common: '⚙️ Közös' }, clientJs);
const browserSource = [...html.matchAll(/<script(?: [^>]*)?>([\s\S]*?)<\/script>/g)].at(-1)[1] const browserSource = [...html.matchAll(/<script(?: [^>]*)?>([\s\S]*?)<\/script>/g)].at(-1)[1]
.replace("render(DATA, document.getElementById('editor'));", '') .replace("render(DATA, document.getElementById('editor'));", '')
.replace("const toast = document.querySelector('.toast');", 'const toast = null;'); .replace("const toast = document.querySelector('.toast');", 'const toast = null;');