fix(cms): deploy only on real changes, abort failed rebases, test publish
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

Review follow-up on MITHOME-59:

- no-op publish no longer triggers a background deploy (deploy moved behind
  a deterministic hadChanges flag)
- replace output-regex classification ('Already up to date.' also appears on
  real publishes when the remote did not move, which misclassified them as
  no_changes) with an explicit __NO_CONTENT_CHANGES__ marker echoed by the
  shell skip-branch
- failed git pull --rebase is aborted immediately so the repo is never left
  mid-rebase; the error is reported and nothing is pushed or deployed
- command + interpretation extracted to scripts/cms-publish.js
- CONTENT_EDITOR_CONTENT_DIR / CONTENT_EDITOR_DEPLOY_CMD env overrides enable
  an integration test against throwaway git repos covering: no-change skip,
  real publish + deploy, rebase conflict abort
- .gitignore: drop patterns already covered by .env.*
- user guide: new no-changes message

Closes MITHOME-60
This commit is contained in:
Do Siki
2026-08-18 20:25:12 +02:00
parent 8afc4e6899
commit c4c89f644e
5 changed files with 244 additions and 24 deletions
+22 -18
View File
@@ -15,9 +15,12 @@ const { exec } = require('child_process');
const crypto = require('crypto');
const { validateContent } = require('./proto/src/content/schema');
const { renderMarkdown } = require('./scripts/markdown-render');
const { buildPublishCommand, interpretPublishResult } = require('./scripts/cms-publish');
const PORT = Number(process.env.CONTENT_EDITOR_PORT) || 4001;
const CONTENT_DIR = path.join(__dirname, 'proto', 'src', 'content');
// WHY: overridable so the publish integration test can run against a throwaway
// git clone instead of the real repository.
const CONTENT_DIR = process.env.CONTENT_EDITOR_CONTENT_DIR || path.join(__dirname, 'proto', 'src', 'content');
const BACKUP_DIR = path.join(__dirname, '.content-backups');
const MAX_REQUEST_BODY_BYTES = 256 * 1024;
const AUDIT_LOG_FILE = process.env.CONTENT_EDITOR_AUDIT_FILE || path.join(__dirname, '.content-editor-audit.jsonl');
@@ -300,25 +303,26 @@ const server = http.createServer(async (req, res) => {
return;
}
// 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) => {
// Command shape and result classification live in scripts/cms-publish.js
// (WHY comments there): commit only when staged changes exist, rebase with
// abort-on-failure, deterministic no-changes marker instead of output matching.
exec(buildPublishCommand('content: frissítve a CMS-ből'), { cwd: CONTENT_DIR }, (error, stdout, stderr) => {
res.writeHead(200, { 'Content-Type': 'application/json' });
const combinedOutput = `${stdout}\n${stderr}`;
const isNoChanges = /nothing to commit|nothing added to commit|working tree clean|everything up-to-date|already up to date/i.test(combinedOutput);
if (error && !isNoChanges) {
writeAudit('publish_finished', { clientAddress, user: CMS_USER, result: 'error' });
res.end(JSON.stringify({ ok: false, error: stderr || stdout || error.message }));
} else {
// Deploy only the explicitly configured environment; never default to production.
exec(`cd ../../../ && ./deploy.sh ${CMS_DEPLOY_ENV} > deploy.log 2>&1 &`);
writeAudit('publish_finished', { clientAddress, user: CMS_USER, result: isNoChanges ? 'no_changes' : 'ok' });
res.end(JSON.stringify({ ok: true, output: stdout || 'Sikeres publikálás' }));
const outcome = interpretPublishResult(error, stdout, stderr);
writeAudit('publish_finished', { clientAddress, user: CMS_USER, result: outcome.result });
if (!outcome.ok) {
res.end(JSON.stringify({ ok: false, error: outcome.error }));
return;
}
// Deploy only when content actually changed — a no-op publish must not
// trigger a rebuild. Deploy only the explicitly configured environment;
// never default to production. Overridable for tests.
if (outcome.hadChanges) {
const deployCmd = process.env.CONTENT_EDITOR_DEPLOY_CMD
|| `cd ../../../ && ./deploy.sh ${CMS_DEPLOY_ENV} > deploy.log 2>&1 &`;
exec(deployCmd);
}
res.end(JSON.stringify({ ok: true, output: outcome.output }));
});
return;
}