diff --git a/readme.md b/readme.md index be4b1498..1646bc0e 100644 --- a/readme.md +++ b/readme.md @@ -35,6 +35,7 @@ (does not apply to external registries) - Opens a prefilled GitHub Releases draft after publish - Warns about the possibility of extraneous files being published +- See exactly what will be executed with [preview mode](https://github.com/sindresorhus/np/issues/391), without pushing or publishing anything remotely - Supports [GitHub Packages](https://github.com/features/packages) @@ -69,6 +70,7 @@ $ np --help --no-tests Skips tests --yolo Skips cleanup and testing --no-publish Skips publishing + --preview Show tasks without actually executing them --tag Publish under a given dist-tag --no-yarn Don't use Yarn --contents Subdirectory to publish @@ -101,6 +103,7 @@ Currently, these are the flags you can configure: - `tests` - Run `npm test` (`true` by default). - `yolo` - Skip cleanup and testing (`false` by default). - `publish` - Publish (`true` by default). +- `preview` - Show tasks without actually executing them (`false` by default). - `tag` - Publish under a given dist-tag (`latest` by default). - `yarn` - Use yarn if possible (`true` by default). - `contents` - Subdirectory to publish (`.` by default). diff --git a/source/cli.js b/source/cli.js index e110cb6f..71b4bc5c 100755 --- a/source/cli.js +++ b/source/cli.js @@ -26,6 +26,7 @@ const cli = meow(` --no-tests Skips tests --yolo Skips cleanup and testing --no-publish Skips publishing + --preview Show tasks without actually executing them --tag Publish under a given dist-tag --no-yarn Don't use Yarn --contents Subdirectory to publish @@ -67,6 +68,9 @@ const cli = meow(` }, contents: { type: 'string' + }, + preview: { + type: 'boolean' } } }); @@ -103,6 +107,11 @@ updateNotifier({pkg: cli.pkg}).notify(); console.log(); // Prints a newline for readability const newPkg = await np(options.version, options); + + if (options.preview) { + return; + } + console.log(`\n ${newPkg.name} ${newPkg.version} published 🎉`); })().catch(error => { console.error(`\n${logSymbols.error} ${error.message}`); diff --git a/source/index.js b/source/index.js index 8cb7321f..64cf016c 100644 --- a/source/index.js +++ b/source/index.js @@ -88,7 +88,9 @@ module.exports = async (input = 'patch', options) => { // The default parameter is a workaround for https://github.com/Tapppi/async-exit-hook/issues/9 exitHook((callback = () => {}) => { - if (publishStatus === 'FAILED') { + if (options.preview) { + callback(); + } else if (publishStatus === 'FAILED') { (async () => { await rollback(); callback(); @@ -173,11 +175,21 @@ module.exports = async (input = 'patch', options) => { { title: 'Bumping version using Yarn', enabled: () => options.yarn === true, + skip: () => { + if (options.preview) { + return `[Preview] Command not executed: yarn version --new-version ${input}.`; + } + }, task: () => exec('yarn', ['version', '--new-version', input]) }, { title: 'Bumping version using npm', enabled: () => options.yarn === false, + skip: () => { + if (options.preview) { + return `[Preview] Command not executed: npm version ${input}.`; + } + }, task: () => exec('npm', ['version', input]) } ]); @@ -186,6 +198,12 @@ module.exports = async (input = 'patch', options) => { tasks.add([ { title: `Publishing package using ${pkgManagerName}`, + skip: () => { + if (options.preview) { + const args = publish.getPackagePublishArguments(options); + return `[Preview] Command not executed: ${pkgManager} ${args.join(' ')}.`; + } + }, task: (context, task) => { let hasError = false; @@ -209,6 +227,12 @@ module.exports = async (input = 'patch', options) => { tasks.add([ { title: 'Enabling two-factor authentication', + skip: () => { + if (options.preview) { + const args = enable2fa.getEnable2faArgs(pkg.name, options); + return `[Preview] Command not executed: npm ${args.join(' ')}.`; + } + }, task: (context, task) => enable2fa(task, pkg.name, {otp: context.otp}) } ]); @@ -224,6 +248,10 @@ module.exports = async (input = 'patch', options) => { return 'Upstream branch not found; not pushing.'; } + if (options.preview) { + return '[Preview] Command not executed: git push --follow-tags.'; + } + if (publishStatus === 'FAILED' && runPublish) { return 'Couldn\'t publish package to npm; not pushing.'; } @@ -234,7 +262,13 @@ module.exports = async (input = 'patch', options) => { tasks.add({ title: 'Creating release draft on GitHub', enabled: () => isOnGitHub === true, - skip: () => !options.releaseDraft, + skip: () => { + if (options.preview) { + return '[Preview] GitHub Releases draft will not be opened in preview mode.'; + } + + return !options.releaseDraft; + }, task: () => releaseTaskHelper(options, pkg) }); diff --git a/source/npm/enable-2fa.js b/source/npm/enable-2fa.js index 91ef65fa..a9e2ef34 100644 --- a/source/npm/enable-2fa.js +++ b/source/npm/enable-2fa.js @@ -4,17 +4,21 @@ const {from} = require('rxjs'); const {catchError} = require('rxjs/operators'); const handleNpmError = require('./handle-npm-error'); -const enable2fa = (packageName, options) => { +const getEnable2faArgs = (packageName, options) => { const args = ['access', '2fa-required', packageName]; if (options && options.otp) { args.push('--otp', options.otp); } - return execa('npm', args); + return args; }; +const enable2fa = (packageName, options) => execa('npm', getEnable2faArgs(packageName, options)); + module.exports = (task, packageName, options) => from(enable2fa(packageName, options)).pipe( catchError(error => handleNpmError(error, task, otp => enable2fa(packageName, {otp}))) ); + +module.exports.getEnable2faArgs = getEnable2faArgs; diff --git a/source/npm/publish.js b/source/npm/publish.js index 57e0d636..0a4ed4ee 100644 --- a/source/npm/publish.js +++ b/source/npm/publish.js @@ -4,7 +4,7 @@ const {from} = require('rxjs'); const {catchError} = require('rxjs/operators'); const handleNpmError = require('./handle-npm-error'); -const pkgPublish = (pkgManager, options) => { +const getPackagePublishArguments = options => { const args = ['publish']; if (options.contents) { @@ -23,9 +23,11 @@ const pkgPublish = (pkgManager, options) => { args.push('--access', 'public'); } - return execa(pkgManager, args); + return args; }; +const pkgPublish = (pkgManager, options) => execa(pkgManager, getPackagePublishArguments(options)); + module.exports = (context, pkgManager, task, options) => from(pkgPublish(pkgManager, options)).pipe( catchError(error => handleNpmError(error, task, otp => { @@ -34,3 +36,5 @@ module.exports = (context, pkgManager, task, options) => return pkgPublish(pkgManager, {...options, otp}); })) ); + +module.exports.getPackagePublishArguments = getPackagePublishArguments;