Something went wrong. Try again.
A Excalidraw fork with syncing to your Atmosphere account and iroh for sync forked from pds.dad/lexidraw
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246const fs = require("fs");const path = require("path");
const { execSync } = require("child_process");
const updateChangelog = require("./updateChangelog");
// skipping utils for now, as it has independent release processconst PACKAGES = [ "common", "fractional-indexing", "math", "element", "excalidraw",];const PACKAGES_DIR = path.resolve(__dirname, "../packages");
/** * Returns the arguments for the release script. * * Usage examples: * - pnpm release --help -> prints this help message * - pnpm release -> publishes `@excalidraw` packages with "test" tag and "-[hash]" version suffix * - pnpm release --tag=test -> same as above * - pnpm release --tag=next -> publishes `@excalidraw` packages with "next" tag and version "-[hash]" suffix * - pnpm release --tag=next --non-interactive -> skips interactive prompts (runs on CI/CD), otherwise same as above * - pnpm release --tag=latest --version=0.19.0 -> publishes `@excalidraw` packages with "latest" tag and version "0.19.0" & prepares changelog for the release * * @returns [tag, version, nonInteractive] */const getArguments = () => { let tag = "test"; let version = ""; let nonInteractive = false;
for (const argument of process.argv.slice(2)) { if (/--help/.test(argument)) { console.info(`Available arguments: --tag=<tag> -> (optional) "test" (default), "next" for auto release, "latest" for stable release --version=<version> -> (optional) for "next" and "test", (required) for "latest" i.e. "0.19.0" --non-interactive -> (optional) disables interactive prompts`);
console.info(`\nUsage examples: - pnpm release -> publishes \`@excalidraw\` packages with "test" tag and "-[hash]" version suffix - pnpm release --tag=test -> same as above - pnpm release --tag=next -> publishes \`@excalidraw\` packages with "next" tag and version "-[hash]" suffix - pnpm release --tag=next --non-interactive -> skips interactive prompts (runs on CI/CD), otherwise same as above - pnpm release --tag=latest --version=0.19.0 -> publishes \`@excalidraw\` packages with "latest" tag and version "0.19.0" & prepares changelog for the release`);
process.exit(0); }
if (/--tag=/.test(argument)) { tag = argument.split("=")[1]; }
if (/--version=/.test(argument)) { version = argument.split("=")[1]; }
if (/--non-interactive/.test(argument)) { nonInteractive = true; } }
if (tag !== "latest" && tag !== "next" && tag !== "test") { console.error(`Unsupported tag "${tag}", use "latest", "next" or "test".`); process.exit(1); }
if (tag === "latest" && !version) { console.error("Pass the version to make the latest stable release!"); process.exit(1); }
if (!version) { // set the next version based on the excalidraw package version + commit hash const excalidrawPackageVersion = require(getPackageJsonPath( "excalidraw", )).version;
const hash = getShortCommitHash();
if (!excalidrawPackageVersion.includes(hash)) { version = `${excalidrawPackageVersion}-${hash}`; } else { // ensuring idempotency version = excalidrawPackageVersion; } }
console.info(`Running with tag "${tag}" and version "${version}"...`);
return [tag, version, nonInteractive];};
const validatePackageName = (packageName) => { if (!PACKAGES.includes(packageName)) { console.error(`Package "${packageName}" not found!`); process.exit(1); }};
const getPackageJsonPath = (packageName) => { validatePackageName(packageName); return path.resolve(PACKAGES_DIR, packageName, "package.json");};
const updatePackageJsons = (nextVersion) => { const packageJsons = new Map();
for (const packageName of PACKAGES) { const pkg = require(getPackageJsonPath(packageName));
pkg.version = nextVersion;
if (pkg.dependencies) { for (const dependencyName of PACKAGES) { if (!pkg.dependencies[`@excalidraw/${dependencyName}`]) { continue; }
pkg.dependencies[`@excalidraw/${dependencyName}`] = nextVersion; } }
packageJsons.set(packageName, `${JSON.stringify(pkg, null, 2)}\n`); }
// modify once, to avoid inconsistent state for (const packageName of PACKAGES) { const content = packageJsons.get(packageName); fs.writeFileSync(getPackageJsonPath(packageName), content, "utf-8"); }};
const getShortCommitHash = () => { return execSync("git rev-parse --short HEAD").toString().trim();};
const askToCommit = (tag, nextVersion) => { if (tag !== "latest") { return Promise.resolve(); }
return new Promise((resolve) => { const rl = require("readline").createInterface({ input: process.stdin, output: process.stdout, });
rl.question( "Would you like to commit these changes to git? (Y/n): ", (answer) => { rl.close();
if (answer.toLowerCase() === "y") { execSync(`git add -u`); execSync( `git commit -m "chore: release @excalidraw/excalidraw@${nextVersion} 🎉"`, ); } else { console.warn( "Skipping commit. Don't forget to commit manually later!", ); }
resolve(); }, ); });};
const buildPackages = () => { console.info("Running pnpm install..."); execSync(`pnpm install --frozen-lockfile`, { stdio: "inherit" });
console.info("Removing existing build artifacts..."); execSync(`pnpm rm:build`, { stdio: "inherit" });
for (const packageName of PACKAGES) { console.info(`Building "@excalidraw/${packageName}"...`); execSync(`pnpm run build:esm`, { cwd: path.resolve(PACKAGES_DIR, packageName), stdio: "inherit", }); }};
const askToPublish = (tag, version) => { return new Promise((resolve) => { const rl = require("readline").createInterface({ input: process.stdin, output: process.stdout, });
rl.question( "Would you like to publish these changes to npm? (Y/n): ", (answer) => { rl.close();
if (answer.toLowerCase() === "y") { publishPackages(tag, version); } else { console.info("Skipping publish."); }
resolve(); }, ); });};
const publishPackages = (tag, version) => { for (const packageName of PACKAGES) { execSync(`pnpm publish --tag ${tag} --no-git-checks`, { cwd: path.resolve(PACKAGES_DIR, packageName), stdio: "inherit", });
console.info( `Published "@excalidraw/${packageName}@${tag}" with version "${version}"! 🎉`, ); }};
/** main */(async () => { const [tag, version, nonInteractive] = getArguments();
buildPackages();
if (tag === "latest") { await updateChangelog(version); }
updatePackageJsons(version);
if (nonInteractive) { publishPackages(tag, version); } else { await askToCommit(tag, version); await askToPublish(tag, version); }})();