From 3818cee11fe8012684dd549481255cfff3704c66 Mon Sep 17 00:00:00 2001 From: Masterluke77 <163446896+Masterluke77@users.noreply.github.com> Date: Fri, 10 Jul 2026 14:42:04 +0200 Subject: [PATCH] test: harden updater 3.4 parallel workflow regressions --- tools/verify-production-updater-3.4.mjs | 53 ++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/tools/verify-production-updater-3.4.mjs b/tools/verify-production-updater-3.4.mjs index b67fbbd..15d5926 100644 --- a/tools/verify-production-updater-3.4.mjs +++ b/tools/verify-production-updater-3.4.mjs @@ -30,18 +30,35 @@ for (const file of [ 'docs/PRODUCTION_UPDATER_3_4.md', ]) assert(existsSync(join(root, file)), `Pflichtdatei fehlt: ${file}`); +const lifecycle = read('tools/updater-lifecycle-3.4.mjs'); +for (const marker of ['main-and-production-at-target', 'main-at-target-production-behind', 'matching-open-pr', 'matching-pr-already-merged']) { + assert(lifecycle.includes(marker), `Lifecycle-Entscheidung fehlt: ${marker}`); +} + if (existsSync(join(root, 'scripts/updater/Vendoo.Updater.Worker34.ps1'))) { const worker = read('scripts/updater/Vendoo.Updater.Worker34.ps1'); for (const marker of [ "'3.4.0'", 'production-update-v4', 'payloadHash', 'baseCommit', 'sourceCommit', 'Get-ReleaseObservation', 'Wait-RequiredGitHubChecks', 'headRefOid', 'workflow_runs', - 'force-with-lease', 'main-and-production-at-target', 'completedAt', 'finalPrHeadSha', + 'force-with-lease', 'completedAt', 'finalPrHeadSha', 'check-release-payload-3.4.mjs', '--match-head-commit', ]) assert(worker.includes(marker), `Worker-3.4-Vertrag fehlt: ${marker}`); assert(!worker.includes("@('pr','checks'"), 'Updater 3.4 darf gh pr checks --watch nicht mehr verwenden.'); assert(!worker.includes("@('push','--force'"), 'Updater 3.4 darf keinen unbedingten Force-Push verwenden.'); } +if (existsSync(join(root, 'scripts/updater/Vendoo.Updater.UI.ps1'))) { + const ui = read('scripts/updater/Vendoo.Updater.UI.ps1'); + assert(ui.includes("$UpdaterVersion = '3.4.0'"), 'Updater-UI meldet nicht Version 3.4.0.'); + assert(ui.includes("Vendoo.Updater.Worker34.ps1"), 'Updater-UI startet nicht den Worker 3.4.'); +} +if (existsSync(join(root, 'scripts/updater/Vendoo.Updater.Host.ps1'))) { + assert(read('scripts/updater/Vendoo.Updater.Host.ps1').includes("$UpdaterVersion = '3.4.0'"), 'Updater-Host meldet nicht Version 3.4.0.'); +} +const manifestSync = read('.github/workflows/sync-release-manifest.yml'); +assert(manifestSync.includes("'release/*-production-update-v*'"), 'Manifest-Sync ist nicht auf versionsneutrale Releasebranches generalisiert.'); +assert(!manifestSync.includes('release/1.43.0-production-update-v3'), 'Manifest-Sync enthält weiterhin den alten festen 3.3-Branch.'); + const packageJson = JSON.parse(read('package.json')); for (const name of ['verify:one-click-update', 'verify:updater-ui', 'verify:updater-hotfix']) { assert(packageJson.scripts?.[name] === 'node tools/verify-production-updater-3.4.mjs', `${name} verweist nicht auf Updater 3.4.`); @@ -70,11 +87,43 @@ for (const status of ['QUEUED', 'PENDING', 'IN_PROGRESS']) { assert(['pending', 'waiting-missing'].includes(result.state), `${status} wurde nicht als laufend behandelt.`); } result = classifyChecks({ checks: [...successChecks, { ...successChecks[0], completedAt: '2026-07-10T11:00:00Z', conclusion: 'CANCELLED' }], workflowRuns: successRuns, elapsedSeconds: 120 }); -assert(result.state === 'success', 'Paralleler älterer abgebrochener Lauf darf neueren Erfolg nicht überstimmen.'); +assert(result.state === 'success', 'Paralleler älterer abgebrochener Check darf neueren Erfolg nicht überstimmen.'); result = classifyChecks({ checks: successChecks.map((x, i) => i ? x : ({ ...x, conclusion: 'FAILURE' })), workflowRuns: successRuns, elapsedSeconds: 120 }); assert(result.state === 'failed', 'Fehlgeschlagener Pflichtcheck wurde nicht terminal erkannt.'); assert(formatStatusMatrix(result.rows).includes(REQUIRED_CHECKS[0]), 'Timeout-/Fehlermatrix enthält Checknamen nicht.'); +const runBase = successRuns.filter(run => run.name !== REQUIRED_WORKFLOWS[0]); +result = classifyChecks({ + checks: successChecks, + workflowRuns: [ + ...runBase, + { name: REQUIRED_WORKFLOWS[0], status: 'completed', conclusion: 'success', updated_at: '2026-07-10T11:00:00Z' }, + { name: REQUIRED_WORKFLOWS[0], status: 'completed', conclusion: 'failure', updated_at: '2026-07-10T12:00:00Z' }, + ], + elapsedSeconds: 120, +}); +assert(result.state === 'failed', 'Ein älterer erfolgreicher Workflow-Run darf einen neueren Fehler nicht verdecken.'); +result = classifyChecks({ + checks: successChecks, + workflowRuns: [ + ...runBase, + { name: REQUIRED_WORKFLOWS[0], status: 'completed', conclusion: 'failure', updated_at: '2026-07-10T11:00:00Z' }, + { name: REQUIRED_WORKFLOWS[0], status: 'in_progress', conclusion: null, updated_at: '2026-07-10T12:00:00Z' }, + ], + elapsedSeconds: 120, +}); +assert(result.state === 'pending', 'Ein neuer laufender Workflow-Run muss einen älteren Fehler ablösen.'); +result = classifyChecks({ + checks: successChecks, + workflowRuns: [ + ...runBase, + { name: REQUIRED_WORKFLOWS[0], status: 'completed', conclusion: 'cancelled', updated_at: '2026-07-10T11:00:00Z' }, + { name: REQUIRED_WORKFLOWS[0], status: 'completed', conclusion: 'success', updated_at: '2026-07-10T12:00:00Z' }, + ], + elapsedSeconds: 120, +}); +assert(result.state === 'success', 'Ein neuer erfolgreicher Workflow-Run muss einen älteren Abbruch ablösen.'); + let decision = decideReleasePath({ targetVersion: '1.43.0', mainVersion: '1.43.0', productionReady: true, productionVersion: '1.43.0' }); assert(decision.action === 'complete', 'Bereits deployte Zielversion muss sofort erfolgreich enden.'); decision = decideReleasePath({ targetVersion: '1.43.0', mainVersion: '1.43.0', productionReady: true, productionVersion: '1.42.0' });