81 lines
3.6 KiB
TypeScript
81 lines
3.6 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import { spawnSync } from "node:child_process";
|
|
import { test } from "node:test";
|
|
import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from "node:fs";
|
|
import { tmpdir } from "node:os";
|
|
import { join, resolve } from "node:path";
|
|
|
|
const fixture = "synthetic-cli-fixture";
|
|
const entrypoint = resolve("build/release-tools/publish-release.js");
|
|
|
|
function runPublication(mode: "success" | "transport" | "missing") {
|
|
const dir = mkdtempSync(join(tmpdir(), "potato-cli-"));
|
|
try {
|
|
mkdirSync(join(dir, "build/libs"), { recursive: true });
|
|
if (mode !== "missing") writeFileSync(join(dir, "build/libs/purpur-potato-1.2.3.jar"), Buffer.from([80, 75, 3, 4]));
|
|
// A process-local fake at the HTTP boundary: these tests must never contact Gitea.
|
|
const preload = join(dir, "http-fixture.mjs");
|
|
writeFileSync(preload, `
|
|
import assert from 'node:assert/strict';
|
|
let calls = 0;
|
|
globalThis.fetch = async (url, init) => {
|
|
calls++;
|
|
assert.equal(new Headers(init.headers).get('authorization'), 'token ' + process.env.RELEASE_CREDENTIAL);
|
|
assert.equal(init.redirect, 'error');
|
|
assert.ok(!url.includes(process.env.RELEASE_CREDENTIAL));
|
|
if (process.env.FIXTURE_MODE === 'transport') throw new Error(process.env.RELEASE_CREDENTIAL);
|
|
if (calls === 1) {
|
|
const body = JSON.parse(init.body);
|
|
assert.equal(body.target_commitish, 'a'.repeat(40));
|
|
assert.equal(body.body, 'Fixture notes');
|
|
assert.equal(body.draft, true);
|
|
} else if (calls === 2) {
|
|
assert.deepEqual(new Uint8Array(init.body), new Uint8Array([80, 75, 3, 4]));
|
|
assert.ok(url.endsWith('/42/assets?name=purpur-potato-1.2.3.jar'));
|
|
} else {
|
|
assert.equal(calls, 3);
|
|
assert.equal(init.method, 'PATCH');
|
|
}
|
|
return Response.json({id:42, draft: calls !== 3, tag_name:'v1.2.3', name:'purpur-potato-1.2.3.jar', size:4});
|
|
};
|
|
if (process.env.FIXTURE_MODE === 'success') process.on('exit', () => assert.equal(calls, 3));
|
|
`);
|
|
return spawnSync(process.execPath, ["--import", preload, entrypoint], {
|
|
cwd: dir, encoding: "utf8", env: {
|
|
VERSION: "1.2.3", RELEASE_COMMIT: "a".repeat(40), RELEASE_CREDENTIAL: fixture,
|
|
RELEASE_NOTES: "Fixture notes", FIXTURE_MODE: mode,
|
|
},
|
|
});
|
|
} finally { rmSync(dir, { recursive: true, force: true }); }
|
|
}
|
|
|
|
test("CLI reads only the exact versioned JAR and reports completed publication", () => {
|
|
const child = runPublication("success");
|
|
assert.equal(child.status, 0, child.stderr);
|
|
assert.equal(child.stdout, "Published purpur-potato v1.2.3.\n");
|
|
assert.equal(child.stderr, "");
|
|
});
|
|
|
|
for (const mode of ["transport", "missing"] as const) {
|
|
test(`CLI sanitizes ${mode} failures and never claims publication`, () => {
|
|
const child = runPublication(mode);
|
|
assert.equal(child.status, 1);
|
|
assert.equal(child.stdout, "");
|
|
assert.equal(child.stderr, "Release publication failed; inspect the release state before retrying.\n");
|
|
});
|
|
}
|
|
|
|
for (const environment of [
|
|
{ VERSION: "1.2.3", RELEASE_COMMIT: "a".repeat(40) },
|
|
{ VERSION: "../../outside", RELEASE_CREDENTIAL: "synthetic-cli-fixture", RELEASE_COMMIT: "a".repeat(40) },
|
|
]) {
|
|
test(`CLI fails closed on invalid input without echoing environment: ${Object.keys(environment)}`, () => {
|
|
const child = spawnSync(process.execPath, ["build/release-tools/publish-release.js"], {
|
|
encoding: "utf8", env: environment,
|
|
});
|
|
assert.equal(child.status, 1);
|
|
assert.equal(child.stdout, "");
|
|
assert.equal(child.stderr, "Release publication failed; inspect the release state before retrying.\n");
|
|
});
|
|
}
|