UNPKG

@mesh-tech/mesh-cli

Version:

CLI for Mesh platform development utilities

116 lines (115 loc) 5.72 kB
import { execFileSync, execSync } from "child_process"; import * as fs from "fs"; import * as path from "path"; import { logError, logInfo, logSuccess } from "../utils/log.js"; import { resolveCredentials, codeartifactLogin } from "./registry.js"; function repoRoot() { return execSync("git rev-parse --show-toplevel", { encoding: "utf-8" }).trim(); } function computeSnapshotVersion(root) { const sha = execSync("git rev-parse --short HEAD", { cwd: root, encoding: "utf-8" }).trim(); const stamp = new Date().toISOString().replace(/[-:T]/g, "").slice(0, 14); return `0.0.0-dev.${stamp}.${sha}`; } function setPackageVersion(file, version) { const content = fs.readFileSync(file, "utf-8"); const next = content.replace(/"version"(\s*:\s*)"[^"]*"/, `"version"$1"${version}"`); fs.writeFileSync(file, next); } function dirtyPackageJsons(root) { const out = execSync("git diff --name-only", { cwd: root, encoding: "utf-8" }); return new Set(out.split("\n").map((s) => s.trim()).filter((s) => s.endsWith("package.json"))); } export function registerRegistryPublish(registry) { registry .command("publish") .description("Publish an in-development snapshot of @mesh-tech packages to CodeArtifact (dev dist-tag)") .argument("[context]", 'Platform context for Zitadel auth (e.g. "mesh.dev")') .option("--snapshot", "Publish a dev snapshot build (required — real releases go through changesets/CI)", false) .option("--tag <tag>", "dist-tag to publish the snapshot under", "dev") .option("--only <pkgs>", "Comma-separated substring filter, e.g. --only agent-sdk,app-kit (default: all publishable)") .option("--dry-run", "Build + resolve versions but do not upload", false) .option("--role <arn>", "IAM role ARN for registry access") .action(async (context, opts) => { if (!opts.snapshot) { logError("mesh registry publish currently supports only snapshot (dev) builds.\n\n" + "Re-run with --snapshot. Real releases go through changesets + the\n" + "changeset-version CI workflow, not this command."); process.exit(1); } const root = repoRoot(); const awsCreds = resolveCredentials(context, opts.role); const env = Object.keys(awsCreds).length > 0 ? { ...process.env, ...awsCreds } : undefined; logInfo("Authenticating with CodeArtifact..."); if (!codeartifactLogin(env)) { logError("CodeArtifact login failed. Run: mesh registry login <context>"); process.exit(1); } const listPath = path.join(root, "scripts/lib/publishable-packages.json"); const all = JSON.parse(fs.readFileSync(listPath, "utf-8")); const patterns = (opts.only ?? "") .split(",") .map((s) => s.trim()) .filter(Boolean); const selected = patterns.length ? all.filter((p) => patterns.some((pat) => p.dir.includes(pat) || p.name.includes(pat))) : all; if (selected.length === 0) { logError(`No publishable package matched --only '${opts.only}'`); process.exit(1); } const version = computeSnapshotVersion(root); logInfo(`Snapshot version: ${version} (dist-tag '${opts.tag}')`); const preDirty = dirtyPackageJsons(root); const backups = []; const stamp = (dir) => { const file = path.join(root, dir, "package.json"); if (!fs.existsSync(file)) return; backups.push({ file, content: fs.readFileSync(file, "utf-8") }); setPackageVersion(file, version); }; try { for (const p of selected) { stamp(p.dir); for (const sub of p.subPackages ?? []) { stamp(path.join(p.dir, typeof sub === "string" ? sub : sub.dir)); } } const args = [ "scripts/publish-packages.sh", "--tag", opts.tag, "--skip-latest", ...(patterns.length ? ["--only", selected.map((p) => p.dir).join(",")] : []), ...(opts.dryRun ? ["--dry-run"] : []), ]; logInfo(`Publishing ${selected.length} package(s)...`); execFileSync("bash", args, { cwd: root, stdio: "inherit", env: env ?? process.env }); } finally { for (const b of backups) fs.writeFileSync(b.file, b.content); logInfo("Restored source package.json versions."); const collateral = [...dirtyPackageJsons(root)].filter((f) => !preDirty.has(f)); if (collateral.length) { try { execFileSync("git", ["checkout", "--", ...collateral], { cwd: root, stdio: "inherit" }); logInfo(`Reverted ${collateral.length} package.json file(s) re-vendored by build:publish.`); } catch { logError(`Could not auto-revert build:publish side-effects — run \`git checkout --\` on:\n ${collateral.join("\n ")}`); } } } logSuccess(`Published snapshot ${version} under dist-tag '${opts.tag}'.`); console.log("\nPin these EXACTLY in the consumer repo (prereleases are never auto-resolved by ^/~):"); for (const p of selected) console.log(` "${p.name}": "${version}",`); console.log(`\nOr always grab the newest dev build:\n pnpm add ${selected .map((p) => `${p.name}@${opts.tag}`) .join(" ")}`); }); }