123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135 |
- "use strict";
- const fs = require("fs-extra");
- const path = require("path");
- const log = require("npmlog");
- const { publish } = require("libnpmpublish");
- const pify = require("pify");
- const readJSON = require("read-package-json");
- const { runLifecycle } = require("@lerna/run-lifecycle");
- const npa = require("npm-package-arg");
- const { otplease } = require("@lerna/otplease");
- module.exports.npmPublish = npmPublish;
- const readJSONAsync = pify(readJSON);
- /**
- * @typedef {object} NpmPublishOptions
- * @property {boolean} [dryRun]
- * @property {string} [tag] Passed to libnpmpublish as `opts.defaultTag` to preserve npm v6 back-compat
- */
- /**
- * Alias dash-cased npmConf to camelCase
- * @param {NpmPublishOptions} obj
- * @returns {NpmPublishOptions}
- */
- function flattenOptions(obj) {
- return {
- // eslint-disable-next-line dot-notation -- (npm v7 compat)
- defaultTag: obj["tag"] || "latest",
- dryRun: obj["dry-run"],
- ...obj,
- };
- }
- /**
- * @typedef {import('npm-registry-fetch').FetchOptions & { access?: 'public' | 'restricted'; defaultTag?: string; }} LibNpmPublishOptions https://github.com/npm/libnpmpublish#opts
- */
- /**
- * Publish a package to the configured registry.
- * @param {import("@lerna/package").Package} pkg
- * @param {string} tarFilePath
- * @param {LibNpmPublishOptions & NpmPublishOptions} [options]
- * @param {import("@lerna/otplease").OneTimePasswordCache} [otpCache]
- */
- function npmPublish(pkg, tarFilePath, options = {}, otpCache) {
- const { dryRun, ...remainingOptions } = flattenOptions(options);
- const { scope } = npa(pkg.name);
- // pass only the package scope to libnpmpublish
- const opts = {
- log,
- ...remainingOptions,
- projectScope: scope,
- };
- opts.log.verbose("publish", pkg.name);
- let chain = Promise.resolve();
- if (!dryRun) {
- chain = chain.then(() => {
- let { manifestLocation } = pkg;
- if (pkg.contents !== pkg.location) {
- // "rebase" manifest used to generated directory
- manifestLocation = path.join(pkg.contents, "package.json");
- }
- return Promise.all([fs.readFile(tarFilePath), readJSONAsync(manifestLocation)]);
- });
- chain = chain.then(([tarData, manifest]) => {
- // non-default tag needs to override publishConfig.tag,
- // which is merged into opts below if necessary
- if (
- opts.defaultTag !== "latest" &&
- manifest.publishConfig &&
- manifest.publishConfig.tag &&
- manifest.publishConfig.tag !== opts.defaultTag
- ) {
- // eslint-disable-next-line no-param-reassign
- manifest.publishConfig.tag = opts.defaultTag;
- }
- // publishConfig is no longer consumed in n-r-f, so merge here
- if (manifest.publishConfig) {
- Object.assign(opts, publishConfigToOpts(manifest.publishConfig));
- }
- return otplease((innerOpts) => publish(manifest, tarData, innerOpts), opts, otpCache).catch((err) => {
- opts.log.silly("", err);
- opts.log.error(err.code, (err.body && err.body.error) || err.message);
- // avoid dumping logs, this isn't a lerna problem
- err.name = "ValidationError";
- // ensure process exits non-zero
- process.exitCode = "errno" in err ? err.errno : 1;
- // re-throw to break chain upstream
- throw err;
- });
- });
- }
- chain = chain.then(() => runLifecycle(pkg, "publish", opts));
- chain = chain.then(() => runLifecycle(pkg, "postpublish", opts));
- return chain;
- }
- /**
- * @typedef {object} PackagePublishConfig
- * @property {'public' | 'restricted'} [access]
- * @property {string} [registry]
- * @property {string} [tag]
- */
- /**
- * Obtain an object suitable for assignment onto existing options from `pkg.publishConfig`.
- * @param {PackagePublishConfig} publishConfig
- * @returns {Omit<PackagePublishConfig, 'tag'> & { defaultTag?: string }}
- */
- function publishConfigToOpts(publishConfig) {
- const opts = { ...publishConfig };
- // npm v7 renamed tag internally
- if (publishConfig.tag) {
- opts.defaultTag = publishConfig.tag;
- delete opts.tag;
- }
- return opts;
- }
|