const path = require("path"); const { execSync } = require("child_process"); const jsonfile = require("jsonfile"); const semver = require("semver"); const rootDir = path.resolve(__dirname, ".."); /** * @param {*} cond * @param {string} message * @returns {asserts cond} */ function invariant(cond, message) { if (!cond) throw new Error(message); } /** * @returns {string} */ function getTaggedVersion() { let output = execSync("git tag --list --points-at HEAD").toString(); return output.replace(/^v|\n+$/g, ""); } /** * @param {string} packageName * @param {string|number} version */ async function ensureBuildVersion(packageName, version) { let file = path.join(rootDir, "packages", packageName, "package.json"); let json = await jsonfile.readFile(file); invariant( json.version === version, `Package ${packageName} is on version ${json.version}, but should be on ${version}` ); } /** * @param {string} packageName * @param {string} tag */ function publishBuild(packageName, tag, releaseBranch) { let buildDir = path.join(rootDir, "packages", packageName); let args = ["--access public"]; if (tag) { args.push(`--tag ${tag}`); } if (tag === "experimental" || tag === "nightly") { args.push("--no-git-checks"); } else if (releaseBranch) { args.push(`--publish-branch ${releaseBranch}`); } else { throw new Error( "Expected a release branch name to be provided for non-experimental/nightly releases" ); } console.log(); console.log(` pnpm publish ${buildDir} --tag ${tag} --access public`); console.log(); execSync(`pnpm publish ${buildDir} ${args.join(" ")}`, { stdio: "inherit", }); } /** * @returns {Promise<1 | 0>} */ async function run() { try { // 0. Ensure we are in CI. We don't do this manually invariant( process.env.CI, `You should always run the publish script from the CI environment!` ); // 1. Get the current tag, which has the release version number let version = getTaggedVersion(); invariant( version !== "", "Missing release version. Run the version script first." ); // 2. Determine the appropriate npm tag to use let releaseBranch; let tag; if (version.includes("experimental")) { tag = "experimental"; } else if (version.includes("nightly")) { tag = "nightly"; } else if (version.startsWith("6.")) { // !!! Note: publish.js is not used for prereleases and stable releases. // We should be using the Changesets CI process for those. // These code paths are only left here for emergency usages releaseBranch = "release-v6"; tag = null; } else if (version.startsWith("7.")) { // !!! Note: publish.js is not used for prereleases and stable releases. // We should be using the Changesets CI process for those. // These code paths are only left here for emergency usages releaseBranch = "release-next"; tag = semver.prerelease(version) == null ? "latest" : "pre"; } console.log(); console.log(` Publishing version ${version} to npm with tag "${tag}"`); // 3. Ensure build versions match the release version await ensureBuildVersion("react-router", version); await ensureBuildVersion("react-router-dom", version); await ensureBuildVersion("react-router-dev", version); await ensureBuildVersion("react-router-express", version); await ensureBuildVersion("react-router-node", version); await ensureBuildVersion("react-router-serve", version); await ensureBuildVersion("react-router-architect", version); await ensureBuildVersion("react-router-cloudflare", version); await ensureBuildVersion("react-router-fs-routes", version); await ensureBuildVersion( "react-router-remix-routes-option-adapter", version ); await ensureBuildVersion("create-react-router", version); // 4. Publish to npm publishBuild("react-router", tag, releaseBranch); publishBuild("react-router-dom", tag, releaseBranch); publishBuild("react-router-dev", tag, releaseBranch); publishBuild("react-router-express", tag, releaseBranch); publishBuild("react-router-node", tag, releaseBranch); publishBuild("react-router-serve", tag, releaseBranch); publishBuild("react-router-architect", tag, releaseBranch); publishBuild("react-router-cloudflare", tag, releaseBranch); publishBuild("react-router-fs-routes", tag, releaseBranch); publishBuild( "react-router-remix-routes-option-adapter", tag, releaseBranch ); publishBuild("create-react-router", tag, releaseBranch); } catch (error) { console.log(); console.error(` ${error.message}`); console.log(); return 1; } return 0; } run().then((code) => { process.exit(code); });