Release ForgeFlow 0.6.1

This commit is contained in:
NuklearRabbit
2026-07-25 06:18:11 +02:00
parent 9d3933c878
commit 971896a1d5
10 changed files with 229 additions and 49 deletions
+54 -2
View File
@@ -71,7 +71,9 @@ test('source updater confirms an external STARTED marker before ForgeFlow may cl
queueMicrotask(() => child.emit('spawn'));
const statusIndex = args.indexOf('-StatusPath');
const statusPath = args[statusIndex + 1];
setTimeout(() => writeFile(statusPath, JSON.stringify({ state: 'started', expectedVersion: '0.5.3' })), 30);
const updateIdIndex = args.indexOf('-UpdateId');
const updateId = args[updateIdIndex + 1];
setTimeout(() => writeFile(statusPath, JSON.stringify({ state: 'started', expectedVersion: '0.5.3', updateId })), 30);
return child;
};
@@ -154,7 +156,7 @@ test('PowerShell update helper starts with param and has no BOM or stray leading
});
test('release publisher verifies Gitea and bootstraps only the installed updater helper', async () => {
test('release publisher verifies Gitea and bootstraps the installed updater service and helper', async () => {
const script = await readFile(new URL('../Publish-ForgeFlow-Release.ps1', import.meta.url), 'utf8');
assert.match(script, /npm install --no-audit --no-fund/);
assert.match(script, /package-lock\.json/);
@@ -163,7 +165,57 @@ test('release publisher verifies Gitea and bootstraps only the installed updater
assert.match(script, /git ls-remote origin/);
assert.match(script, /publishedCommit -ne \$localCommit/);
assert.match(script, /scripts\\apply-source-update\.ps1/);
assert.match(script, /src\\main\\update-service\.cjs/);
assert.match(script, /expectedUpdateId/);
assert.match(script, /readLogTail/);
assert.match(script, /HandshakeOnly/);
assert.match(script, /handshakeResult\.state -ne "started"/);
assert.match(script, /Windows-tested/);
assert.match(script, /without changing its version/);
assert.doesNotMatch(script, /Copy-Item[^\n]+package\.json/);
});
test('PowerShell helper replaces an existing launching status with a Windows-safe file API', async () => {
const script = await readFile(new URL('../scripts/apply-source-update.ps1', import.meta.url), 'utf8');
assert.match(script, /System\.IO\.File\]::Replace\(\$temporary, \$StatusPath, \$null\)/);
assert.match(script, /System\.IO\.File\]::Copy\(\$temporary, \$StatusPath, \$true\)/);
assert.doesNotMatch(script, /Move-Item -LiteralPath \$temporary -Destination \$StatusPath -Force/);
assert.match(script, /\[switch\]\$HandshakeOnly/);
assert.match(script, /Handshake-only verification completed successfully/);
});
test('early helper exit reports the helper log instead of only an exit code', async () => {
const temp = await mkdtemp(path.join(os.tmpdir(), 'forgeflow-update-log-tail-'));
const statusPath = path.join(temp, 'status.json');
const logPath = path.join(temp, 'apply.log');
await writeFile(statusPath, JSON.stringify({ state: 'launching', updateId: 'request-1' }));
await writeFile(logPath, 'first line\nactual helper failure\n');
await assert.rejects(
() => waitForUpdaterStarted(statusPath, {
timeoutMs: 100,
pollMs: 5,
childState: { exited: true, code: 0, error: null },
expectedUpdateId: 'request-1',
logPath
}),
(error) => error.code === 'UPDATE_HELPER_EXITED_EARLY' && /actual helper failure/.test(error.message)
);
await rm(temp, { recursive: true, force: true });
});
test('updater handshake rejects a stale status from another update request', async () => {
const temp = await mkdtemp(path.join(os.tmpdir(), 'forgeflow-update-id-'));
const statusPath = path.join(temp, 'status.json');
await writeFile(statusPath, JSON.stringify({ state: 'started', updateId: 'old-request' }));
await assert.rejects(
() => waitForUpdaterStarted(statusPath, {
timeoutMs: 50,
pollMs: 5,
childState: { exited: false, code: null, error: null },
expectedUpdateId: 'new-request'
}),
(error) => error.code === 'UPDATE_HELPER_START_TIMEOUT'
);
await rm(temp, { recursive: true, force: true });
});