UNPKG

@storm-software/workspace-tools

Version:

Tools for managing a Storm workspace, including various Nx generators and executors for common development tasks.

328 lines (316 loc) • 11 kB
import { addPackageJsonGitHead } from "./chunk-HXCYA4WX.mjs"; import { pnpmUpdate } from "./chunk-KHT5W6AJ.mjs"; import { joinPaths } from "./chunk-U7JFVMCK.mjs"; // src/executors/npm-publish/executor.ts import { execSync } from "node:child_process"; import { readFile, writeFile } from "node:fs/promises"; import { format } from "prettier"; var LARGE_BUFFER = 1024 * 1e6; async function npmPublishExecutorFn(options, context) { const isDryRun = process.env.NX_DRY_RUN === "true" || options.dryRun || false; if (!context.projectName) { throw new Error("The `npm-publish` executor requires a `projectName`."); } const projectConfig = context.projectsConfigurations?.projects?.[context.projectName]; if (!projectConfig) { throw new Error( `Could not find project configuration for \`${context.projectName}\`` ); } const packageRoot = joinPaths( context.root, options.packageRoot || joinPaths("dist", projectConfig.root) ); const projectRoot = context.projectsConfigurations.projects[context.projectName]?.root ? joinPaths( context.root, // eslint-disable-next-line @typescript-eslint/no-non-null-assertion context.projectsConfigurations.projects[context.projectName].root ) : packageRoot; const packageJsonPath = joinPaths(packageRoot, "package.json"); const packageJsonFile = await readFile(packageJsonPath, "utf8"); if (!packageJsonFile) { throw new Error(`Could not find \`package.json\` at ${packageJsonPath}`); } const packageJson = JSON.parse(packageJsonFile); const projectPackageJsonPath = joinPaths(projectRoot, "package.json"); const projectPackageJsonFile = await readFile(projectPackageJsonPath, "utf8"); if (!projectPackageJsonFile) { throw new Error( `Could not find \`package.json\` at ${projectPackageJsonPath}` ); } const projectPackageJson = JSON.parse(projectPackageJsonFile); if (packageJson.version !== projectPackageJson.version) { console.warn( `The version in the package.json file at ${packageJsonPath} (current: ${packageJson.version}) does not match the version in the package.json file at ${projectPackageJsonPath} (current: ${projectPackageJson.version}). This file will be updated to match the version in the project package.json file.` ); if (projectPackageJson.version) { packageJson.version = projectPackageJson.version; await writeFile( packageJsonPath, await format(JSON.stringify(packageJson), { parser: "json", proseWrap: "always", trailingComma: "none", tabWidth: 2, semi: true, singleQuote: false, quoteProps: "as-needed", insertPragma: false, bracketSameLine: true, printWidth: 80, bracketSpacing: true, arrowParens: "avoid", endOfLine: "lf", plugins: ["prettier-plugin-pkg"] }) ); } } const packageName = packageJson.name; console.info( `\u{1F680} Running Storm NPM Publish executor on the ${packageName} package` ); const packageTxt = packageName === context.projectName ? `package "${packageName}"` : `package "${packageName}" from project "${context.projectName}"`; if (packageJson.private === true) { console.warn( `Skipped ${packageTxt}, because it has \`"private": true\` in ${packageJsonPath}` ); return { success: true }; } await pnpmUpdate(packageRoot, context.root); await addPackageJsonGitHead(packageRoot); const npmPublishCommandSegments = [`npm publish --json`]; const npmViewCommandSegments = [ `npm view ${packageName} versions dist-tags --json` ]; const registry = options.registry ? options.registry : execSync("npm config get registry", { cwd: packageRoot, env: { ...process.env, FORCE_COLOR: "true" }, maxBuffer: LARGE_BUFFER, killSignal: "SIGTERM" }).toString().trim(); if (registry) { npmPublishCommandSegments.push(`--registry="${registry}" `); npmViewCommandSegments.push(`--registry="${registry}" `); } if (options.otp) { npmPublishCommandSegments.push(`--otp="${options.otp}" `); } if (isDryRun) { npmPublishCommandSegments.push("--dry-run"); } npmPublishCommandSegments.push("--provenance --access=public "); const tag = options.tag || execSync("npm config get tag", { cwd: packageRoot, env: { ...process.env, FORCE_COLOR: "true" }, maxBuffer: LARGE_BUFFER, killSignal: "SIGTERM" }).toString().trim(); if (tag) { npmPublishCommandSegments.push(`--tag="${tag}" `); } if (!isDryRun) { const currentVersion = options.version || packageJson.version; try { try { const result = execSync(npmViewCommandSegments.join(" "), { cwd: packageRoot, env: { ...process.env, FORCE_COLOR: "true" }, maxBuffer: LARGE_BUFFER, killSignal: "SIGTERM" }); const resultJson = JSON.parse(result.toString()); const distTags = resultJson["dist-tags"] || {}; if (distTags[tag] === currentVersion) { console.warn( `Skipped ${packageTxt} because v${currentVersion} already exists in ${registry} with tag "${tag}"` ); return { success: true }; } } catch (err) { console.warn("\n ********************** \n"); console.warn( `An error occurred while checking for existing dist-tags ${JSON.stringify(err)} Note: If this is the first time this package has been published to NPM, this can be ignored. ` ); console.info(""); } try { if (!isDryRun) { const command = `npm dist-tag add ${packageName}@${currentVersion} ${tag} --registry="${registry}" `; console.info( `Adding the dist-tag ${tag} - preparing to run the following: ${command} ` ); const result = execSync(command, { cwd: packageRoot, env: { ...process.env, FORCE_COLOR: "true" }, maxBuffer: LARGE_BUFFER, killSignal: "SIGTERM" }); console.info( `Added the dist-tag ${tag} to v${currentVersion} for registry "${registry}" Execution response: ${result.toString()} ` ); } else { console.info( `Would add the dist-tag ${tag} to v${currentVersion} for registry "${registry}", but [dry-run] was set. ` ); } return { success: true }; } catch (err) { try { console.warn("\n ********************** \n"); let error = err; if (Buffer.isBuffer(error)) { error = error.toString(); } console.warn( `An error occurred while adding dist-tags: ${error} Note: If this is the first time this package has been published to NPM, this can be ignored. ` ); console.info(""); const stdoutData = JSON.parse(err.stdout?.toString() || "{}"); if (stdoutData?.error && !(stdoutData.error?.code?.includes("E404") && stdoutData.error?.summary?.includes("no such package available")) && !(err.stderr?.toString().includes("E404") && err.stderr?.toString().includes("no such package available"))) { console.error( "npm dist-tag add error please see below for more information:" ); if (stdoutData.error.summary) { console.error(stdoutData.error?.summary); } if (stdoutData.error.detail) { console.error(stdoutData.error?.detail); } if (context.isVerbose) { console.error( `npm dist-tag add stdout: ${JSON.stringify(stdoutData, null, 2)}` ); } return { success: false }; } } catch (err2) { console.error( `Something unexpected went wrong when processing the npm dist-tag add output ${JSON.stringify(err2)}` ); return { success: false }; } } } catch (err) { let error = err; if (Buffer.isBuffer(error)) { error = error.toString(); } console.error("\n ********************** \n"); console.info(""); console.error( "An error occured trying to run the npm dist-tag add command." ); console.error(error); console.info(""); const stdoutData = JSON.parse(err.stdout?.toString() || "{}"); if (!(stdoutData.error?.code?.includes("E404") && stdoutData.error?.summary?.toLowerCase().includes("not found")) && !(err.stderr?.toString().includes("E404") && err.stderr?.toString().toLowerCase().includes("not found"))) { console.error( `Something unexpected went wrong when checking for existing dist-tags. Error: ${JSON.stringify(err)} ` ); return { success: false }; } } } try { const cwd = packageRoot; const command = npmPublishCommandSegments.join(" "); console.info( `Running publish command "${command}" in current working directory: "${cwd}" ` ); const result = execSync(command, { cwd, env: { ...process.env, FORCE_COLOR: "true" }, maxBuffer: LARGE_BUFFER, killSignal: "SIGTERM" }); if (isDryRun) { console.info( `Would publish to ${registry} with tag "${tag}", but [dry-run] was set ${result ? ` Execution response: ${result.toString()}` : ""} ` ); } else { console.info(`Published to ${registry} with tag "${tag}" ${result ? ` Execution response: ${result.toString()}` : ""} `); } return { success: true }; } catch (err) { try { console.error("\n ********************** \n"); console.info(""); console.error("An error occured running npm publish."); console.error("Please see below for more information:"); console.info(""); const stdoutData = JSON.parse(err.stdout?.toString() || "{}"); if (stdoutData.error.summary) { console.error(stdoutData.error.summary); console.error(stdoutData.error.summary); } if (stdoutData.error.detail) { console.error(stdoutData.error.detail); } if (context.isVerbose) { console.error( `npm publish stdout: ${JSON.stringify(stdoutData, null, 2)}` ); } console.error("\n ********************** \n"); return { success: false }; } catch (err2) { let error = err2; if (Buffer.isBuffer(error)) { error = error.toString(); } console.error( `Something unexpected went wrong when processing the npm publish output Error: ${JSON.stringify(error)} ` ); console.error("\n ********************** \n"); return { success: false }; } } } export { LARGE_BUFFER, npmPublishExecutorFn };