@lerna-lite/publish 1.16.1 → 1.16.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/dist/index.d.ts +3 -3
  2. package/dist/index.js +6 -6
  3. package/dist/lib/create-temp-licenses.d.ts +7 -7
  4. package/dist/lib/create-temp-licenses.js +30 -30
  5. package/dist/lib/fetch-config.d.ts +10 -10
  6. package/dist/lib/fetch-config.js +19 -19
  7. package/dist/lib/get-current-sha.d.ts +6 -6
  8. package/dist/lib/get-current-sha.js +17 -17
  9. package/dist/lib/get-current-tags.d.ts +8 -8
  10. package/dist/lib/get-current-tags.js +32 -32
  11. package/dist/lib/get-npm-username.d.ts +7 -7
  12. package/dist/lib/get-npm-username.js +52 -52
  13. package/dist/lib/get-packages-without-license.d.ts +8 -8
  14. package/dist/lib/get-packages-without-license.js +20 -20
  15. package/dist/lib/get-packed.d.ts +3 -3
  16. package/dist/lib/get-packed.js +63 -63
  17. package/dist/lib/get-profile-data.d.ts +7 -7
  18. package/dist/lib/get-profile-data.js +20 -20
  19. package/dist/lib/get-tagged-packages.d.ts +9 -9
  20. package/dist/lib/get-tagged-packages.js +26 -26
  21. package/dist/lib/get-two-factor-auth-required.d.ts +7 -7
  22. package/dist/lib/get-two-factor-auth-required.js +42 -42
  23. package/dist/lib/get-unpublished-packages.d.ts +8 -8
  24. package/dist/lib/get-unpublished-packages.js +34 -34
  25. package/dist/lib/get-whoami.d.ts +11 -11
  26. package/dist/lib/get-whoami.js +18 -18
  27. package/dist/lib/git-checkout.d.ts +10 -10
  28. package/dist/lib/git-checkout.js +18 -18
  29. package/dist/lib/index.d.ts +19 -19
  30. package/dist/lib/index.js +22 -22
  31. package/dist/lib/log-packed.d.ts +5 -5
  32. package/dist/lib/log-packed.js +70 -70
  33. package/dist/lib/npm-dist-tag.d.ts +33 -33
  34. package/dist/lib/npm-dist-tag.js +137 -137
  35. package/dist/lib/npm-publish.d.ts +11 -11
  36. package/dist/lib/npm-publish.js +93 -93
  37. package/dist/lib/override-publish-config.d.ts +6 -6
  38. package/dist/lib/override-publish-config.js +43 -43
  39. package/dist/lib/pack-directory.d.ts +9 -9
  40. package/dist/lib/pack-directory.js +67 -67
  41. package/dist/lib/remove-temp-licenses.d.ts +6 -6
  42. package/dist/lib/remove-temp-licenses.js +17 -17
  43. package/dist/lib/verify-npm-package-access.d.ts +9 -9
  44. package/dist/lib/verify-npm-package-access.js +53 -53
  45. package/dist/models/index.d.ts +34 -34
  46. package/dist/models/index.js +2 -2
  47. package/dist/publish-command.d.ts +74 -74
  48. package/dist/publish-command.js +781 -781
  49. package/package.json +4 -4
@@ -1,782 +1,782 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.PublishCommand = exports.factory = void 0;
4
- const tslib_1 = require("tslib");
5
- const chalk_1 = tslib_1.__importDefault(require("chalk"));
6
- const glob_1 = tslib_1.__importDefault(require("glob"));
7
- const fs_extra_1 = tslib_1.__importDefault(require("fs-extra"));
8
- const os_1 = tslib_1.__importDefault(require("os"));
9
- const path_1 = tslib_1.__importDefault(require("path"));
10
- const crypto_1 = tslib_1.__importDefault(require("crypto"));
11
- const p_map_1 = tslib_1.__importDefault(require("p-map"));
12
- const p_pipe_1 = tslib_1.__importDefault(require("p-pipe"));
13
- const semver_1 = tslib_1.__importDefault(require("semver"));
14
- const temp_dir_1 = tslib_1.__importDefault(require("temp-dir"));
15
- const version_1 = require("@lerna-lite/version");
16
- const core_1 = require("@lerna-lite/core");
17
- const get_current_tags_1 = require("./lib/get-current-tags");
18
- const get_tagged_packages_1 = require("./lib/get-tagged-packages");
19
- const get_unpublished_packages_1 = require("./lib/get-unpublished-packages");
20
- const get_npm_username_1 = require("./lib/get-npm-username");
21
- const verify_npm_package_access_1 = require("./lib/verify-npm-package-access");
22
- const get_two_factor_auth_required_1 = require("./lib/get-two-factor-auth-required");
23
- const get_current_sha_1 = require("./lib/get-current-sha");
24
- const git_checkout_1 = require("./lib/git-checkout");
25
- const pack_directory_1 = require("./lib/pack-directory");
26
- const npm_publish_1 = require("./lib/npm-publish");
27
- const log_packed_1 = require("./lib/log-packed");
28
- const npm_dist_tag_1 = require("./lib/npm-dist-tag");
29
- const override_publish_config_1 = require("./lib/override-publish-config");
30
- const remove_temp_licenses_1 = require("./lib/remove-temp-licenses");
31
- const create_temp_licenses_1 = require("./lib/create-temp-licenses");
32
- const get_packages_without_license_1 = require("./lib/get-packages-without-license");
33
- function factory(argv) {
34
- return new PublishCommand(argv);
35
- }
36
- exports.factory = factory;
37
- class PublishCommand extends core_1.Command {
38
- get otherCommandConfigs() {
39
- // back-compat
40
- return ['version'];
41
- }
42
- get requiresGit() {
43
- // `lerna publish from-package` doesn't _need_ git, per se
44
- return this.options.bump !== 'from-package';
45
- }
46
- constructor(argv) {
47
- super(argv);
48
- /** command name */
49
- this.name = 'publish';
50
- this.gitReset = false;
51
- this.savePrefix = '';
52
- this.tagPrefix = '';
53
- this.hasRootedLeaf = false;
54
- this.npmSession = '';
55
- this.packagesToPublish = [];
56
- this.publishedPackages = [];
57
- this.packagesToBeLicensed = [];
58
- this.verifyAccess = false;
59
- this.toposort = false;
60
- this.twoFactorAuthRequired = false;
61
- this.updates = [];
62
- }
63
- configureProperties() {
64
- super.configureProperties();
65
- // For publish we want to enable topological sorting by default, but allow users to override with --no-sort
66
- this.toposort = this.options.sort !== false;
67
- // Defaults are necessary here because yargs defaults
68
- // override durable options provided by a config file
69
- const {
70
- // prettier-ignore
71
- exact, gitHead, gitReset, tagVersionPrefix = 'v', verifyAccess, } = this.options;
72
- if (this.requiresGit && gitHead) {
73
- throw new core_1.ValidationError('EGITHEAD', '--git-head is only allowed with "from-package" positional');
74
- }
75
- // https://docs.npmjs.com/misc/config#save-prefix
76
- this.savePrefix = exact ? '' : '^';
77
- // https://docs.npmjs.com/misc/config#tag-version-prefix
78
- this.tagPrefix = tagVersionPrefix;
79
- // TODO: properly inherit from npm-conf
80
- // inverted boolean options are only respected if prefixed with `--no-`, e.g. `--no-verify-access`
81
- this.gitReset = gitReset !== false;
82
- // consumed by npm-registry-fetch (via libnpmpublish)
83
- this.npmSession = crypto_1.default.randomBytes(8).toString('hex');
84
- this.verifyAccess = verifyAccess;
85
- }
86
- get userAgent() {
87
- // consumed by npm-registry-fetch (via libnpmpublish)
88
- return `lerna/${this.options.lernaVersion}/node@${process.version}+${process.arch} (${process.platform})`;
89
- }
90
- initialize() {
91
- if (this.options.verifyAccess === false) {
92
- 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.');
93
- }
94
- if (this.options.graphType === 'dependencies') {
95
- this.logger.warn('graph-type', '--graph-type=dependencies is deprecated and will be removed in the next major version of lerna-lite. If you have a use-case you feel requires it please open an issue to discuss: https://github.com/lerna/lerna/issues/new/choose');
96
- }
97
- if (this.options.workspaceStrictMatch === false) {
98
- this.logger.warn('deprecation', 'Providing --no-workspace-strict-match is deprecated and will be removed in future version, we will make "workspace:" protocol strict matching in every case.');
99
- }
100
- if (this.options.buildMetadata && this.options.canary) {
101
- throw new core_1.ValidationError('ENOTSATISFIED', 'Cannot use --build-metadata in conjunction with --canary option.');
102
- }
103
- else if (this.options.canary) {
104
- this.logger.info('canary', 'enabled');
105
- }
106
- // @deprecated, to be removed in next major
107
- if (this.options.requireScripts) {
108
- this.logger.info('require-scripts', 'enabled');
109
- }
110
- // npmSession and user-agent are consumed by npm-registry-fetch (via libnpmpublish)
111
- this.logger.verbose('session', this.npmSession);
112
- this.logger.verbose('user-agent', this.userAgent);
113
- this.conf = (0, core_1.npmConf)({
114
- lernaCommand: 'publish',
115
- _auth: this.options.legacyAuth,
116
- npmSession: this.npmSession,
117
- npmVersion: this.userAgent,
118
- otp: this.options.otp,
119
- registry: this.options.registry,
120
- 'ignore-prepublish': this.options.ignorePrepublish,
121
- 'ignore-scripts': this.options.ignoreScripts,
122
- });
123
- // cache to hold a one-time-password across publishes
124
- this.otpCache = { otp: this.conf.get('otp') };
125
- this.conf.set('user-agent', this.userAgent, 'cli');
126
- if (this.conf.get('registry') === 'https://registry.yarnpkg.com') {
127
- this.logger.warn('', `Yarn's registry proxy is broken, replacing with public npm registry`);
128
- this.logger.warn('', `If you don't have an npm token, you should exit and run "npm login"`);
129
- this.conf.set('registry', 'https://registry.npmjs.org/', 'cli');
130
- }
131
- // inject --dist-tag into opts, if present
132
- const distTag = this.getDistTag();
133
- if (distTag) {
134
- this.conf.set('tag', distTag.trim(), 'cli');
135
- }
136
- // a 'rooted leaf' is the regrettable pattern of adding '.' to the 'packages' config in lerna.json
137
- this.hasRootedLeaf = this.packageGraph.has(this.project.manifest.name);
138
- if (this.hasRootedLeaf) {
139
- this.logger.info('publish', 'rooted leaf detected, skipping synthetic root lifecycles');
140
- }
141
- this.runPackageLifecycle = (0, core_1.createRunner)(this.options);
142
- // don't execute recursively if run from a poorly-named script
143
- this.runRootLifecycle = /^(pre|post)?publish$/.test(process.env.npm_lifecycle_event || '')
144
- ? (stage) => this.logger.warn('lifecycle', 'Skipping root %j because it has already been called', stage)
145
- : (stage) => this.runPackageLifecycle(this.project.manifest, stage);
146
- let chain = Promise.resolve();
147
- if (this.options.bump === 'from-git') {
148
- chain = chain.then(() => this.detectFromGit());
149
- }
150
- else if (this.options.bump === 'from-package') {
151
- chain = chain.then(() => this.detectFromPackage());
152
- }
153
- else if (this.options.canary) {
154
- chain = chain.then(() => this.detectCanaryVersions());
155
- }
156
- else {
157
- chain = chain.then(() => new version_1.VersionCommand(this.argv));
158
- }
159
- return chain.then((result) => {
160
- if (!result) {
161
- // early return from nested VersionCommand
162
- return false;
163
- }
164
- if (!result.updates.length) {
165
- this.logger.success('No changed packages to publish');
166
- // still exits zero, aka 'ok'
167
- return false;
168
- }
169
- // (occasionally) redundant private filtering necessary to handle nested VersionCommand
170
- this.updates = result.updates.filter((node) => !node.pkg.private);
171
- this.updatesVersions = new Map(result.updatesVersions);
172
- this.packagesToPublish = this.updates.map((node) => node.pkg);
173
- if (this.options.contents) {
174
- // globally override directory to publish
175
- for (const pkg of this.packagesToPublish) {
176
- pkg.contents = this.options.contents;
177
- }
178
- }
179
- if (result.needsConfirmation) {
180
- // only confirm for --canary, bump === 'from-git',
181
- // or bump === 'from-package', as VersionCommand
182
- // has its own confirmation prompt
183
- return this.confirmPublish();
184
- }
185
- return true;
186
- });
187
- }
188
- async execute() {
189
- var _a;
190
- this.enableProgressBar();
191
- this.logger.info('publish', 'Publishing packages to npm...');
192
- await this.prepareRegistryActions();
193
- await this.prepareLicenseActions();
194
- if (this.options.canary) {
195
- await this.updateCanaryVersions();
196
- }
197
- await this.resolveLocalDependencyLinks();
198
- await this.resolveLocalDependencyWorkspaceProtocols();
199
- if (this.options.removePackageFields) {
200
- await this.removePackageProperties();
201
- }
202
- if (this.options.publishConfigOverrides !== false) {
203
- await this.applyPublishConfigOverrides();
204
- }
205
- await this.annotateGitHead();
206
- await this.serializeChanges();
207
- await this.packUpdated();
208
- await this.publishPacked();
209
- if (this.gitReset) {
210
- await this.resetChanges();
211
- }
212
- if (this.options.tempTag) {
213
- await this.npmUpdateAsLatest();
214
- }
215
- const count = (_a = this.publishedPackages) === null || _a === void 0 ? void 0 : _a.length;
216
- const publishedPackagesSorted = this.publishedPackages.sort((a, b) => a.name.localeCompare(b.name));
217
- if (!count) {
218
- this.logger.success('All packages have already been published.');
219
- return;
220
- }
221
- (0, core_1.logOutput)('Successfully published:');
222
- if (this.options.summaryFile !== undefined) {
223
- // create a json object and output it to a file location.
224
- const filePath = this.options.summaryFile
225
- ? `${this.options.summaryFile}/lerna-publish-summary.json`
226
- : './lerna-publish-summary.json';
227
- const jsonObject = publishedPackagesSorted.map((pkg) => {
228
- return {
229
- packageName: pkg.name,
230
- version: pkg.version,
231
- };
232
- });
233
- (0, core_1.logOutput)(jsonObject);
234
- try {
235
- fs_extra_1.default.outputFileSync(filePath, JSON.stringify(jsonObject));
236
- (0, core_1.logOutput)('Publish summary created: ', filePath);
237
- }
238
- catch (error) {
239
- (0, core_1.logOutput)('Failed to create the summary report', error);
240
- }
241
- }
242
- else {
243
- const message = publishedPackagesSorted.map((pkg) => ` - ${pkg.name}@${pkg.version}`);
244
- (0, core_1.logOutput)(message.join(os_1.default.EOL));
245
- }
246
- // optionally cleanup temp packed files after publish, opt-in option
247
- if (this.options.cleanupTempFiles) {
248
- (0, glob_1.default)(path_1.default.join(temp_dir_1.default, '/lerna-*'), (_err, deleteFolders) => {
249
- // delete silently all files/folders that startsWith "lerna-"
250
- deleteFolders.forEach((folder) => fs_extra_1.default.removeSync(folder));
251
- this.logger.verbose('publish', `Found ${deleteFolders.length} temp folders to cleanup after publish.`);
252
- });
253
- }
254
- this.logger.success('published', '%d %s', count, count === 1 ? 'package' : 'packages');
255
- }
256
- verifyWorkingTreeClean() {
257
- return (0, core_1.describeRef)(this.execOpts, undefined, this.options.dryRun).then(core_1.throwIfUncommitted);
258
- }
259
- detectFromGit() {
260
- const matchingPattern = this.project.isIndependent() ? `*@*` : `${this.tagPrefix}*.*.*`;
261
- let chain = Promise.resolve();
262
- // attempting to publish a tagged release with local changes is not allowed
263
- chain = chain.then(() => this.verifyWorkingTreeClean());
264
- chain = chain.then(() => (0, get_current_tags_1.getCurrentTags)(this.execOpts, matchingPattern));
265
- chain = chain.then((taggedPackageNames) => {
266
- if (!taggedPackageNames.length) {
267
- this.logger.notice('from-git', 'No tagged release found. You might not have fetched tags.');
268
- return [];
269
- }
270
- if (this.project.isIndependent()) {
271
- return taggedPackageNames.map((name) => this.packageGraph.get(name));
272
- }
273
- return (0, get_tagged_packages_1.getTaggedPackages)(this.packageGraph, this.project.rootPath, this.execOpts);
274
- });
275
- // private packages are never published, full stop.
276
- chain = chain.then((updates) => updates.filter((node) => !node.pkg.private));
277
- return chain.then((updates) => {
278
- const updatesVersions = updates.map((node) => [node.name, node.version]);
279
- return {
280
- updates,
281
- updatesVersions,
282
- needsConfirmation: true,
283
- };
284
- });
285
- }
286
- detectFromPackage() {
287
- let chain = Promise.resolve();
288
- // attempting to publish a release with local changes is not allowed
289
- chain = chain
290
- .then(() => this.verifyWorkingTreeClean())
291
- .catch((err) => {
292
- // an execa error is thrown when git suffers a fatal error (such as no git repository present)
293
- if (err.failed && /git describe/.test(err.command)) {
294
- // (we tried)
295
- this.logger.silly('EWORKINGTREE', err.message);
296
- this.logger.notice('FYI', 'Unable to verify working tree, proceed at your own risk');
297
- process.exitCode = 0;
298
- }
299
- else {
300
- // validation errors should be preserved
301
- throw err;
302
- }
303
- });
304
- // private packages are already omitted by getUnpublishedPackages()
305
- chain = chain.then(() => (0, get_unpublished_packages_1.getUnpublishedPackages)(this.packageGraph, this.conf.snapshot));
306
- chain = chain.then((unpublished) => {
307
- if (!unpublished.length) {
308
- this.logger.notice('from-package', 'No unpublished release found');
309
- }
310
- return unpublished;
311
- });
312
- return chain.then((updates) => {
313
- const updatesVersions = updates.map((node) => [node.name, node.version]);
314
- return {
315
- updates,
316
- updatesVersions,
317
- needsConfirmation: true,
318
- };
319
- });
320
- }
321
- detectCanaryVersions() {
322
- const { cwd } = this.execOpts;
323
- const { bump = 'prepatch', preid = 'alpha', ignoreChanges, forcePublish, includeMergedTags } = this.options;
324
- // 'prerelease' and 'prepatch' are identical, for our purposes
325
- const release = bump.startsWith('pre') ? bump.replace('release', 'patch') : `pre${bump}`;
326
- let chain = Promise.resolve();
327
- // attempting to publish a canary release with local changes is not allowed
328
- chain = chain
329
- .then(() => this.verifyWorkingTreeClean())
330
- .catch((err) => {
331
- // an execa error is thrown when git suffers a fatal error (such as no git repository present)
332
- if (err.failed && /git describe/.test(err.command)) {
333
- // (we tried)
334
- this.logger.silly('EWORKINGTREE', err.message);
335
- this.logger.notice('FYI', 'Unable to verify working tree, proceed at your own risk');
336
- }
337
- else {
338
- // validation errors should be preserved
339
- throw err;
340
- }
341
- });
342
- const isIndependent = this.project.isIndependent();
343
- // find changed packages since last release, if any
344
- chain = chain.then(() => {
345
- var _a, _b;
346
- return (0, core_1.collectUpdates)((_b = (_a = this.packageGraph) === null || _a === void 0 ? void 0 : _a.rawPackageList) !== null && _b !== void 0 ? _b : [], this.packageGraph, this.execOpts, {
347
- bump: 'prerelease',
348
- canary: true,
349
- ignoreChanges,
350
- forcePublish,
351
- includeMergedTags,
352
- isIndependent,
353
- // private packages are never published, don't bother describing their refs.
354
- }, this.options.dryRun).filter((node) => !node.pkg.private);
355
- });
356
- // prettier-ignore
357
- const makeVersion = (fallback) => ({ lastVersion = fallback, refCount, sha }) => {
358
- // the next version is bumped without concern for preid or current index
359
- // prettier-ignore
360
- const nextVersion = semver_1.default.inc(lastVersion.replace(this.tagPrefix, ''), release.replace('pre', ''));
361
- // semver.inc() starts a new prerelease at .0, git describe starts at .1
362
- // and build metadata is always ignored when comparing dependency ranges
363
- return `${nextVersion}-${preid}.${Math.max(0, refCount - 1)}+${sha}`;
364
- };
365
- if (isIndependent) {
366
- // each package is described against its tags only
367
- chain = chain.then((updates) => (0, p_map_1.default)(updates, (node) => (0, core_1.describeRef)({
368
- match: `${node.name}@*`,
369
- cwd,
370
- }, includeMergedTags, this.options.dryRun)
371
- // an unpublished package will have no reachable git tag
372
- .then(makeVersion(node.version))
373
- .then((version) => [node.name, version])).then((updatesVersions) => ({
374
- updates,
375
- updatesVersions,
376
- })));
377
- }
378
- else {
379
- // all packages are described against the last tag
380
- chain = chain.then((updates) => (0, core_1.describeRef)({
381
- match: `${this.tagPrefix}*.*.*`,
382
- cwd,
383
- }, includeMergedTags, this.options.dryRun)
384
- // a repo with no tags should default to whatever lerna.json claims
385
- .then(makeVersion(this.project.version))
386
- .then((version) => updates.map((node) => [node.name, version]))
387
- .then((updatesVersions) => ({
388
- updates,
389
- updatesVersions,
390
- })));
391
- }
392
- return chain.then(({ updates, updatesVersions }) => ({
393
- updates,
394
- updatesVersions,
395
- needsConfirmation: true,
396
- }));
397
- }
398
- confirmPublish() {
399
- var _a, _b, _c;
400
- const count = (_a = this.packagesToPublish) === null || _a === void 0 ? void 0 : _a.length;
401
- const message = (_c = (_b = this.packagesToPublish) === null || _b === void 0 ? void 0 : _b.map((pkg) => { var _a; return ` - ${pkg.name} => ${(_a = this.updatesVersions) === null || _a === void 0 ? void 0 : _a.get(pkg.name)}`; })) !== null && _c !== void 0 ? _c : [];
402
- (0, core_1.logOutput)('');
403
- (0, core_1.logOutput)(`Found ${count} ${count === 1 ? 'package' : 'packages'} to publish:`);
404
- (0, core_1.logOutput)(message.join(os_1.default.EOL));
405
- (0, core_1.logOutput)('');
406
- if (this.options.yes) {
407
- this.logger.info('auto-confirmed', '');
408
- return true;
409
- }
410
- let confirmMessage = this.options.dryRun ? chalk_1.default.bgMagenta('[dry-run]') : '';
411
- confirmMessage += ' Are you sure you want to publish these packages?';
412
- return (0, core_1.promptConfirmation)(confirmMessage.trim());
413
- }
414
- prepareLicenseActions() {
415
- return Promise.resolve()
416
- .then(() => { var _a; return (0, get_packages_without_license_1.getPackagesWithoutLicense)(this.project, (_a = this.packagesToPublish) !== null && _a !== void 0 ? _a : []); })
417
- .then((packagesWithoutLicense) => {
418
- if (packagesWithoutLicense.length && !this.project.licensePath) {
419
- this.packagesToBeLicensed = [];
420
- const names = packagesWithoutLicense.map((pkg) => pkg.name);
421
- const noun = names.length > 1 ? 'Packages' : 'Package';
422
- const verb = names.length > 1 ? 'are' : 'is';
423
- const list =
424
- // prettier-ignore
425
- names.length > 1
426
- ? `${names.slice(0, -1).join(', ')}${names.length > 2 ? ',' : ''} and ${names[names.length - 1] /* oxford commas _are_ that important */}`
427
- : names[0];
428
- 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.');
429
- }
430
- else {
431
- this.packagesToBeLicensed = packagesWithoutLicense;
432
- }
433
- });
434
- }
435
- prepareRegistryActions() {
436
- let chain = Promise.resolve();
437
- if (this.conf.get('registry') !== 'https://registry.npmjs.org/') {
438
- this.logger.notice('', 'Skipping all user and access validation due to third-party registry');
439
- this.logger.notice('', `Make sure you're authenticated properly "\\_(ツ)_ /"`);
440
- return chain;
441
- }
442
- /* istanbul ignore if */
443
- if (process.env.LERNA_INTEGRATION) {
444
- return chain;
445
- }
446
- if (this.verifyAccess) {
447
- // validate user has valid npm credentials first,
448
- // by far the most common form of failed execution
449
- chain = chain.then(() => (0, get_npm_username_1.getNpmUsername)(this.conf.snapshot));
450
- chain = chain.then((username) => {
451
- var _a;
452
- // if no username was retrieved, don't bother validating
453
- if (username) {
454
- return (0, verify_npm_package_access_1.verifyNpmPackageAccess)((_a = this.packagesToPublish) !== null && _a !== void 0 ? _a : [], username, this.conf.snapshot);
455
- }
456
- });
457
- // read profile metadata to determine if account-level 2FA is enabled
458
- chain = chain.then(() => (0, get_two_factor_auth_required_1.getTwoFactorAuthRequired)(this.conf.snapshot));
459
- chain = chain.then((isRequired) => {
460
- // notably, this still doesn't handle package-level 2FA requirements
461
- this.twoFactorAuthRequired = isRequired;
462
- });
463
- }
464
- return chain;
465
- }
466
- updateCanaryVersions() {
467
- return (0, p_map_1.default)(this.updates, (node) => {
468
- var _a, _b, _c;
469
- node.pkg.set('version', (_a = this.updatesVersions) === null || _a === void 0 ? void 0 : _a.get(node.name));
470
- for (const [depName, resolved] of node.localDependencies) {
471
- // other canary versions need to be updated, non-canary is a no-op
472
- const depVersion = ((_b = this.updatesVersions) === null || _b === void 0 ? void 0 : _b.get(depName)) || ((_c = this.packageGraph) === null || _c === void 0 ? void 0 : _c.get(depName).pkg.version);
473
- // it no longer matters if we mutate the shared Package instance
474
- node.pkg.updateLocalDependency(resolved, depVersion, this.savePrefix, this.options.allowPeerDependenciesUpdate, this.options.workspaceStrictMatch, this.commandName);
475
- }
476
- // writing changes to disk handled in serializeChanges()
477
- });
478
- }
479
- /**
480
- * It is possible to override some fields in the manifest before the package is packed
481
- * @see https://pnpm.io/package_json#publishconfig
482
- * @returns
483
- */
484
- applyPublishConfigOverrides() {
485
- // potentially apply any packages that might have publishConfig overrides
486
- return (0, p_map_1.default)(this.updates, (node) => (0, override_publish_config_1.overridePublishConfig)(node.pkg.manifest));
487
- }
488
- resolveLocalDependencyLinks() {
489
- // resolve relative file: links to their actual version range
490
- const updatesWithLocalLinks = this.updates.filter((node) => Array.from(node.localDependencies.values()).some((resolved) => resolved.type === 'directory'));
491
- return (0, p_map_1.default)(updatesWithLocalLinks, (node) => {
492
- var _a, _b;
493
- for (const [depName, resolved] of node.localDependencies) {
494
- // regardless of where the version comes from, we can't publish 'file:../sibling-pkg' specs
495
- const depVersion = ((_a = this.updatesVersions) === null || _a === void 0 ? void 0 : _a.get(depName)) || ((_b = this.packageGraph) === null || _b === void 0 ? void 0 : _b.get(depName).pkg.version);
496
- // it no longer matters if we mutate the shared Package instance
497
- node.pkg.updateLocalDependency(resolved, depVersion, this.savePrefix, this.options.allowPeerDependenciesUpdate, this.options.workspaceStrictMatch, this.commandName);
498
- }
499
- // writing changes to disk handled in serializeChanges()
500
- });
501
- }
502
- resolveLocalDependencyWorkspaceProtocols() {
503
- // resolve workspace protocol: translates to their actual version target/range
504
- const publishingPackagesWithLocalWorkspaces = this.updates.filter((node) => Array.from(node.localDependencies.values()).some((resolved) => resolved.workspaceSpec));
505
- return (0, p_map_1.default)(publishingPackagesWithLocalWorkspaces, (node) => {
506
- // regardless of where the version comes from, we can't publish 'workspace:*' specs, it has to be transformed for both local & external dependencies
507
- // e.g. considering version is `1.2.3` and we have `workspace:*` it will be converted to "^1.2.3" or to "1.2.3" with strict match range enabled
508
- var _a, _b;
509
- // 1. update & bump version of local dependencies
510
- for (const [depName, resolved] of node.localDependencies) {
511
- const depVersion = ((_a = this.updatesVersions) === null || _a === void 0 ? void 0 : _a.get(depName)) || ((_b = this.packageGraph) === null || _b === void 0 ? void 0 : _b.get(depName).pkg.version);
512
- // it no longer matters if we mutate the shared Package instance
513
- node.pkg.updateLocalDependency(resolved, depVersion, this.savePrefix, this.options.allowPeerDependenciesUpdate, this.options.workspaceStrictMatch, this.commandName);
514
- }
515
- // 2. remove any "workspace:" prefix from the package to be published any of external dependencies (without anything being bumped)
516
- // we will only accept "workspace:" with semver version, for example "workspace:1.2.3" is ok but "workspace:*" will log an error
517
- for (const [_depName, resolved] of node.externalDependencies) {
518
- node.pkg.removeDependencyWorkspaceProtocolPrefix(node.name, resolved);
519
- }
520
- // writing changes to disk handled in serializeChanges()
521
- });
522
- }
523
- annotateGitHead() {
524
- var _a;
525
- try {
526
- const gitHead = this.options.gitHead || (0, get_current_sha_1.getCurrentSHA)(this.execOpts);
527
- for (const pkg of (_a = this.packagesToPublish) !== null && _a !== void 0 ? _a : []) {
528
- // provide gitHead property that is normally added during npm publish
529
- pkg.set('gitHead', gitHead);
530
- }
531
- }
532
- catch (err) {
533
- // from-package should be _able_ to run without git, but at least we tried
534
- this.logger.silly('EGITHEAD', err.message);
535
- this.logger.notice('FYI', 'Unable to set temporary gitHead property, it will be missing from registry metadata');
536
- }
537
- // writing changes to disk handled in serializeChanges()
538
- }
539
- serializeChanges() {
540
- var _a;
541
- return (0, p_map_1.default)((_a = this.packagesToPublish) !== null && _a !== void 0 ? _a : [], (pkg) => pkg.serialize());
542
- }
543
- resetChanges() {
544
- // the package.json files are changed (by gitHead if not --canary)
545
- // and we should always __attempt_ to leave the working tree clean
546
- const { cwd } = this.execOpts;
547
- const gitOpts = {
548
- granularPathspec: this.options.granularPathspec !== false,
549
- };
550
- const dirtyManifests = [this.project.manifest]
551
- .concat(this.packagesToPublish)
552
- .map((pkg) => path_1.default.relative(cwd, pkg.manifestLocation));
553
- return (0, git_checkout_1.gitCheckout)(dirtyManifests, gitOpts, this.execOpts, this.options.dryRun).catch((err) => {
554
- this.logger.silly('EGITCHECKOUT', err.message);
555
- this.logger.notice('FYI', `Unable to reset working tree changes, this probably isn't a git repo.`);
556
- });
557
- }
558
- // @deprecated, see Lerna PR https://github.com/lerna/lerna/pull/1862/files
559
- execScript(pkg, script) {
560
- const scriptLocation = path_1.default.join(pkg.location, 'scripts', script);
561
- try {
562
- require(scriptLocation);
563
- }
564
- catch (ex) {
565
- this.logger.silly('execScript', `No ${script} script found at ${scriptLocation}`);
566
- }
567
- return pkg;
568
- }
569
- removePackageProperties() {
570
- const { removePackageFields } = this.options;
571
- return (0, p_map_1.default)(this.updates, (node) => {
572
- if (Array.isArray(removePackageFields)) {
573
- for (const removeField of removePackageFields) {
574
- (0, core_1.deleteComplexObjectProp)(node.pkg.manifest, removeField, `"${node.pkg.name}" package`);
575
- }
576
- }
577
- });
578
- }
579
- removeTempLicensesOnError(error) {
580
- return Promise.resolve()
581
- .then(() => {
582
- var _a;
583
- return (0, remove_temp_licenses_1.removeTempLicenses)((_a = this.packagesToBeLicensed) !== null && _a !== void 0 ? _a : []).catch((removeError) => {
584
- this.logger.error('licenses', 'error removing temporary license files', removeError.stack || removeError);
585
- });
586
- })
587
- .then(() => {
588
- // restore original error into promise chain
589
- throw error;
590
- });
591
- }
592
- requestOneTimePassword() {
593
- if (this.options.dryRun) {
594
- this.logger.info(chalk_1.default.bold.magenta('[dry-run] >'), 'will ask OTP');
595
- return;
596
- }
597
- // if OTP has already been provided, skip prompt
598
- if (this.otpCache.otp) {
599
- return;
600
- }
601
- return Promise.resolve()
602
- .then(() => (0, version_1.getOneTimePassword)('Enter OTP:'))
603
- .then((otp) => (this.otpCache.otp = otp));
604
- }
605
- topoMapPackages(mapper) {
606
- return (0, core_1.runTopologically)(this.packagesToPublish, mapper, {
607
- concurrency: this.concurrency,
608
- rejectCycles: this.options.rejectCycles,
609
- /**
610
- * Previously `publish` had unique default behavior for graph creation vs other commands: it would only consider dependencies when finding
611
- * edges by default (i.e. relationships between packages specified via devDependencies would be ignored). It was documented to be the case
612
- * in order to try and reduce the chance of dependency cycles.
613
- *
614
- * We are removing this behavior altogether in v6 because we do not want to have different ways of constructing the graph,
615
- * only different ways of utilizing it (e.g. --no-sort vs topological sort).
616
- *
617
- * Therefore until we remove graphType altogether in v6, we provide a way for users to opt into the old default behavior
618
- * by setting the `graphType` option to `dependencies`.
619
- */
620
- // prettier-ignore
621
- graphType: this.options.graphType === 'dependencies'
622
- ? 'dependencies'
623
- : this.options.allowPeerDependenciesUpdate
624
- ? 'allPlusPeerDependencies'
625
- : 'allDependencies',
626
- });
627
- }
628
- packUpdated() {
629
- var _a;
630
- const tracker = this.logger.newItem('npm pack');
631
- tracker.addWork((_a = this.packagesToPublish) === null || _a === void 0 ? void 0 : _a.length);
632
- let chain = Promise.resolve();
633
- chain = chain.then(() => { var _a; return (0, create_temp_licenses_1.createTempLicenses)(this.project.licensePath, (_a = this.packagesToBeLicensed) !== null && _a !== void 0 ? _a : []); });
634
- if (!this.hasRootedLeaf) {
635
- // despite being deprecated for years...
636
- chain = chain.then(() => this.runRootLifecycle('prepublish'));
637
- // these lifecycles _should_ never be employed to run `lerna publish`...
638
- chain = chain.then(() => this.runPackageLifecycle(this.project.manifest, 'prepare'));
639
- chain = chain.then(() => this.runPackageLifecycle(this.project.manifest, 'prepublishOnly'));
640
- chain = chain.then(() => this.runPackageLifecycle(this.project.manifest, 'prepack'));
641
- }
642
- const opts = this.conf.snapshot;
643
- const mapper = (0, p_pipe_1.default)(...[
644
- this.options.requireScripts && ((pkg) => this.execScript(pkg, 'prepublish')),
645
- (pkg) => (0, core_1.pulseTillDone)((0, pack_directory_1.packDirectory)(pkg, pkg.location, opts)).then((packed) => {
646
- var _a;
647
- tracker.verbose('packed', path_1.default.relative((_a = this.project.rootPath) !== null && _a !== void 0 ? _a : '', pkg.contents));
648
- tracker.completeWork(1);
649
- // store metadata for use in this.publishPacked()
650
- pkg.packed = packed;
651
- // manifest may be mutated by any previous lifecycle
652
- return pkg.refresh();
653
- }),
654
- ].filter(Boolean));
655
- chain = chain.then(() => {
656
- if (this.toposort) {
657
- return this.topoMapPackages(mapper);
658
- }
659
- return (0, p_map_1.default)(this.packagesToPublish, mapper, { concurrency: this.concurrency });
660
- });
661
- chain = chain.then(() => { var _a; return (0, remove_temp_licenses_1.removeTempLicenses)((_a = this.packagesToBeLicensed) !== null && _a !== void 0 ? _a : []); });
662
- // remove temporary license files if _any_ error occurs _anywhere_ in the promise chain
663
- chain = chain.catch((error) => this.removeTempLicensesOnError(error));
664
- if (!this.hasRootedLeaf) {
665
- chain = chain.then(() => this.runPackageLifecycle(this.project.manifest, 'postpack'));
666
- }
667
- return chain.finally(() => tracker.finish());
668
- }
669
- publishPacked() {
670
- var _a;
671
- this.publishedPackages = [];
672
- const tracker = this.logger.newItem('publish');
673
- tracker.addWork((_a = this.packagesToPublish) === null || _a === void 0 ? void 0 : _a.length);
674
- let chain = Promise.resolve();
675
- // if account-level 2FA is enabled, prime the OTP cache
676
- if (this.twoFactorAuthRequired) {
677
- chain = chain.then(() => this.requestOneTimePassword());
678
- }
679
- const opts = Object.assign(this.conf.snapshot, {
680
- // distTag defaults to 'latest' OR whatever is in pkg.publishConfig.tag
681
- // if we skip temp tags we should tag with the proper value immediately
682
- tag: this.options.tempTag ? 'lerna-temp' : this.conf.get('tag'),
683
- 'git-dry-run': this.options.dryRun || false,
684
- });
685
- const mapper = (0, p_pipe_1.default)(...[
686
- (pkg) => {
687
- const preDistTag = this.getPreDistTag(pkg);
688
- const tag = !this.options.tempTag && preDistTag ? preDistTag : opts.tag;
689
- const pkgOpts = Object.assign({}, opts, { tag });
690
- return (0, core_1.pulseTillDone)((0, npm_publish_1.npmPublish)(pkg, pkg.packed.tarFilePath, pkgOpts, this.otpCache))
691
- .then(() => {
692
- this.publishedPackages.push(pkg);
693
- tracker.success('published', pkg.name, pkg.version);
694
- tracker.completeWork(1);
695
- (0, log_packed_1.logPacked)(pkg, this.options.dryRun);
696
- return pkg;
697
- })
698
- .catch((err) => {
699
- if (err.code === 'EPUBLISHCONFLICT') {
700
- tracker.warn('publish', `Package is already published: ${pkg.name}@${pkg.version}`);
701
- tracker.completeWork(1);
702
- return pkg;
703
- }
704
- this.logger.silly('', err);
705
- this.logger.error(err.code, (err.body && err.body.error) || err.message);
706
- // avoid dumping logs, this isn't a lerna problem
707
- err.name = 'ValidationError';
708
- // ensure process exits non-zero
709
- process.exitCode = 'errno' in err ? err.errno : 1;
710
- throw err;
711
- });
712
- },
713
- this.options.requireScripts && ((pkg) => this.execScript(pkg, 'postpublish')),
714
- ].filter(Boolean));
715
- chain = chain.then(() => {
716
- if (this.toposort) {
717
- return this.topoMapPackages(mapper);
718
- }
719
- return (0, p_map_1.default)(this.packagesToPublish, mapper, { concurrency: this.concurrency });
720
- });
721
- if (!this.hasRootedLeaf) {
722
- // cyclical 'publish' lifecycles are automatically skipped
723
- chain = chain.then(() => this.runRootLifecycle('publish'));
724
- chain = chain.then(() => this.runRootLifecycle('postpublish'));
725
- }
726
- return chain.finally(() => tracker.finish());
727
- }
728
- npmUpdateAsLatest() {
729
- var _a;
730
- const tracker = this.logger.newItem('npmUpdateAsLatest');
731
- tracker.addWork((_a = this.packagesToPublish) === null || _a === void 0 ? void 0 : _a.length);
732
- tracker.showProgress();
733
- let chain = Promise.resolve();
734
- const opts = this.conf.snapshot;
735
- const getDistTag = (publishConfig) => {
736
- if (opts.tag === 'latest' && (publishConfig === null || publishConfig === void 0 ? void 0 : publishConfig.tag)) {
737
- return publishConfig.tag;
738
- }
739
- return opts.tag;
740
- };
741
- const mapper = (pkg) => {
742
- const spec = `${pkg.name}@${pkg.version}`;
743
- const preDistTag = this.getPreDistTag(pkg);
744
- const distTag = preDistTag || getDistTag(pkg.get('publishConfig'));
745
- return Promise.resolve()
746
- .then(() => (0, core_1.pulseTillDone)((0, npm_dist_tag_1.remove)(spec, 'lerna-temp', opts, this.otpCache)))
747
- .then(() => (0, core_1.pulseTillDone)((0, npm_dist_tag_1.add)(spec, distTag, opts, this.otpCache)))
748
- .then(() => {
749
- tracker.success('dist-tag', '%s@%s => %j', pkg.name, pkg.version, distTag);
750
- tracker.completeWork(1);
751
- return pkg;
752
- });
753
- };
754
- chain = chain.then(() => {
755
- if (this.toposort) {
756
- return this.topoMapPackages(mapper);
757
- }
758
- return (0, p_map_1.default)(this.packagesToPublish, mapper, { concurrency: this.concurrency });
759
- });
760
- return chain.finally(() => tracker.finish());
761
- }
762
- getDistTag() {
763
- if (this.options.distTag) {
764
- return this.options.distTag;
765
- }
766
- if (this.options.canary) {
767
- return 'canary';
768
- }
769
- // undefined defaults to 'latest' OR whatever is in pkg.publishConfig.tag
770
- }
771
- getPreDistTag(pkg) {
772
- if (!this.options.preDistTag) {
773
- return;
774
- }
775
- const isPrerelease = (0, core_1.prereleaseIdFromVersion)(pkg.version);
776
- if (isPrerelease) {
777
- return this.options.preDistTag;
778
- }
779
- }
780
- }
781
- exports.PublishCommand = PublishCommand;
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PublishCommand = exports.factory = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const chalk_1 = tslib_1.__importDefault(require("chalk"));
6
+ const glob_1 = tslib_1.__importDefault(require("glob"));
7
+ const fs_extra_1 = tslib_1.__importDefault(require("fs-extra"));
8
+ const os_1 = tslib_1.__importDefault(require("os"));
9
+ const path_1 = tslib_1.__importDefault(require("path"));
10
+ const crypto_1 = tslib_1.__importDefault(require("crypto"));
11
+ const p_map_1 = tslib_1.__importDefault(require("p-map"));
12
+ const p_pipe_1 = tslib_1.__importDefault(require("p-pipe"));
13
+ const semver_1 = tslib_1.__importDefault(require("semver"));
14
+ const temp_dir_1 = tslib_1.__importDefault(require("temp-dir"));
15
+ const version_1 = require("@lerna-lite/version");
16
+ const core_1 = require("@lerna-lite/core");
17
+ const get_current_tags_1 = require("./lib/get-current-tags");
18
+ const get_tagged_packages_1 = require("./lib/get-tagged-packages");
19
+ const get_unpublished_packages_1 = require("./lib/get-unpublished-packages");
20
+ const get_npm_username_1 = require("./lib/get-npm-username");
21
+ const verify_npm_package_access_1 = require("./lib/verify-npm-package-access");
22
+ const get_two_factor_auth_required_1 = require("./lib/get-two-factor-auth-required");
23
+ const get_current_sha_1 = require("./lib/get-current-sha");
24
+ const git_checkout_1 = require("./lib/git-checkout");
25
+ const pack_directory_1 = require("./lib/pack-directory");
26
+ const npm_publish_1 = require("./lib/npm-publish");
27
+ const log_packed_1 = require("./lib/log-packed");
28
+ const npm_dist_tag_1 = require("./lib/npm-dist-tag");
29
+ const override_publish_config_1 = require("./lib/override-publish-config");
30
+ const remove_temp_licenses_1 = require("./lib/remove-temp-licenses");
31
+ const create_temp_licenses_1 = require("./lib/create-temp-licenses");
32
+ const get_packages_without_license_1 = require("./lib/get-packages-without-license");
33
+ function factory(argv) {
34
+ return new PublishCommand(argv);
35
+ }
36
+ exports.factory = factory;
37
+ class PublishCommand extends core_1.Command {
38
+ get otherCommandConfigs() {
39
+ // back-compat
40
+ return ['version'];
41
+ }
42
+ get requiresGit() {
43
+ // `lerna publish from-package` doesn't _need_ git, per se
44
+ return this.options.bump !== 'from-package';
45
+ }
46
+ constructor(argv) {
47
+ super(argv);
48
+ /** command name */
49
+ this.name = 'publish';
50
+ this.gitReset = false;
51
+ this.savePrefix = '';
52
+ this.tagPrefix = '';
53
+ this.hasRootedLeaf = false;
54
+ this.npmSession = '';
55
+ this.packagesToPublish = [];
56
+ this.publishedPackages = [];
57
+ this.packagesToBeLicensed = [];
58
+ this.verifyAccess = false;
59
+ this.toposort = false;
60
+ this.twoFactorAuthRequired = false;
61
+ this.updates = [];
62
+ }
63
+ configureProperties() {
64
+ super.configureProperties();
65
+ // For publish we want to enable topological sorting by default, but allow users to override with --no-sort
66
+ this.toposort = this.options.sort !== false;
67
+ // Defaults are necessary here because yargs defaults
68
+ // override durable options provided by a config file
69
+ const {
70
+ // prettier-ignore
71
+ exact, gitHead, gitReset, tagVersionPrefix = 'v', verifyAccess, } = this.options;
72
+ if (this.requiresGit && gitHead) {
73
+ throw new core_1.ValidationError('EGITHEAD', '--git-head is only allowed with "from-package" positional');
74
+ }
75
+ // https://docs.npmjs.com/misc/config#save-prefix
76
+ this.savePrefix = exact ? '' : '^';
77
+ // https://docs.npmjs.com/misc/config#tag-version-prefix
78
+ this.tagPrefix = tagVersionPrefix;
79
+ // TODO: properly inherit from npm-conf
80
+ // inverted boolean options are only respected if prefixed with `--no-`, e.g. `--no-verify-access`
81
+ this.gitReset = gitReset !== false;
82
+ // consumed by npm-registry-fetch (via libnpmpublish)
83
+ this.npmSession = crypto_1.default.randomBytes(8).toString('hex');
84
+ this.verifyAccess = verifyAccess;
85
+ }
86
+ get userAgent() {
87
+ // consumed by npm-registry-fetch (via libnpmpublish)
88
+ return `lerna/${this.options.lernaVersion}/node@${process.version}+${process.arch} (${process.platform})`;
89
+ }
90
+ initialize() {
91
+ if (this.options.verifyAccess === false) {
92
+ 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.');
93
+ }
94
+ if (this.options.graphType === 'dependencies') {
95
+ this.logger.warn('graph-type', '--graph-type=dependencies is deprecated and will be removed in the next major version of lerna-lite. If you have a use-case you feel requires it please open an issue to discuss: https://github.com/lerna/lerna/issues/new/choose');
96
+ }
97
+ if (this.options.workspaceStrictMatch === false) {
98
+ this.logger.warn('deprecation', 'Providing --no-workspace-strict-match is deprecated and will be removed in future version, we will make "workspace:" protocol strict matching in every case.');
99
+ }
100
+ if (this.options.buildMetadata && this.options.canary) {
101
+ throw new core_1.ValidationError('ENOTSATISFIED', 'Cannot use --build-metadata in conjunction with --canary option.');
102
+ }
103
+ else if (this.options.canary) {
104
+ this.logger.info('canary', 'enabled');
105
+ }
106
+ // @deprecated, to be removed in next major
107
+ if (this.options.requireScripts) {
108
+ this.logger.info('require-scripts', 'enabled');
109
+ }
110
+ // npmSession and user-agent are consumed by npm-registry-fetch (via libnpmpublish)
111
+ this.logger.verbose('session', this.npmSession);
112
+ this.logger.verbose('user-agent', this.userAgent);
113
+ this.conf = (0, core_1.npmConf)({
114
+ lernaCommand: 'publish',
115
+ _auth: this.options.legacyAuth,
116
+ npmSession: this.npmSession,
117
+ npmVersion: this.userAgent,
118
+ otp: this.options.otp,
119
+ registry: this.options.registry,
120
+ 'ignore-prepublish': this.options.ignorePrepublish,
121
+ 'ignore-scripts': this.options.ignoreScripts,
122
+ });
123
+ // cache to hold a one-time-password across publishes
124
+ this.otpCache = { otp: this.conf.get('otp') };
125
+ this.conf.set('user-agent', this.userAgent, 'cli');
126
+ if (this.conf.get('registry') === 'https://registry.yarnpkg.com') {
127
+ this.logger.warn('', `Yarn's registry proxy is broken, replacing with public npm registry`);
128
+ this.logger.warn('', `If you don't have an npm token, you should exit and run "npm login"`);
129
+ this.conf.set('registry', 'https://registry.npmjs.org/', 'cli');
130
+ }
131
+ // inject --dist-tag into opts, if present
132
+ const distTag = this.getDistTag();
133
+ if (distTag) {
134
+ this.conf.set('tag', distTag.trim(), 'cli');
135
+ }
136
+ // a 'rooted leaf' is the regrettable pattern of adding '.' to the 'packages' config in lerna.json
137
+ this.hasRootedLeaf = this.packageGraph.has(this.project.manifest.name);
138
+ if (this.hasRootedLeaf) {
139
+ this.logger.info('publish', 'rooted leaf detected, skipping synthetic root lifecycles');
140
+ }
141
+ this.runPackageLifecycle = (0, core_1.createRunner)(this.options);
142
+ // don't execute recursively if run from a poorly-named script
143
+ this.runRootLifecycle = /^(pre|post)?publish$/.test(process.env.npm_lifecycle_event || '')
144
+ ? (stage) => this.logger.warn('lifecycle', 'Skipping root %j because it has already been called', stage)
145
+ : (stage) => this.runPackageLifecycle(this.project.manifest, stage);
146
+ let chain = Promise.resolve();
147
+ if (this.options.bump === 'from-git') {
148
+ chain = chain.then(() => this.detectFromGit());
149
+ }
150
+ else if (this.options.bump === 'from-package') {
151
+ chain = chain.then(() => this.detectFromPackage());
152
+ }
153
+ else if (this.options.canary) {
154
+ chain = chain.then(() => this.detectCanaryVersions());
155
+ }
156
+ else {
157
+ chain = chain.then(() => new version_1.VersionCommand(this.argv));
158
+ }
159
+ return chain.then((result) => {
160
+ if (!result) {
161
+ // early return from nested VersionCommand
162
+ return false;
163
+ }
164
+ if (!result.updates.length) {
165
+ this.logger.success('No changed packages to publish');
166
+ // still exits zero, aka 'ok'
167
+ return false;
168
+ }
169
+ // (occasionally) redundant private filtering necessary to handle nested VersionCommand
170
+ this.updates = result.updates.filter((node) => !node.pkg.private);
171
+ this.updatesVersions = new Map(result.updatesVersions);
172
+ this.packagesToPublish = this.updates.map((node) => node.pkg);
173
+ if (this.options.contents) {
174
+ // globally override directory to publish
175
+ for (const pkg of this.packagesToPublish) {
176
+ pkg.contents = this.options.contents;
177
+ }
178
+ }
179
+ if (result.needsConfirmation) {
180
+ // only confirm for --canary, bump === 'from-git',
181
+ // or bump === 'from-package', as VersionCommand
182
+ // has its own confirmation prompt
183
+ return this.confirmPublish();
184
+ }
185
+ return true;
186
+ });
187
+ }
188
+ async execute() {
189
+ var _a;
190
+ this.enableProgressBar();
191
+ this.logger.info('publish', 'Publishing packages to npm...');
192
+ await this.prepareRegistryActions();
193
+ await this.prepareLicenseActions();
194
+ if (this.options.canary) {
195
+ await this.updateCanaryVersions();
196
+ }
197
+ await this.resolveLocalDependencyLinks();
198
+ await this.resolveLocalDependencyWorkspaceProtocols();
199
+ if (this.options.removePackageFields) {
200
+ await this.removePackageProperties();
201
+ }
202
+ if (this.options.publishConfigOverrides !== false) {
203
+ await this.applyPublishConfigOverrides();
204
+ }
205
+ await this.annotateGitHead();
206
+ await this.serializeChanges();
207
+ await this.packUpdated();
208
+ await this.publishPacked();
209
+ if (this.gitReset) {
210
+ await this.resetChanges();
211
+ }
212
+ if (this.options.tempTag) {
213
+ await this.npmUpdateAsLatest();
214
+ }
215
+ const count = (_a = this.publishedPackages) === null || _a === void 0 ? void 0 : _a.length;
216
+ const publishedPackagesSorted = this.publishedPackages.sort((a, b) => a.name.localeCompare(b.name));
217
+ if (!count) {
218
+ this.logger.success('All packages have already been published.');
219
+ return;
220
+ }
221
+ (0, core_1.logOutput)('Successfully published:');
222
+ if (this.options.summaryFile !== undefined) {
223
+ // create a json object and output it to a file location.
224
+ const filePath = this.options.summaryFile
225
+ ? `${this.options.summaryFile}/lerna-publish-summary.json`
226
+ : './lerna-publish-summary.json';
227
+ const jsonObject = publishedPackagesSorted.map((pkg) => {
228
+ return {
229
+ packageName: pkg.name,
230
+ version: pkg.version,
231
+ };
232
+ });
233
+ (0, core_1.logOutput)(jsonObject);
234
+ try {
235
+ fs_extra_1.default.outputFileSync(filePath, JSON.stringify(jsonObject));
236
+ (0, core_1.logOutput)('Publish summary created: ', filePath);
237
+ }
238
+ catch (error) {
239
+ (0, core_1.logOutput)('Failed to create the summary report', error);
240
+ }
241
+ }
242
+ else {
243
+ const message = publishedPackagesSorted.map((pkg) => ` - ${pkg.name}@${pkg.version}`);
244
+ (0, core_1.logOutput)(message.join(os_1.default.EOL));
245
+ }
246
+ // optionally cleanup temp packed files after publish, opt-in option
247
+ if (this.options.cleanupTempFiles) {
248
+ (0, glob_1.default)(path_1.default.join(temp_dir_1.default, '/lerna-*'), (_err, deleteFolders) => {
249
+ // delete silently all files/folders that startsWith "lerna-"
250
+ deleteFolders.forEach((folder) => fs_extra_1.default.removeSync(folder));
251
+ this.logger.verbose('publish', `Found ${deleteFolders.length} temp folders to cleanup after publish.`);
252
+ });
253
+ }
254
+ this.logger.success('published', '%d %s', count, count === 1 ? 'package' : 'packages');
255
+ }
256
+ verifyWorkingTreeClean() {
257
+ return (0, core_1.describeRef)(this.execOpts, undefined, this.options.dryRun).then(core_1.throwIfUncommitted);
258
+ }
259
+ detectFromGit() {
260
+ const matchingPattern = this.project.isIndependent() ? `*@*` : `${this.tagPrefix}*.*.*`;
261
+ let chain = Promise.resolve();
262
+ // attempting to publish a tagged release with local changes is not allowed
263
+ chain = chain.then(() => this.verifyWorkingTreeClean());
264
+ chain = chain.then(() => (0, get_current_tags_1.getCurrentTags)(this.execOpts, matchingPattern));
265
+ chain = chain.then((taggedPackageNames) => {
266
+ if (!taggedPackageNames.length) {
267
+ this.logger.notice('from-git', 'No tagged release found. You might not have fetched tags.');
268
+ return [];
269
+ }
270
+ if (this.project.isIndependent()) {
271
+ return taggedPackageNames.map((name) => this.packageGraph.get(name));
272
+ }
273
+ return (0, get_tagged_packages_1.getTaggedPackages)(this.packageGraph, this.project.rootPath, this.execOpts);
274
+ });
275
+ // private packages are never published, full stop.
276
+ chain = chain.then((updates) => updates.filter((node) => !node.pkg.private));
277
+ return chain.then((updates) => {
278
+ const updatesVersions = updates.map((node) => [node.name, node.version]);
279
+ return {
280
+ updates,
281
+ updatesVersions,
282
+ needsConfirmation: true,
283
+ };
284
+ });
285
+ }
286
+ detectFromPackage() {
287
+ let chain = Promise.resolve();
288
+ // attempting to publish a release with local changes is not allowed
289
+ chain = chain
290
+ .then(() => this.verifyWorkingTreeClean())
291
+ .catch((err) => {
292
+ // an execa error is thrown when git suffers a fatal error (such as no git repository present)
293
+ if (err.failed && /git describe/.test(err.command)) {
294
+ // (we tried)
295
+ this.logger.silly('EWORKINGTREE', err.message);
296
+ this.logger.notice('FYI', 'Unable to verify working tree, proceed at your own risk');
297
+ process.exitCode = 0;
298
+ }
299
+ else {
300
+ // validation errors should be preserved
301
+ throw err;
302
+ }
303
+ });
304
+ // private packages are already omitted by getUnpublishedPackages()
305
+ chain = chain.then(() => (0, get_unpublished_packages_1.getUnpublishedPackages)(this.packageGraph, this.conf.snapshot));
306
+ chain = chain.then((unpublished) => {
307
+ if (!unpublished.length) {
308
+ this.logger.notice('from-package', 'No unpublished release found');
309
+ }
310
+ return unpublished;
311
+ });
312
+ return chain.then((updates) => {
313
+ const updatesVersions = updates.map((node) => [node.name, node.version]);
314
+ return {
315
+ updates,
316
+ updatesVersions,
317
+ needsConfirmation: true,
318
+ };
319
+ });
320
+ }
321
+ detectCanaryVersions() {
322
+ const { cwd } = this.execOpts;
323
+ const { bump = 'prepatch', preid = 'alpha', ignoreChanges, forcePublish, includeMergedTags } = this.options;
324
+ // 'prerelease' and 'prepatch' are identical, for our purposes
325
+ const release = bump.startsWith('pre') ? bump.replace('release', 'patch') : `pre${bump}`;
326
+ let chain = Promise.resolve();
327
+ // attempting to publish a canary release with local changes is not allowed
328
+ chain = chain
329
+ .then(() => this.verifyWorkingTreeClean())
330
+ .catch((err) => {
331
+ // an execa error is thrown when git suffers a fatal error (such as no git repository present)
332
+ if (err.failed && /git describe/.test(err.command)) {
333
+ // (we tried)
334
+ this.logger.silly('EWORKINGTREE', err.message);
335
+ this.logger.notice('FYI', 'Unable to verify working tree, proceed at your own risk');
336
+ }
337
+ else {
338
+ // validation errors should be preserved
339
+ throw err;
340
+ }
341
+ });
342
+ const isIndependent = this.project.isIndependent();
343
+ // find changed packages since last release, if any
344
+ chain = chain.then(() => {
345
+ var _a, _b;
346
+ return (0, core_1.collectUpdates)((_b = (_a = this.packageGraph) === null || _a === void 0 ? void 0 : _a.rawPackageList) !== null && _b !== void 0 ? _b : [], this.packageGraph, this.execOpts, {
347
+ bump: 'prerelease',
348
+ canary: true,
349
+ ignoreChanges,
350
+ forcePublish,
351
+ includeMergedTags,
352
+ isIndependent,
353
+ // private packages are never published, don't bother describing their refs.
354
+ }, this.options.dryRun).filter((node) => !node.pkg.private);
355
+ });
356
+ // prettier-ignore
357
+ const makeVersion = (fallback) => ({ lastVersion = fallback, refCount, sha }) => {
358
+ // the next version is bumped without concern for preid or current index
359
+ // prettier-ignore
360
+ const nextVersion = semver_1.default.inc(lastVersion.replace(this.tagPrefix, ''), release.replace('pre', ''));
361
+ // semver.inc() starts a new prerelease at .0, git describe starts at .1
362
+ // and build metadata is always ignored when comparing dependency ranges
363
+ return `${nextVersion}-${preid}.${Math.max(0, refCount - 1)}+${sha}`;
364
+ };
365
+ if (isIndependent) {
366
+ // each package is described against its tags only
367
+ chain = chain.then((updates) => (0, p_map_1.default)(updates, (node) => (0, core_1.describeRef)({
368
+ match: `${node.name}@*`,
369
+ cwd,
370
+ }, includeMergedTags, this.options.dryRun)
371
+ // an unpublished package will have no reachable git tag
372
+ .then(makeVersion(node.version))
373
+ .then((version) => [node.name, version])).then((updatesVersions) => ({
374
+ updates,
375
+ updatesVersions,
376
+ })));
377
+ }
378
+ else {
379
+ // all packages are described against the last tag
380
+ chain = chain.then((updates) => (0, core_1.describeRef)({
381
+ match: `${this.tagPrefix}*.*.*`,
382
+ cwd,
383
+ }, includeMergedTags, this.options.dryRun)
384
+ // a repo with no tags should default to whatever lerna.json claims
385
+ .then(makeVersion(this.project.version))
386
+ .then((version) => updates.map((node) => [node.name, version]))
387
+ .then((updatesVersions) => ({
388
+ updates,
389
+ updatesVersions,
390
+ })));
391
+ }
392
+ return chain.then(({ updates, updatesVersions }) => ({
393
+ updates,
394
+ updatesVersions,
395
+ needsConfirmation: true,
396
+ }));
397
+ }
398
+ confirmPublish() {
399
+ var _a, _b, _c;
400
+ const count = (_a = this.packagesToPublish) === null || _a === void 0 ? void 0 : _a.length;
401
+ const message = (_c = (_b = this.packagesToPublish) === null || _b === void 0 ? void 0 : _b.map((pkg) => { var _a; return ` - ${pkg.name} => ${(_a = this.updatesVersions) === null || _a === void 0 ? void 0 : _a.get(pkg.name)}`; })) !== null && _c !== void 0 ? _c : [];
402
+ (0, core_1.logOutput)('');
403
+ (0, core_1.logOutput)(`Found ${count} ${count === 1 ? 'package' : 'packages'} to publish:`);
404
+ (0, core_1.logOutput)(message.join(os_1.default.EOL));
405
+ (0, core_1.logOutput)('');
406
+ if (this.options.yes) {
407
+ this.logger.info('auto-confirmed', '');
408
+ return true;
409
+ }
410
+ let confirmMessage = this.options.dryRun ? chalk_1.default.bgMagenta('[dry-run]') : '';
411
+ confirmMessage += ' Are you sure you want to publish these packages?';
412
+ return (0, core_1.promptConfirmation)(confirmMessage.trim());
413
+ }
414
+ prepareLicenseActions() {
415
+ return Promise.resolve()
416
+ .then(() => { var _a; return (0, get_packages_without_license_1.getPackagesWithoutLicense)(this.project, (_a = this.packagesToPublish) !== null && _a !== void 0 ? _a : []); })
417
+ .then((packagesWithoutLicense) => {
418
+ if (packagesWithoutLicense.length && !this.project.licensePath) {
419
+ this.packagesToBeLicensed = [];
420
+ const names = packagesWithoutLicense.map((pkg) => pkg.name);
421
+ const noun = names.length > 1 ? 'Packages' : 'Package';
422
+ const verb = names.length > 1 ? 'are' : 'is';
423
+ const list =
424
+ // prettier-ignore
425
+ names.length > 1
426
+ ? `${names.slice(0, -1).join(', ')}${names.length > 2 ? ',' : ''} and ${names[names.length - 1] /* oxford commas _are_ that important */}`
427
+ : names[0];
428
+ 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.');
429
+ }
430
+ else {
431
+ this.packagesToBeLicensed = packagesWithoutLicense;
432
+ }
433
+ });
434
+ }
435
+ prepareRegistryActions() {
436
+ let chain = Promise.resolve();
437
+ if (this.conf.get('registry') !== 'https://registry.npmjs.org/') {
438
+ this.logger.notice('', 'Skipping all user and access validation due to third-party registry');
439
+ this.logger.notice('', `Make sure you're authenticated properly "\\_(ツ)_ /"`);
440
+ return chain;
441
+ }
442
+ /* istanbul ignore if */
443
+ if (process.env.LERNA_INTEGRATION) {
444
+ return chain;
445
+ }
446
+ if (this.verifyAccess) {
447
+ // validate user has valid npm credentials first,
448
+ // by far the most common form of failed execution
449
+ chain = chain.then(() => (0, get_npm_username_1.getNpmUsername)(this.conf.snapshot));
450
+ chain = chain.then((username) => {
451
+ var _a;
452
+ // if no username was retrieved, don't bother validating
453
+ if (username) {
454
+ return (0, verify_npm_package_access_1.verifyNpmPackageAccess)((_a = this.packagesToPublish) !== null && _a !== void 0 ? _a : [], username, this.conf.snapshot);
455
+ }
456
+ });
457
+ // read profile metadata to determine if account-level 2FA is enabled
458
+ chain = chain.then(() => (0, get_two_factor_auth_required_1.getTwoFactorAuthRequired)(this.conf.snapshot));
459
+ chain = chain.then((isRequired) => {
460
+ // notably, this still doesn't handle package-level 2FA requirements
461
+ this.twoFactorAuthRequired = isRequired;
462
+ });
463
+ }
464
+ return chain;
465
+ }
466
+ updateCanaryVersions() {
467
+ return (0, p_map_1.default)(this.updates, (node) => {
468
+ var _a, _b, _c;
469
+ node.pkg.set('version', (_a = this.updatesVersions) === null || _a === void 0 ? void 0 : _a.get(node.name));
470
+ for (const [depName, resolved] of node.localDependencies) {
471
+ // other canary versions need to be updated, non-canary is a no-op
472
+ const depVersion = ((_b = this.updatesVersions) === null || _b === void 0 ? void 0 : _b.get(depName)) || ((_c = this.packageGraph) === null || _c === void 0 ? void 0 : _c.get(depName).pkg.version);
473
+ // it no longer matters if we mutate the shared Package instance
474
+ node.pkg.updateLocalDependency(resolved, depVersion, this.savePrefix, this.options.allowPeerDependenciesUpdate, this.options.workspaceStrictMatch, this.commandName);
475
+ }
476
+ // writing changes to disk handled in serializeChanges()
477
+ });
478
+ }
479
+ /**
480
+ * It is possible to override some fields in the manifest before the package is packed
481
+ * @see https://pnpm.io/package_json#publishconfig
482
+ * @returns
483
+ */
484
+ applyPublishConfigOverrides() {
485
+ // potentially apply any packages that might have publishConfig overrides
486
+ return (0, p_map_1.default)(this.updates, (node) => (0, override_publish_config_1.overridePublishConfig)(node.pkg.manifest));
487
+ }
488
+ resolveLocalDependencyLinks() {
489
+ // resolve relative file: links to their actual version range
490
+ const updatesWithLocalLinks = this.updates.filter((node) => Array.from(node.localDependencies.values()).some((resolved) => resolved.type === 'directory'));
491
+ return (0, p_map_1.default)(updatesWithLocalLinks, (node) => {
492
+ var _a, _b;
493
+ for (const [depName, resolved] of node.localDependencies) {
494
+ // regardless of where the version comes from, we can't publish 'file:../sibling-pkg' specs
495
+ const depVersion = ((_a = this.updatesVersions) === null || _a === void 0 ? void 0 : _a.get(depName)) || ((_b = this.packageGraph) === null || _b === void 0 ? void 0 : _b.get(depName).pkg.version);
496
+ // it no longer matters if we mutate the shared Package instance
497
+ node.pkg.updateLocalDependency(resolved, depVersion, this.savePrefix, this.options.allowPeerDependenciesUpdate, this.options.workspaceStrictMatch, this.commandName);
498
+ }
499
+ // writing changes to disk handled in serializeChanges()
500
+ });
501
+ }
502
+ resolveLocalDependencyWorkspaceProtocols() {
503
+ // resolve workspace protocol: translates to their actual version target/range
504
+ const publishingPackagesWithLocalWorkspaces = this.updates.filter((node) => Array.from(node.localDependencies.values()).some((resolved) => resolved.workspaceSpec));
505
+ return (0, p_map_1.default)(publishingPackagesWithLocalWorkspaces, (node) => {
506
+ // regardless of where the version comes from, we can't publish 'workspace:*' specs, it has to be transformed for both local & external dependencies
507
+ // e.g. considering version is `1.2.3` and we have `workspace:*` it will be converted to "^1.2.3" or to "1.2.3" with strict match range enabled
508
+ var _a, _b;
509
+ // 1. update & bump version of local dependencies
510
+ for (const [depName, resolved] of node.localDependencies) {
511
+ const depVersion = ((_a = this.updatesVersions) === null || _a === void 0 ? void 0 : _a.get(depName)) || ((_b = this.packageGraph) === null || _b === void 0 ? void 0 : _b.get(depName).pkg.version);
512
+ // it no longer matters if we mutate the shared Package instance
513
+ node.pkg.updateLocalDependency(resolved, depVersion, this.savePrefix, this.options.allowPeerDependenciesUpdate, this.options.workspaceStrictMatch, this.commandName);
514
+ }
515
+ // 2. remove any "workspace:" prefix from the package to be published any of external dependencies (without anything being bumped)
516
+ // we will only accept "workspace:" with semver version, for example "workspace:1.2.3" is ok but "workspace:*" will log an error
517
+ for (const [_depName, resolved] of node.externalDependencies) {
518
+ node.pkg.removeDependencyWorkspaceProtocolPrefix(node.name, resolved);
519
+ }
520
+ // writing changes to disk handled in serializeChanges()
521
+ });
522
+ }
523
+ annotateGitHead() {
524
+ var _a;
525
+ try {
526
+ const gitHead = this.options.gitHead || (0, get_current_sha_1.getCurrentSHA)(this.execOpts);
527
+ for (const pkg of (_a = this.packagesToPublish) !== null && _a !== void 0 ? _a : []) {
528
+ // provide gitHead property that is normally added during npm publish
529
+ pkg.set('gitHead', gitHead);
530
+ }
531
+ }
532
+ catch (err) {
533
+ // from-package should be _able_ to run without git, but at least we tried
534
+ this.logger.silly('EGITHEAD', err.message);
535
+ this.logger.notice('FYI', 'Unable to set temporary gitHead property, it will be missing from registry metadata');
536
+ }
537
+ // writing changes to disk handled in serializeChanges()
538
+ }
539
+ serializeChanges() {
540
+ var _a;
541
+ return (0, p_map_1.default)((_a = this.packagesToPublish) !== null && _a !== void 0 ? _a : [], (pkg) => pkg.serialize());
542
+ }
543
+ resetChanges() {
544
+ // the package.json files are changed (by gitHead if not --canary)
545
+ // and we should always __attempt_ to leave the working tree clean
546
+ const { cwd } = this.execOpts;
547
+ const gitOpts = {
548
+ granularPathspec: this.options.granularPathspec !== false,
549
+ };
550
+ const dirtyManifests = [this.project.manifest]
551
+ .concat(this.packagesToPublish)
552
+ .map((pkg) => path_1.default.relative(cwd, pkg.manifestLocation));
553
+ return (0, git_checkout_1.gitCheckout)(dirtyManifests, gitOpts, this.execOpts, this.options.dryRun).catch((err) => {
554
+ this.logger.silly('EGITCHECKOUT', err.message);
555
+ this.logger.notice('FYI', `Unable to reset working tree changes, this probably isn't a git repo.`);
556
+ });
557
+ }
558
+ // @deprecated, see Lerna PR https://github.com/lerna/lerna/pull/1862/files
559
+ execScript(pkg, script) {
560
+ const scriptLocation = path_1.default.join(pkg.location, 'scripts', script);
561
+ try {
562
+ require(scriptLocation);
563
+ }
564
+ catch (ex) {
565
+ this.logger.silly('execScript', `No ${script} script found at ${scriptLocation}`);
566
+ }
567
+ return pkg;
568
+ }
569
+ removePackageProperties() {
570
+ const { removePackageFields } = this.options;
571
+ return (0, p_map_1.default)(this.updates, (node) => {
572
+ if (Array.isArray(removePackageFields)) {
573
+ for (const removeField of removePackageFields) {
574
+ (0, core_1.deleteComplexObjectProp)(node.pkg.manifest, removeField, `"${node.pkg.name}" package`);
575
+ }
576
+ }
577
+ });
578
+ }
579
+ removeTempLicensesOnError(error) {
580
+ return Promise.resolve()
581
+ .then(() => {
582
+ var _a;
583
+ return (0, remove_temp_licenses_1.removeTempLicenses)((_a = this.packagesToBeLicensed) !== null && _a !== void 0 ? _a : []).catch((removeError) => {
584
+ this.logger.error('licenses', 'error removing temporary license files', removeError.stack || removeError);
585
+ });
586
+ })
587
+ .then(() => {
588
+ // restore original error into promise chain
589
+ throw error;
590
+ });
591
+ }
592
+ requestOneTimePassword() {
593
+ if (this.options.dryRun) {
594
+ this.logger.info(chalk_1.default.bold.magenta('[dry-run] >'), 'will ask OTP');
595
+ return;
596
+ }
597
+ // if OTP has already been provided, skip prompt
598
+ if (this.otpCache.otp) {
599
+ return;
600
+ }
601
+ return Promise.resolve()
602
+ .then(() => (0, version_1.getOneTimePassword)('Enter OTP:'))
603
+ .then((otp) => (this.otpCache.otp = otp));
604
+ }
605
+ topoMapPackages(mapper) {
606
+ return (0, core_1.runTopologically)(this.packagesToPublish, mapper, {
607
+ concurrency: this.concurrency,
608
+ rejectCycles: this.options.rejectCycles,
609
+ /**
610
+ * Previously `publish` had unique default behavior for graph creation vs other commands: it would only consider dependencies when finding
611
+ * edges by default (i.e. relationships between packages specified via devDependencies would be ignored). It was documented to be the case
612
+ * in order to try and reduce the chance of dependency cycles.
613
+ *
614
+ * We are removing this behavior altogether in v6 because we do not want to have different ways of constructing the graph,
615
+ * only different ways of utilizing it (e.g. --no-sort vs topological sort).
616
+ *
617
+ * Therefore until we remove graphType altogether in v6, we provide a way for users to opt into the old default behavior
618
+ * by setting the `graphType` option to `dependencies`.
619
+ */
620
+ // prettier-ignore
621
+ graphType: this.options.graphType === 'dependencies'
622
+ ? 'dependencies'
623
+ : this.options.allowPeerDependenciesUpdate
624
+ ? 'allPlusPeerDependencies'
625
+ : 'allDependencies',
626
+ });
627
+ }
628
+ packUpdated() {
629
+ var _a;
630
+ const tracker = this.logger.newItem('npm pack');
631
+ tracker.addWork((_a = this.packagesToPublish) === null || _a === void 0 ? void 0 : _a.length);
632
+ let chain = Promise.resolve();
633
+ chain = chain.then(() => { var _a; return (0, create_temp_licenses_1.createTempLicenses)(this.project.licensePath, (_a = this.packagesToBeLicensed) !== null && _a !== void 0 ? _a : []); });
634
+ if (!this.hasRootedLeaf) {
635
+ // despite being deprecated for years...
636
+ chain = chain.then(() => this.runRootLifecycle('prepublish'));
637
+ // these lifecycles _should_ never be employed to run `lerna publish`...
638
+ chain = chain.then(() => this.runPackageLifecycle(this.project.manifest, 'prepare'));
639
+ chain = chain.then(() => this.runPackageLifecycle(this.project.manifest, 'prepublishOnly'));
640
+ chain = chain.then(() => this.runPackageLifecycle(this.project.manifest, 'prepack'));
641
+ }
642
+ const opts = this.conf.snapshot;
643
+ const mapper = (0, p_pipe_1.default)(...[
644
+ this.options.requireScripts && ((pkg) => this.execScript(pkg, 'prepublish')),
645
+ (pkg) => (0, core_1.pulseTillDone)((0, pack_directory_1.packDirectory)(pkg, pkg.location, opts)).then((packed) => {
646
+ var _a;
647
+ tracker.verbose('packed', path_1.default.relative((_a = this.project.rootPath) !== null && _a !== void 0 ? _a : '', pkg.contents));
648
+ tracker.completeWork(1);
649
+ // store metadata for use in this.publishPacked()
650
+ pkg.packed = packed;
651
+ // manifest may be mutated by any previous lifecycle
652
+ return pkg.refresh();
653
+ }),
654
+ ].filter(Boolean));
655
+ chain = chain.then(() => {
656
+ if (this.toposort) {
657
+ return this.topoMapPackages(mapper);
658
+ }
659
+ return (0, p_map_1.default)(this.packagesToPublish, mapper, { concurrency: this.concurrency });
660
+ });
661
+ chain = chain.then(() => { var _a; return (0, remove_temp_licenses_1.removeTempLicenses)((_a = this.packagesToBeLicensed) !== null && _a !== void 0 ? _a : []); });
662
+ // remove temporary license files if _any_ error occurs _anywhere_ in the promise chain
663
+ chain = chain.catch((error) => this.removeTempLicensesOnError(error));
664
+ if (!this.hasRootedLeaf) {
665
+ chain = chain.then(() => this.runPackageLifecycle(this.project.manifest, 'postpack'));
666
+ }
667
+ return chain.finally(() => tracker.finish());
668
+ }
669
+ publishPacked() {
670
+ var _a;
671
+ this.publishedPackages = [];
672
+ const tracker = this.logger.newItem('publish');
673
+ tracker.addWork((_a = this.packagesToPublish) === null || _a === void 0 ? void 0 : _a.length);
674
+ let chain = Promise.resolve();
675
+ // if account-level 2FA is enabled, prime the OTP cache
676
+ if (this.twoFactorAuthRequired) {
677
+ chain = chain.then(() => this.requestOneTimePassword());
678
+ }
679
+ const opts = Object.assign(this.conf.snapshot, {
680
+ // distTag defaults to 'latest' OR whatever is in pkg.publishConfig.tag
681
+ // if we skip temp tags we should tag with the proper value immediately
682
+ tag: this.options.tempTag ? 'lerna-temp' : this.conf.get('tag'),
683
+ 'git-dry-run': this.options.dryRun || false,
684
+ });
685
+ const mapper = (0, p_pipe_1.default)(...[
686
+ (pkg) => {
687
+ const preDistTag = this.getPreDistTag(pkg);
688
+ const tag = !this.options.tempTag && preDistTag ? preDistTag : opts.tag;
689
+ const pkgOpts = Object.assign({}, opts, { tag });
690
+ return (0, core_1.pulseTillDone)((0, npm_publish_1.npmPublish)(pkg, pkg.packed.tarFilePath, pkgOpts, this.otpCache))
691
+ .then(() => {
692
+ this.publishedPackages.push(pkg);
693
+ tracker.success('published', pkg.name, pkg.version);
694
+ tracker.completeWork(1);
695
+ (0, log_packed_1.logPacked)(pkg, this.options.dryRun);
696
+ return pkg;
697
+ })
698
+ .catch((err) => {
699
+ if (err.code === 'EPUBLISHCONFLICT') {
700
+ tracker.warn('publish', `Package is already published: ${pkg.name}@${pkg.version}`);
701
+ tracker.completeWork(1);
702
+ return pkg;
703
+ }
704
+ this.logger.silly('', err);
705
+ this.logger.error(err.code, (err.body && err.body.error) || err.message);
706
+ // avoid dumping logs, this isn't a lerna problem
707
+ err.name = 'ValidationError';
708
+ // ensure process exits non-zero
709
+ process.exitCode = 'errno' in err ? err.errno : 1;
710
+ throw err;
711
+ });
712
+ },
713
+ this.options.requireScripts && ((pkg) => this.execScript(pkg, 'postpublish')),
714
+ ].filter(Boolean));
715
+ chain = chain.then(() => {
716
+ if (this.toposort) {
717
+ return this.topoMapPackages(mapper);
718
+ }
719
+ return (0, p_map_1.default)(this.packagesToPublish, mapper, { concurrency: this.concurrency });
720
+ });
721
+ if (!this.hasRootedLeaf) {
722
+ // cyclical 'publish' lifecycles are automatically skipped
723
+ chain = chain.then(() => this.runRootLifecycle('publish'));
724
+ chain = chain.then(() => this.runRootLifecycle('postpublish'));
725
+ }
726
+ return chain.finally(() => tracker.finish());
727
+ }
728
+ npmUpdateAsLatest() {
729
+ var _a;
730
+ const tracker = this.logger.newItem('npmUpdateAsLatest');
731
+ tracker.addWork((_a = this.packagesToPublish) === null || _a === void 0 ? void 0 : _a.length);
732
+ tracker.showProgress();
733
+ let chain = Promise.resolve();
734
+ const opts = this.conf.snapshot;
735
+ const getDistTag = (publishConfig) => {
736
+ if (opts.tag === 'latest' && (publishConfig === null || publishConfig === void 0 ? void 0 : publishConfig.tag)) {
737
+ return publishConfig.tag;
738
+ }
739
+ return opts.tag;
740
+ };
741
+ const mapper = (pkg) => {
742
+ const spec = `${pkg.name}@${pkg.version}`;
743
+ const preDistTag = this.getPreDistTag(pkg);
744
+ const distTag = preDistTag || getDistTag(pkg.get('publishConfig'));
745
+ return Promise.resolve()
746
+ .then(() => (0, core_1.pulseTillDone)((0, npm_dist_tag_1.remove)(spec, 'lerna-temp', opts, this.otpCache)))
747
+ .then(() => (0, core_1.pulseTillDone)((0, npm_dist_tag_1.add)(spec, distTag, opts, this.otpCache)))
748
+ .then(() => {
749
+ tracker.success('dist-tag', '%s@%s => %j', pkg.name, pkg.version, distTag);
750
+ tracker.completeWork(1);
751
+ return pkg;
752
+ });
753
+ };
754
+ chain = chain.then(() => {
755
+ if (this.toposort) {
756
+ return this.topoMapPackages(mapper);
757
+ }
758
+ return (0, p_map_1.default)(this.packagesToPublish, mapper, { concurrency: this.concurrency });
759
+ });
760
+ return chain.finally(() => tracker.finish());
761
+ }
762
+ getDistTag() {
763
+ if (this.options.distTag) {
764
+ return this.options.distTag;
765
+ }
766
+ if (this.options.canary) {
767
+ return 'canary';
768
+ }
769
+ // undefined defaults to 'latest' OR whatever is in pkg.publishConfig.tag
770
+ }
771
+ getPreDistTag(pkg) {
772
+ if (!this.options.preDistTag) {
773
+ return;
774
+ }
775
+ const isPrerelease = (0, core_1.prereleaseIdFromVersion)(pkg.version);
776
+ if (isPrerelease) {
777
+ return this.options.preDistTag;
778
+ }
779
+ }
780
+ }
781
+ exports.PublishCommand = PublishCommand;
782
782
  //# sourceMappingURL=publish-command.js.map