UNPKG

lerna

Version:

Lerna is a fast, modern build system for managing and publishing multiple JavaScript/TypeScript packages from the same repository

1,036 lines (1,027 loc) 37.3 kB
import { src_default } from "./chunk-TN6YF3FA.js"; import { getTwoFactorAuthRequired } from "./chunk-INUJPTDX.js"; import { removeTempLicenses } from "./chunk-EEBWF3UO.js"; import { verifyNpmPackageAccess } from "./chunk-OBPFTNQ3.js"; import { createTempLicenses } from "./chunk-WOINNVM2.js"; import { getCurrentSHA } from "./chunk-KFGPY7TY.js"; import { getCurrentTags } from "./chunk-YGM4W3QB.js"; import { getNpmUsername } from "./chunk-YXYXKZ5Q.js"; import { getPackagesWithoutLicense } from "./chunk-WGEG4Q2A.js"; import { Command, ValidationError, collectProjectUpdates, createRunner, describeRef, exec, getOneTimePassword, getPackage, gitCheckout, logPacked, npmConf, npmPublish, npm_dist_tag_exports, npmlog_default, output, packDirectory, prereleaseIdFromVersion, promptConfirmation, pulseTillDone, runProjectsTopologically, throwIfUncommitted } from "./chunk-WC2B4V4E.js"; // libs/commands/publish/src/index.ts import { workspaceRoot as workspaceRoot2 } from "@nx/devkit"; import fsExtra from "fs-extra"; import crypto from "node:crypto"; import fs, { existsSync } from "node:fs"; import { createRequire } from "node:module"; import os from "node:os"; import path, { basename, join, normalize } from "node:path"; import npa from "npm-package-arg"; import pMap2 from "p-map"; import semver from "semver"; import { glob } from "tinyglobby"; // libs/commands/publish/src/lib/get-projects-with-tagged-packages.ts async function getProjectsWithTaggedPackages(projectNodes, projectFileMap, execOpts) { npmlog_default.silly("getTaggedPackages", ""); const result = await exec( "git", ["diff-tree", "--name-only", "--no-commit-id", "--root", "-r", "-c", "HEAD"], execOpts ); const stdout = result.stdout; const files = new Set(stdout.split("\n")); return projectNodes.filter((node) => projectFileMap[node.name]?.some((file) => files.has(file.file))); } // libs/commands/publish/src/lib/get-projects-with-unpublished-packages.ts import pMap from "p-map"; import pacote from "pacote"; async function getProjectsWithUnpublishedPackages(projectNodes, opts) { npmlog_default.silly("getProjectsWithUnpublishedPackages", ""); const mapper = (node) => { const pkg = getPackage(node); opts["strictSSL"] = opts["strict-ssl"]; return pacote.packument(pkg.name, opts).then( (packument) => { if (packument.versions === void 0 || packument.versions[pkg.version] === void 0) { return node; } return void 0; }, () => { npmlog_default.warn("", "Unable to determine published version, assuming %j unpublished.", pkg.name); return node; } ); }; const results = await pMap(projectNodes, mapper, { concurrency: 4 }); return results.filter(Boolean); } // libs/commands/publish/src/lib/interpolate.ts import { workspaceRoot } from "@nx/devkit"; function interpolate(template, data) { const _workspaceRoot = process.env["NX_WORKSPACE_ROOT_PATH"] || workspaceRoot; if (template.includes("{workspaceRoot}", 1)) { throw new Error( `Config '${template}' is invalid. {workspaceRoot} can only be used at the beginning of the expression.` ); } if (data.projectRoot == "." && template.includes("{projectRoot}", 1)) { throw new Error( `Config '${template}' is invalid. When {projectRoot} is '.', it can only be used at the beginning of the expression.` ); } let res = template.replace("{workspaceRoot}", _workspaceRoot); if (data.projectRoot == ".") { res = res.replace("{projectRoot}/", ""); } return res.replace(/{([\s\S]+?)}/g, (match) => { let value = data; const path2 = match.slice(1, -1).trim().split("."); for (let idx = 0; idx < path2.length; idx++) { if (!value[path2[idx]]) { return match; } value = value[path2[idx]]; } return value; }); } // libs/commands/publish/src/lib/make-canary-version.ts function makeCanaryVersion(nextVersion, preid, refCount, sha) { return `${nextVersion}-${preid}.${Math.max(0, refCount - 1)}.sha-${sha}`; } // libs/commands/publish/src/lib/throttle-queue.ts var TailHeadQueue = class { queue_list; queue_size; queue_period; allowance; last_end; /** * @param size The number of items that may run concurrently * @param period The time between the end of the execution of an item and the start of the execution of the next one (ms) */ constructor(size, period) { this.queue_list = []; this.queue_size = Math.floor(size); this.queue_period = period; this.allowance = this.queue_size; this.last_end = []; } /** * Validate the execution of a queue item and schedule the execution of the next one */ _on_settled() { const next = this.queue_list.shift(); if (next !== void 0) { setTimeout(next, this.queue_period); } else { this.last_end.push(Date.now()); this.allowance += 1; } } async queue(f) { let p; if (this.allowance > 0) { this.allowance -= 1; if (this.allowance + 1 <= this.last_end.length) { const time_offset = Date.now() - (this.last_end.shift() || 0); if (time_offset < this.queue_period) { p = new Promise((r) => setTimeout(r, this.queue_period - time_offset)).then(f); } } if (p === void 0) { p = f(); } } else { p = new Promise((r) => { this.queue_list.push(r); }).then(f); } return p.finally(() => { this._on_settled(); }); } }; // libs/commands/publish/src/index.ts var require2 = createRequire(import.meta.url); function factory(argv) { return new PublishCommand(argv); } var PublishCommand = class extends Command { savePrefix; tagPrefix; gitReset; npmSession; verifyAccess; conf; otpCache; hasRootedLeaf; runPackageLifecycle; runRootLifecycle; updates; projectsWithPackage; updatesVersions; packagesToPublish; publishedPackages; privatePackagesToPublish; packagesToBeLicensed; twoFactorAuthRequired; uniqueProvenanceUrls = /* @__PURE__ */ new Set(); get otherCommandConfigs() { return ["version"]; } get requiresGit() { return this.options.bump !== "from-package"; } configureProperties() { super.configureProperties(); this.toposort = this.options.sort !== false; const { // prettier-ignore exact, gitHead, gitReset, tagVersionPrefix = "v", verifyAccess } = this.options; if (this.requiresGit && gitHead) { throw new ValidationError("EGITHEAD", "--git-head is only allowed with 'from-package' positional"); } this.savePrefix = exact ? "" : "^"; this.tagPrefix = tagVersionPrefix; this.gitReset = gitReset !== false; this.npmSession = crypto.randomBytes(8).toString("hex"); this.verifyAccess = verifyAccess; } get userAgent() { return `lerna/${this.options.lernaVersion}/node@${process.version}+${process.arch} (${process.platform})`; } async initialize() { if (this.options.verifyAccess === false) { this.logger.warn( "verify-access", "--verify-access=false and --no-verify-access are no longer needed, because the legacy preemptive access verification is now disabled by default. Requests will fail with appropriate errors when not authorized correctly." ); } if (this.options.includePrivate) { if (this.options.includePrivate.length === 0) { throw new ValidationError( "EINCLPRIV", "Must specify at least one private package to include with --include-private." ); } this.logger.info("publish", `Including private packages %j`, this.options.includePrivate); } if (this.options.skipNpm) { this.logger.warn("deprecated", "Instead of --skip-npm, call `lerna version` directly"); return src_default(this.argv).then(() => false); } if (this.options.buildMetadata && this.options.canary) { throw new ValidationError( "ENOTSATISFIED", "Cannot use --build-metadata in conjunction with --canary option." ); } else if (this.options.canary) { this.logger.info("canary", "enabled"); } if (this.options.requireScripts) { this.logger.info("require-scripts", "enabled"); } this.logger.verbose("session", this.npmSession); this.logger.verbose("user-agent", this.userAgent); this.conf = npmConf({ lernaCommand: "publish", _auth: this.options.legacyAuth, npmSession: this.npmSession, npmVersion: this.userAgent, otp: this.options.otp, registry: this.options.registry, "ignore-prepublish": this.options.ignorePrepublish, "ignore-scripts": this.options.ignoreScripts }); this.otpCache = { otp: this.conf["get"]("otp") }; this.conf["set"]("user-agent", this.userAgent, "cli"); if (this.conf["get"]("registry") === "https://registry.yarnpkg.com") { this.logger.warn("", "Yarn's registry proxy is broken, replacing with public npm registry"); this.logger.warn("", "If you don't have an npm token, you should exit and run `npm login`"); this.conf["set"]("registry", "https://registry.npmjs.org/", "cli"); } const distTag = this.getDistTag(); if (distTag) { this.conf["set"]("tag", distTag.trim(), "cli"); } this.hasRootedLeaf = !!this.projectGraph.nodes[this.project.manifest.name]; if (this.hasRootedLeaf) { this.logger.info("publish", "rooted leaf detected, skipping synthetic root lifecycles"); } this.runPackageLifecycle = createRunner(this.options); this.runRootLifecycle = /^(pre|post)?publish$/.test(process.env["npm_lifecycle_event"]) ? (stage) => { this.logger.warn("lifecycle", "Skipping root %j because it has already been called", stage); } : (stage) => this.runPackageLifecycle(this.project.manifest, stage); this.projectsWithPackage = Object.values(this.projectGraph.nodes).filter((node) => !!node.package); this.projectsWithPackage.map((node) => { const interpolateStr = (str) => { const res = interpolate(str, { projectRoot: node.data.root, projectName: node.name, workspaceRoot: this.project.rootPath }); this.logger.verbose( "silly", `Interpolated string "%s" for node "%s" to produce "%s"`, str, node.name, res ); return res; }; const pkg = getPackage(node); if (this.options.contents) { pkg.contents = this.options.contents; } if (pkg.lernaConfig?.command?.publish?.directory) { pkg.contents = interpolateStr(pkg.lernaConfig.command.publish.directory); } else if (this.project.config.command?.["publish"]?.["directory"]) { pkg.contents = interpolateStr(this.project.config.command["publish"]["directory"]); } if (pkg.lernaConfig?.command?.publish?.assets) { pkg.lernaConfig.command.publish.assets = pkg.lernaConfig.command.publish.assets.map( (asset) => interpolateAsset(asset, interpolateStr) ); } else if (this.project.config.command?.["publish"]?.["assets"]) { const assets = this.project.config.command?.["publish"]?.["assets"].map( (asset) => interpolateAsset(asset, interpolateStr) ); pkg.lernaConfig = pkg.lernaConfig || {}; pkg.lernaConfig.command = pkg.lernaConfig.command || {}; pkg.lernaConfig.command.publish = pkg.lernaConfig.command.publish || {}; pkg.lernaConfig.command.publish.assets = assets; } }); let result; if (this.options.bump === "from-git") { result = await this.detectFromGit(); } else if (this.options.bump === "from-package") { result = await this.detectFromPackage(); } else if (this.options.canary) { result = await this.detectCanaryVersions(); } else { result = await src_default(this.argv, { projectFileMap: this.projectFileMap, projectGraph: this.projectGraph }); } if (!result) { return false; } if (!result.updates.length) { this.logger.success("", "No changed packages to publish"); return false; } this.updates = this.filterPrivatePkgUpdates(result.updates); this.updatesVersions = new Map(result.updatesVersions); function interpolateAsset(asset, interpolationFn) { if (typeof asset === "string") { return interpolationFn(asset); } if (asset.from) { asset.from = interpolationFn(asset.from); } if (asset.to) { asset.to = interpolationFn(asset.to); } return asset; } this.packagesToPublish = this.updates.map((node) => getPackage(node)); if (result.needsConfirmation) { return this.confirmPublish(); } return true; } async execute() { this.enableProgressBar(); this.logger.info("publish", "Publishing packages to npm..."); await this.prepareRegistryActions(); await this.prepareLicenseActions(); this.preparePrivatePackages(); if (this.options.canary) { await this.updateCanaryVersions(); } await this.resolveLocalDependencyLinks(); await this.resolveWorkspaceDependencyLinks(); this.annotateGitHead(); await this.serializeChanges(); await this.packUpdated(); await this.publishPacked(); this.restorePrivatePackages(); await this.serializeChanges(); if (this.gitReset) { await this.resetChanges(); } if (this.options.tempTag) { await this.npmUpdateAsLatest(); } const count = this.publishedPackages.length; const publishedPackagesSorted = this.publishedPackages.sort((a, b) => a.name.localeCompare(b.name)); if (!count) { this.logger.success("", "All packages have already been published."); return; } output("Successfully published:"); if (this.options.summaryFile !== void 0) { const filePath = this.getSummaryFilePath(); const jsonObject = publishedPackagesSorted.map((pkg) => { return { packageName: pkg.name, version: pkg.version }; }); output(jsonObject); try { fs.writeFileSync(filePath, JSON.stringify(jsonObject)); output("Publish summary created: ", filePath); } catch (error) { output("Failed to create the summary report", error); } } else { const message = publishedPackagesSorted.map((pkg) => ` - ${pkg.name}@${pkg.version}`); output(message.join(os.EOL)); } this.logger.success("published", "%d %s", count, count === 1 ? "package" : "packages"); if (this.uniqueProvenanceUrls.size > 0) { output("The following provenance transparency log entries were created during publishing:"); const message = Array.from(this.uniqueProvenanceUrls).map((url) => ` - ${url}`); output(message.join(os.EOL)); } } verifyWorkingTreeClean() { return describeRef(this.execOpts).then(throwIfUncommitted); } async detectFromGit() { const matchingPattern = this.project.isIndependent() ? "*@*" : `${this.tagPrefix}*.*.*`; try { await this.verifyWorkingTreeClean(); } catch (err) { if (err.failed && /git describe/.test(err.command)) { this.logger.silly("EWORKINGTREE", err.message); this.logger.notice("FYI", "Unable to verify working tree, proceed at your own risk"); } else { throw err; } } const taggedPackageNames = await getCurrentTags(this.execOpts, matchingPattern); let updates; let updatesVersions; if (!taggedPackageNames.length) { this.logger.notice("from-git", "No tagged release found"); updates = []; } else if (this.project.isIndependent()) { updates = []; updatesVersions = []; taggedPackageNames.forEach((tag) => { const npaResult = npa(tag); const node = this.projectsWithPackage.find((node2) => getPackage(node2).name === npaResult.name); updates.push(node); updatesVersions.push([node.name, getPackage(node).version || npaResult.rawSpec]); }); } else { updates = await getProjectsWithTaggedPackages( this.projectsWithPackage, this.projectFileMap, this.execOpts ); updatesVersions = updates.map((node) => [node.name, getPackage(node).version]); } updates = this.filterPrivatePkgUpdates(updates); return { updates, updatesVersions, needsConfirmation: true }; } async detectFromPackage() { try { await this.verifyWorkingTreeClean(); } catch (err) { if (err.failed && /git describe/.test(err.command)) { this.logger.silly("EWORKINGTREE", err.message); this.logger.notice("FYI", "Unable to verify working tree, proceed at your own risk"); process.exitCode = 0; } else { throw err; } } let updates; updates = await getProjectsWithUnpublishedPackages(this.projectsWithPackage, this.conf["snapshot"]); updates = this.filterPrivatePkgUpdates(updates); if (!updates.length) { this.logger.notice("from-package", "No unpublished release found"); } const updatesVersions = updates.map((node) => [node.name, getPackage(node).version]); return { updates, updatesVersions, needsConfirmation: true }; } async detectCanaryVersions() { const { cwd } = this.execOpts; const { bump = "prepatch", preid = "alpha", ignoreChanges, forcePublish, includeMergedTags } = this.options; const release = bump.startsWith("pre") ? bump.replace("release", "patch") : `pre${bump}`; try { await this.verifyWorkingTreeClean(); } catch (err) { if (err.failed && /git describe/.test(err.command)) { this.logger.silly("EWORKINGTREE", err.message); this.logger.notice("FYI", "Unable to verify working tree, proceed at your own risk"); } else { throw err; } } const updates = this.filterPrivatePkgUpdates( collectProjectUpdates(this.projectsWithPackage, this.projectGraph, this.execOpts, { bump: "prerelease", canary: true, ignoreChanges, forcePublish, includeMergedTags }) ); const makeVersion = (fallback) => ({ lastVersion = fallback, refCount, sha }) => { const nextVersion = semver.inc( lastVersion.replace(this.tagPrefix, ""), release.replace("pre", "") ); return makeCanaryVersion(nextVersion, preid, refCount, sha); }; let updatesVersions; if (this.project.isIndependent()) { updatesVersions = await pMap2( updates, (node) => describeRef( { match: `${getPackage(node).name}@*`, cwd }, includeMergedTags ).then(makeVersion(getPackage(node).version)).then((version) => [node.name, version]) ); } else { updatesVersions = await describeRef( { match: `${this.tagPrefix}*.*.*`, cwd }, includeMergedTags ).then(makeVersion(this.project.version)).then((version) => updates.map((node) => [node.name, version])); } return { updates, updatesVersions, needsConfirmation: true }; } confirmPublish() { const count = this.updates.length; const message = this.updates.map((node) => { const pkg = getPackage(node); const version = this.updatesVersions.get(node.name); return ` - ${pkg.name} => ${version}${pkg.private ? " (private!)" : ""}`; }); output(""); output(`Found ${count} ${count === 1 ? "package" : "packages"} to publish:`); output(message.join(os.EOL)); output(""); if (this.options.yes) { this.logger.info("auto-confirmed", ""); return true; } return promptConfirmation("Are you sure you want to publish these packages?"); } preparePrivatePackages() { this.privatePackagesToPublish = []; this.packagesToPublish.forEach((pkg) => { if (pkg.private) { pkg.removePrivate(); this.privatePackagesToPublish.push(pkg); } }); } restorePrivatePackages() { this.privatePackagesToPublish.forEach((pkg) => { pkg.private = true; }); } async prepareLicenseActions() { const packagesWithoutLicense = await getPackagesWithoutLicense(this.project, this.packagesToPublish); if (packagesWithoutLicense.length && !this.project.licensePath) { this.packagesToBeLicensed = []; const names = packagesWithoutLicense.map((pkg) => pkg.name); const noun = names.length > 1 ? "Packages" : "Package"; const verb = names.length > 1 ? "are" : "is"; const list = names.length > 1 ? `${names.slice(0, -1).join(", ")}${names.length > 2 ? "," : ""} and ${names[names.length - 1]}` : names[0]; this.logger.warn( "ENOLICENSE", "%s %s %s missing a license.\n%s\n%s", noun, list, verb, "One way to fix this is to add a LICENSE.md file to the root of this repository.", "See https://choosealicense.com for additional guidance." ); } else { this.packagesToBeLicensed = packagesWithoutLicense; } } async prepareRegistryActions() { if (this.conf["get"]("registry") !== "https://registry.npmjs.org/") { this.logger.notice("", "Skipping all user and access validation due to third-party registry"); this.logger.notice("", "Make sure you're authenticated properly \xAF\\_(\u30C4)_/\xAF"); return; } if (process.env["LERNA_INTEGRATION"]) { return; } if (this.verifyAccess) { const username = await getNpmUsername(this.conf["snapshot"]); if (username) { await verifyNpmPackageAccess(this.packagesToPublish, username, this.conf["snapshot"]); } this.twoFactorAuthRequired = await getTwoFactorAuthRequired(this.conf["snapshot"]); } } async updateCanaryVersions() { await pMap2(this.updates, (node) => { const pkg = getPackage(node); pkg.set("version", this.updatesVersions.get(node.name)); const dependencies = this.projectGraph.localPackageDependencies[node.name] || []; dependencies.forEach((dep) => { const depPkg = getPackage(this.projectGraph.nodes[dep.target]); const depVersion = this.updatesVersions.get(dep.target) || depPkg.version; pkg.updateLocalDependency(dep.targetResolvedNpaResult, depVersion, this.savePrefix); }); }); } async resolveLocalDependencyLinks() { const updatesWithLocalLinks = this.updates.filter((node) => { const dependencies = this.projectGraph.localPackageDependencies[node.name] || []; return dependencies.some((dep) => dep.targetResolvedNpaResult.type === "directory"); }); await pMap2(updatesWithLocalLinks, (node) => { const pkg = getPackage(node); const dependencies = this.projectGraph.localPackageDependencies[node.name] || []; dependencies.forEach((dep) => { const depPkg = getPackage(this.projectGraph.nodes[dep.target]); const depVersion = this.updatesVersions.get(dep.target) || depPkg.version; pkg.updateLocalDependency(dep.targetResolvedNpaResult, depVersion, this.savePrefix); }); }); } async resolveWorkspaceDependencyLinks() { const updatesWithWorkspaceLinks = this.updates.filter((node) => { const dependencies = this.projectGraph.localPackageDependencies[node.name] || []; return dependencies.some((dep) => !!dep.targetResolvedNpaResult.workspaceSpec); }); await pMap2(updatesWithWorkspaceLinks, (node) => { const pkg = getPackage(node); const dependencies = this.projectGraph.localPackageDependencies[node.name] || []; dependencies.forEach((dep) => { const depPkg = getPackage(this.projectGraph.nodes[dep.target]); const resolved = dep.targetResolvedNpaResult; if (resolved.workspaceSpec) { let depVersion; let savePrefix; if (resolved.workspaceAlias) { depVersion = this.updatesVersions.get(dep.target) || depPkg.version; savePrefix = resolved.workspaceAlias === "*" ? "" : resolved.workspaceAlias; } else { const specMatch = resolved.workspaceSpec.match(/^workspace:([~^]?)(.*)/); savePrefix = specMatch[1]; depVersion = this.updatesVersions.get(dep.target) || depPkg.version; } pkg.updateLocalDependency(resolved, depVersion, savePrefix, { eraseWorkspacePrefix: true }); } }); }); } annotateGitHead() { try { const gitHead = this.options.gitHead || getCurrentSHA(this.execOpts); for (const pkg of this.packagesToPublish) { pkg.set("gitHead", gitHead); } } catch (err) { this.logger.silly("EGITHEAD", err.message); this.logger.notice( "FYI", "Unable to set temporary gitHead property, it will be missing from registry metadata" ); } } async serializeChanges() { await pMap2(this.packagesToPublish, (pkg) => pkg.serialize()); } async resetChanges() { const _workspaceRoot = process.env["NX_WORKSPACE_ROOT_PATH"] || workspaceRoot2; const gitOpts = { granularPathspec: this.options.granularPathspec !== false }; const dirtyManifests = [this.project.manifest].concat(this.packagesToPublish).map((pkg) => path.relative(_workspaceRoot, pkg.manifestLocation)); try { await gitCheckout(dirtyManifests, gitOpts, this.execOpts); } catch (err) { this.logger.silly("EGITCHECKOUT", err.message); this.logger.notice("FYI", "Unable to reset working tree changes, this probably isn't a git repo."); } } execScript(pkg, script) { const scriptLocation = path.join(pkg.location, "scripts", script); try { require2(scriptLocation); } catch (ex) { this.logger.silly("execScript", `No ${script} script found at ${scriptLocation}`); } return pkg; } async removeTempLicensesOnError() { await removeTempLicenses(this.packagesToBeLicensed).catch((removeError) => { this.logger.error( "licenses", "error removing temporary license files", removeError.stack || removeError ); }); } async requestOneTimePassword() { if (this.otpCache.otp) { return; } const otp = await getOneTimePassword("Enter OTP:"); this.otpCache.otp = otp; } topoMapPackages(mapper) { return runProjectsTopologically(this.updates, this.projectGraph, (node) => mapper(getPackage(node)), { concurrency: this.concurrency, rejectCycles: this.options.rejectCycles }); } async packUpdated() { const tracker = this.logger["newItem"]("npm pack"); tracker.addWork(this.packagesToPublish.length); await createTempLicenses(this.project.licensePath, this.packagesToBeLicensed); if (!this.hasRootedLeaf) { await this.runRootLifecycle("prepublish"); await this.runPackageLifecycle(this.project.manifest, "prepare"); await this.runPackageLifecycle(this.project.manifest, "prepublishOnly"); await this.runPackageLifecycle(this.project.manifest, "prepack"); } const opts = this.conf["snapshot"]; const packSteps = [ this.options.requireScripts && ((pkg) => this.execScript(pkg, "prepublish")), (pkg) => this.copyAssets(pkg).then(() => pkg), (pkg) => pulseTillDone(packDirectory(pkg, pkg.location, opts)).then((packed) => { tracker.verbose("packed", path.relative(this.project.rootPath, pkg.contents)); tracker.completeWork(1); pkg.packed = packed; return pkg.refresh(); }) ].filter(Boolean); const mapper = async (pkg) => { let result = pkg; for (const step of packSteps) { result = await step(result); } return result; }; if (this.toposort) { await this.topoMapPackages(mapper).catch((err) => { this.removeTempLicensesOnError(); throw err; }); } else { await pMap2(this.packagesToPublish, mapper, { concurrency: this.concurrency }); } await removeTempLicenses(this.packagesToBeLicensed); if (!this.hasRootedLeaf) { await this.runPackageLifecycle(this.project.manifest, "postpack"); } tracker.finish(); } async publishPacked() { this.publishedPackages = []; const tracker = this.logger["newItem"]("publish"); tracker.addWork(this.packagesToPublish.length); let chain = Promise.resolve(); if (this.twoFactorAuthRequired) { chain = chain.then(() => this.requestOneTimePassword()); } const opts = Object.assign(this.conf["snapshot"], { // distTag defaults to "latest" OR whatever is in pkg.publishConfig.tag // if we skip temp tags we should tag with the proper value immediately tag: this.options.tempTag ? "lerna-temp" : this.conf["get"]("tag") }); const logListener = (...args) => { const str = args.join(" "); if (str.toLowerCase().includes("provenance statement") && str.includes("https://")) { const url = str.match(/https:\/\/[^ ]+/)[0]; this.uniqueProvenanceUrls.add(url); } }; process.on("log", logListener); let queue = void 0; if (this.options.throttle) { const DEFAULT_QUEUE_THROTTLE_SIZE = 25; const DEFAULT_QUEUE_THROTTLE_DELAY = 30; queue = new TailHeadQueue( this.options.throttleSize !== void 0 ? this.options.throttleSize : DEFAULT_QUEUE_THROTTLE_SIZE, (this.options.throttleDelay !== void 0 ? this.options.throttleDelay : DEFAULT_QUEUE_THROTTLE_DELAY) * 1e3 ); } const publishSteps = [ (pkg) => { const preDistTag = this.getPreDistTag(pkg); const tag = !this.options.tempTag && preDistTag ? preDistTag : opts.tag; const pkgOpts = Object.assign({}, opts, { tag }); return pulseTillDone( queue ? queue.queue(() => npmPublish(pkg, pkg.packed.tarFilePath, pkgOpts, this.conf, this.otpCache)) : npmPublish(pkg, pkg.packed.tarFilePath, pkgOpts, this.conf, this.otpCache) ).then(() => { this.publishedPackages.push(pkg); tracker.success("published", pkg.name, pkg.version); tracker.completeWork(1); logPacked(pkg.packed); return pkg; }).catch((err) => { if (err.code === "E409" || err.code === "EPUBLISHCONFLICT" || err.code === "E403" && err.body?.error?.includes("You cannot publish over the previously published versions")) { tracker.warn("publish", `Package is already published: ${pkg.name}@${pkg.version}`); tracker.completeWork(1); return pkg; } this.logger.silly("", err); this.logger.warn("notice", `Package failed to publish: ${pkg.name}`); this.logger.error(err.code, err.body && err.body.error || err.message); err.name = "ValidationError"; if ("errno" in err && typeof err.errno === "number" && Number.isFinite(err.errno)) { process.exitCode = err.errno; } else { this.logger.error("", `errno "${err.errno}" is not a valid exit code - exiting with code 1`); process.exitCode = 1; } throw err; }); }, this.options.requireScripts && ((pkg) => this.execScript(pkg, "postpublish")) ].filter(Boolean); const mapper = async (pkg) => { let result = pkg; for (const step of publishSteps) { result = await step(result); } return result; }; chain = chain.then(() => { if (this.toposort) { return this.topoMapPackages(mapper); } else { return pMap2(this.packagesToPublish, mapper, { concurrency: this.concurrency }); } }); if (!this.hasRootedLeaf) { chain = chain.then(() => this.runRootLifecycle("publish")); chain = chain.then(() => this.runRootLifecycle("postpublish")); } return chain.finally(() => { process.removeListener("log", logListener); tracker.finish(); }); } async npmUpdateAsLatest() { const tracker = this.logger["newItem"]("npmUpdateAsLatest"); tracker.addWork(this.updates.length); tracker.showProgress(); const opts = this.conf["snapshot"]; const getDistTag = (publishConfig) => { if (opts.tag === "latest" && publishConfig && publishConfig.tag) { return publishConfig.tag; } return opts.tag; }; const mapper = (pkg) => { const spec = `${pkg.name}@${pkg.version}`; const preDistTag = this.getPreDistTag(pkg); const distTag = preDistTag || getDistTag(pkg.get("publishConfig")); return Promise.resolve().then(() => pulseTillDone(npm_dist_tag_exports.remove(spec, "lerna-temp", opts, this.otpCache))).then(() => pulseTillDone(npm_dist_tag_exports.add(spec, distTag, opts, this.otpCache))).then(() => { tracker.success("dist-tag", "%s@%s => %j", pkg.name, pkg.version, distTag); tracker.completeWork(1); return pkg; }); }; if (this.toposort) { await this.topoMapPackages(mapper); } else { await pMap2(this.packagesToPublish, mapper, { concurrency: this.concurrency }); } tracker.finish(); } getDistTag() { if (this.options.distTag) { return this.options.distTag; } if (this.options.canary) { return "canary"; } return void 0; } getPreDistTag(pkg) { if (!this.options.preDistTag) { return; } const isPrerelease = prereleaseIdFromVersion(pkg.version); if (isPrerelease) { return this.options.preDistTag; } return void 0; } // filter out private packages, respecting the --include-private option filterPrivatePkgUpdates(updates) { const privatePackagesToInclude = new Set(this.options.includePrivate || []); return updates.filter( (node) => !getPackage(node).private || privatePackagesToInclude.has("*") || privatePackagesToInclude.has(getPackage(node).name) ); } async copyAssets(pkg) { if (!pkg.lernaConfig?.command?.publish?.assets) { return; } if (normalize(pkg.location) === normalize(pkg.contents)) { return; } const _workspaceRoot = process.env["NX_WORKSPACE_ROOT_PATH"] || workspaceRoot2; const assets = pkg.lernaConfig?.command?.publish?.assets; const filesToCopy = []; const getFiles = (assetGlob) => glob(assetGlob, { cwd: pkg.location, onlyFiles: false, expandDirectories: false }); for (const asset of assets) { if (typeof asset === "string") { const files = await getFiles(asset); this.logger.verbose("publish", "Expanded asset glob %s into files %j", asset, files); for (const file of files) { filesToCopy.push({ from: join(pkg.location, file), to: join(pkg.contents, file) }); } } else if (asset.from && typeof asset.from === "string" && asset.to && typeof asset.to === "string") { const files = await getFiles(asset.from); this.logger.verbose("publish", "Expanded asset glob %s into files %j", asset.from, files); for (const file of files) { filesToCopy.push({ from: join(pkg.location, file), to: join(pkg.contents, asset.to, basename(file)) }); } } else { throw new ValidationError( "EINVALIDASSETS", "Asset configuration must be a plain string or object with both `from` and `to` string properties." ); } } for (const file of filesToCopy) { if (normalize(file.from) === normalize(file.to)) { this.logger.warn( "EPUBLISHASSET", "Asset %s is already in package directory", file.from.replace(`${_workspaceRoot}/`, "") ); } else if (existsSync(file.from)) { this.logger.verbose( "publish", "Copying asset %s to %s", file.from.replace(`${_workspaceRoot}/`, ""), file.to.replace(`${_workspaceRoot}/`, "") ); await fsExtra.copy(file.from, file.to); } else { this.logger.warn( "EPUBLISHASSET", "Asset %s does not exist", file.from.replace(`${_workspaceRoot}/`, "") ); } } } getSummaryFilePath() { if (this.options.summaryFile === void 0) { throw new Error("summaryFile options is not defined. Unable to get path."); } if (this.options.summaryFile === "") { return path.join(process.cwd(), "./lerna-publish-summary.json"); } const normalizedPath = path.normalize(this.options.summaryFile); if (normalizedPath === "") { throw new Error("summaryFile is not a valid path."); } if (normalizedPath.endsWith(".json")) { return path.join(process.cwd(), normalizedPath); } return path.join(process.cwd(), normalizedPath, "lerna-publish-summary.json"); } }; var commonJsExport = Object.assign(factory, { PublishCommand }); var src_default2 = commonJsExport; export { factory, PublishCommand, commonJsExport, src_default2 as src_default };