Files

86 lines
3.0 KiB
JavaScript

#!/usr/bin/env node
/**
* release:cut [patch|minor|major] [--version X.Y.Z] [--watch] [--dry-run]
*
* Cuts a release with zero local mutations: dispatches the Release App
* workflow, which resolves the next version from existing v* tags, creates
* the tag on origin/dev HEAD, stamps versions into the CI workspace, builds,
* and publishes. Nothing is committed to the repo — anywhere.
*/
import { execSync } from "node:child_process";
import { resolve } from "node:path";
import { fileURLToPath } from "node:url";
const root = resolve(fileURLToPath(new URL("../..", import.meta.url)));
const args = process.argv.slice(2);
const REPO = "different-ai/openwork";
const WORKFLOW = "Release App";
const dryRun = args.includes("--dry-run");
const watch = args.includes("--watch");
const versionIndex = args.indexOf("--version");
const explicitVersion = versionIndex >= 0 ? args[versionIndex + 1] : null;
const bumpType = args.find((arg) => ["patch", "minor", "major"].includes(arg)) ?? "patch";
const log = (msg) => console.log(` ${msg}`);
const heading = (msg) => console.log(`\n▸ ${msg}`);
const success = (msg) => console.log(` ✓ ${msg}`);
const fail = (msg) => {
console.error(` ✗ ${msg}`);
process.exit(1);
};
const run = (cmd, opts = {}) => {
if (dryRun && !opts.readOnly) {
log(`[dry-run] ${cmd}`);
return "";
}
try {
return execSync(cmd, {
cwd: root,
encoding: "utf8",
stdio: opts.inherit ? "inherit" : "pipe",
}).trim();
} catch (err) {
if (opts.allowFail) return "";
fail(`Command failed: ${cmd}\n${err.stderr || err.message}`);
}
};
heading("Checking gh auth");
const authed = run("gh auth status", { readOnly: true, allowFail: true });
if (!authed) fail("gh is not authenticated (run: gh auth login)");
success("gh authenticated");
heading("Dispatching Release App");
if (explicitVersion) {
if (!/^\d+\.\d+\.\d+$/.test(explicitVersion)) fail(`Invalid --version: ${explicitVersion} (expected X.Y.Z)`);
run(`gh workflow run "${WORKFLOW}" --repo ${REPO} -f version=${explicitVersion}`);
success(`Dispatched with version=${explicitVersion}`);
} else {
run(`gh workflow run "${WORKFLOW}" --repo ${REPO} -f bump=${bumpType}`);
success(`Dispatched with bump=${bumpType}`);
}
log(`Runs: https://github.com/${REPO}/actions/workflows/release-macos-aarch64.yml`);
log("The run resolves the version from v* tags and creates the tag on origin/dev HEAD.");
if (watch && !dryRun) {
heading("Watching workflow run");
execSync("sleep 10", { cwd: root });
const runId = run(
`gh run list --repo ${REPO} --workflow "${WORKFLOW}" --limit 1 --json databaseId -q ".[0].databaseId"`,
{ readOnly: true, allowFail: true },
);
if (runId) {
run(`gh run watch ${runId} --repo ${REPO} --exit-status`, { inherit: true, allowFail: true });
} else {
log("Could not find the workflow run. Check the Actions tab manually.");
}
}
console.log("\n" + "─".repeat(50));
console.log(` Release dispatched${dryRun ? " (DRY RUN — nothing sent)" : ""}.`);
console.log("─".repeat(50) + "\n");