← back to Open Seo

scripts/publish-release.mjs

59 lines

#!/usr/bin/env node

// @ts-check

import { execFileSync } from "node:child_process";
import { existsSync, readFileSync } from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { parseArgs } from "node:util";

const argv = process.argv.slice(2);
const normalizedArgv = argv[0] === "--" ? argv.slice(1) : argv;

const { values } = parseArgs({
  args: normalizedArgv,
  options: {
    "dry-run": { type: "boolean", default: false },
  },
  allowPositionals: false,
});

const repoRoot = fileURLToPath(new URL("../", import.meta.url));
const packageJsonPath = path.join(repoRoot, "package.json");
/** @type {unknown} */
const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf8"));

if (!packageJson || typeof packageJson !== "object") {
  throw new Error("package.json must contain an object");
}

const version = Reflect.get(packageJson, "version");
if (typeof version !== "string" || !/^\d+\.\d+\.\d+$/.test(version)) {
  throw new Error(`Invalid package version: ${String(version)}`);
}

const tag = `v${version}`;
const notesFile = `release-notes/${tag}.md`;
if (!existsSync(path.join(repoRoot, notesFile))) {
  throw new Error(`Missing release notes: ${notesFile}`);
}

const args = [
  "release",
  "create",
  tag,
  "--repo",
  "every-app/open-seo",
  "--title",
  tag,
  "--notes-file",
  notesFile,
];

if (values["dry-run"]) {
  process.stdout.write(`gh ${args.join(" ")}\n`);
} else {
  execFileSync("gh", args, { cwd: repoRoot, stdio: "inherit" });
}