chore(vendor): import pi 1.3.0
Imported as a linear vendor commit so forge rebases do not replay the upstream root tree. git-subtree-dir: third_party/pi git-subtree-split: 71023aec1546d6d677a65669c5665c0927ce0dd0
This commit is contained in:
136
third_party/pi/scripts/publish.mjs
vendored
136
third_party/pi/scripts/publish.mjs
vendored
@@ -1,110 +1,64 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import { spawnSync } from "node:child_process";
|
||||
import { existsSync } from "node:fs";
|
||||
import { existsSync, rmSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
import { produceArtifactSet } from "./package-artifacts.mjs";
|
||||
import { getPublicWorkspacePackages } from "./release-packages.mjs";
|
||||
|
||||
const packages = getPublicWorkspacePackages();
|
||||
import { execNpmSync } from "./npm-command.mjs";
|
||||
|
||||
const dryRun = process.argv.includes("--dry-run");
|
||||
const unknownArgs = process.argv.slice(2).filter((arg) => arg !== "--dry-run");
|
||||
|
||||
if (unknownArgs.length > 0) {
|
||||
console.error(`Usage: node scripts/publish.mjs [--dry-run]`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
function commandForPlatform(command) {
|
||||
return process.platform === "win32" ? `${command}.cmd` : command;
|
||||
}
|
||||
|
||||
function run(command, args, options = {}) {
|
||||
console.log(`$ ${[command, ...args].join(" ")}`);
|
||||
const result = spawnSync(commandForPlatform(command), args, {
|
||||
cwd: options.cwd,
|
||||
encoding: "utf8",
|
||||
stdio: options.capture ? ["inherit", "pipe", "pipe"] : "inherit",
|
||||
});
|
||||
|
||||
if (result.status !== 0) {
|
||||
const output = [result.stdout, result.stderr].filter(Boolean).join("\n");
|
||||
throw new Error(output ? `Command failed: ${command} ${args.join(" ")}\n${output}` : `Command failed: ${command} ${args.join(" ")}`);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function assertBuildOutputExists(directory) {
|
||||
if (!existsSync(join(directory, "dist"))) {
|
||||
throw new Error(`${directory}/dist does not exist. Run npm run build before publishing.`);
|
||||
}
|
||||
}
|
||||
|
||||
function validatePack(directory) {
|
||||
const result = run("npm", ["pack", "--dry-run", "--ignore-scripts", "--json"], { capture: true, cwd: directory });
|
||||
const packed = JSON.parse(result.stdout)[0];
|
||||
console.log(` ${packed.filename}: ${packed.files.length} files, ${packed.size} bytes packed, ${packed.unpackedSize} bytes unpacked`);
|
||||
}
|
||||
if (unknownArgs.length > 0) throw new Error("Usage: node scripts/publish.mjs [--dry-run]");
|
||||
|
||||
function isPublished(name, version) {
|
||||
const result = spawnSync(commandForPlatform("npm"), ["view", `${name}@${version}`, "version", "--json"], {
|
||||
encoding: "utf8",
|
||||
stdio: ["inherit", "pipe", "pipe"],
|
||||
});
|
||||
|
||||
if (result.status === 0 && result.stdout.trim()) {
|
||||
try {
|
||||
const output = execNpmSync(["view", `${name}@${version}`, "version", "--json"], {
|
||||
encoding: "utf8",
|
||||
stdio: ["inherit", "pipe", "pipe"],
|
||||
});
|
||||
if (!output.trim()) throw new Error(`npm returned no version for ${name}@${version}`);
|
||||
return true;
|
||||
} catch (error) {
|
||||
const output = error && typeof error === "object"
|
||||
? ["stdout", "stderr"].map((key) => key in error ? String(error[key] ?? "") : "").filter(Boolean).join("\n")
|
||||
: "";
|
||||
if (output.includes("E404") || output.includes("404 Not Found")) return false;
|
||||
throw new Error(`Failed to query ${name}@${version}${output ? `\n${output}` : ""}`, { cause: error });
|
||||
}
|
||||
|
||||
const output = [result.stdout, result.stderr].filter(Boolean).join("\n");
|
||||
if (result.status !== 0 && (output.includes("E404") || output.includes("404 Not Found"))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
throw new Error(output ? `Failed to query ${name}@${version}\n${output}` : `Failed to query ${name}@${version}`);
|
||||
}
|
||||
|
||||
const packageVersions = new Map(packages.map((pkg) => [pkg.name, pkg.version]));
|
||||
|
||||
const versions = [...new Set(packageVersions.values())];
|
||||
if (versions.length !== 1) {
|
||||
throw new Error(`Publish packages are not lockstep versioned: ${versions.join(", ")}`);
|
||||
const repoRoot = process.cwd();
|
||||
const packages = getPublicWorkspacePackages();
|
||||
const packageByName = new Map(packages.map((pkg) => [pkg.name, pkg]));
|
||||
const versions = [...new Set(packages.map((pkg) => pkg.version))];
|
||||
if (versions.length !== 1) throw new Error(`Publish packages are not lockstep versioned: ${versions.join(", ")}`);
|
||||
for (const pkg of packages) {
|
||||
if (!existsSync(join(pkg.directory, "dist"))) {
|
||||
throw new Error(`${pkg.directory}/dist does not exist. Run npm run build before publishing.`);
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`Publishing pi packages at ${versions[0]}${dryRun ? " (dry run)" : ""}\n`);
|
||||
|
||||
const packageStates = packages.map((pkg) => ({
|
||||
...pkg,
|
||||
published: false,
|
||||
version: packageVersions.get(pkg.name),
|
||||
}));
|
||||
|
||||
for (const pkg of packageStates) {
|
||||
assertBuildOutputExists(pkg.directory);
|
||||
pkg.published = isPublished(pkg.name, pkg.version);
|
||||
|
||||
if (pkg.published) {
|
||||
console.log(`${pkg.name}@${pkg.version} is already published; validating package contents only.`);
|
||||
} else {
|
||||
console.log(`${pkg.name}@${pkg.version} is not published; validating package contents before publish.`);
|
||||
const artifactSet = produceArtifactSet({ build: false, repoRoot });
|
||||
try {
|
||||
const packageStates = artifactSet.packages.map((pkg) => ({ ...pkg, published: isPublished(pkg.name, pkg.version) }));
|
||||
for (const pkg of packageStates) {
|
||||
console.log(`${pkg.name}@${pkg.version} ${pkg.published ? "is already published" : "is ready to publish"}: ${pkg.tarballPath}`);
|
||||
}
|
||||
validatePack(pkg.directory);
|
||||
console.log();
|
||||
}
|
||||
|
||||
if (dryRun) {
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
console.log("All packages validated; starting publication.\n");
|
||||
|
||||
for (const pkg of packageStates) {
|
||||
if (pkg.published) {
|
||||
console.log(`Skipping ${pkg.name}@${pkg.version}: already published\n`);
|
||||
continue;
|
||||
console.log(dryRun ? "\nDry-running tarball publication with provenance.\n" : "\nAll packages packed; starting publication.\n");
|
||||
for (const pkg of packageStates) {
|
||||
if (pkg.published) {
|
||||
console.log(`Skipping ${pkg.name}@${pkg.version}: already published\n`);
|
||||
continue;
|
||||
}
|
||||
const args = ["publish", pkg.tarballPath, "--access", "public", "--provenance", "--ignore-scripts"];
|
||||
if (dryRun) args.push("--dry-run");
|
||||
execNpmSync(args, {
|
||||
cwd: packageByName.get(pkg.name).directory,
|
||||
stdio: "inherit",
|
||||
});
|
||||
console.log();
|
||||
}
|
||||
|
||||
run("npm", ["publish", "--access", "public", "--provenance", "--ignore-scripts"], { cwd: pkg.directory });
|
||||
console.log();
|
||||
} finally {
|
||||
rmSync(artifactSet.artifactDirectory, { force: true, recursive: true });
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user