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
JavaScript
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
};