diff --git a/readme.md b/readme.md index 1646bc0e..d13da11e 100644 --- a/readme.md +++ b/readme.md @@ -207,6 +207,16 @@ To publish [scoped packages](https://docs.npmjs.com/misc/scope#publishing-public } ``` +### Private Org-scoped packages + +To publish a [private Org-scoped package](https://docs.npmjs.com/creating-and-publishing-an-org-scoped-package#publishing-a-private-org-scoped-package), you need to set the access level to `restricted`. You can do that by adding the following to your `package.json`: + +```json +"publishConfig": { + "access": "restricted" +} +``` + ### Publish to a custom registry Set the [`registry` option](https://docs.npmjs.com/misc/config#registry) in package.json to the URL of your registry: diff --git a/source/cli.js b/source/cli.js index 71b4bc5c..fd0be0c4 100755 --- a/source/cli.js +++ b/source/cli.js @@ -95,11 +95,18 @@ updateNotifier({pkg: cli.pkg}).notify(); ...cli.flags }; + const runPublish = flags.publish && !pkg.private; + const availability = await isPackageNameAvailable(pkg); const version = cli.input.length > 0 ? cli.input[0] : false; - const options = await ui({...flags, availability, version}, pkg); + const options = await ui({ + ...flags, + availability, + version, + runPublish + }, pkg); if (!options.confirm) { process.exit(0); diff --git a/source/index.js b/source/index.js index 64cf016c..562b9dd9 100644 --- a/source/index.js +++ b/source/index.js @@ -37,13 +37,6 @@ const exec = (cmd, args) => { // eslint-disable-next-line default-param-last module.exports = async (input = 'patch', options) => { - options = { - cleanup: true, - tests: true, - publish: true, - ...options - }; - if (!hasYarn() && options.yarn) { throw new Error('Could not use Yarn without yarn.lock file'); } @@ -56,7 +49,6 @@ module.exports = async (input = 'patch', options) => { const pkg = util.readPkg(options.contents); const runTests = options.tests && !options.yolo; const runCleanup = options.cleanup && !options.yolo; - const runPublish = options.publish && !pkg.private; const pkgManager = options.yarn === true ? 'yarn' : 'npm'; const pkgManagerName = options.yarn === true ? 'Yarn' : 'npm'; const rootDir = pkgDir.sync(); @@ -106,7 +98,7 @@ module.exports = async (input = 'patch', options) => { const tasks = new Listr([ { title: 'Prerequisite check', - enabled: () => runPublish, + enabled: () => options.runPublish, task: () => prerequisiteTasks(input, pkg, options) }, { @@ -194,7 +186,7 @@ module.exports = async (input = 'patch', options) => { } ]); - if (runPublish) { + if (options.runPublish) { tasks.add([ { title: `Publishing package using ${pkgManagerName}`, @@ -252,7 +244,7 @@ module.exports = async (input = 'patch', options) => { return '[Preview] Command not executed: git push --follow-tags.'; } - if (publishStatus === 'FAILED' && runPublish) { + if (publishStatus === 'FAILED' && options.runPublish) { return 'Couldn\'t publish package to npm; not pushing.'; } }, diff --git a/source/ui.js b/source/ui.js index d89217f9..caca34a5 100644 --- a/source/ui.js +++ b/source/ui.js @@ -56,9 +56,8 @@ module.exports = async (options, pkg) => { const repoUrl = pkg.repository && githubUrlFromGit(pkg.repository.url, {extraBaseUrls}); const pkgManager = options.yarn ? 'yarn' : 'npm'; const registryUrl = await getRegistryUrl(pkgManager, pkg); - const runPublish = options.publish && !pkg.private; - if (runPublish) { + if (options.runPublish) { checkIgnoreStrategy(pkg); } @@ -106,7 +105,7 @@ module.exports = async (options, pkg) => { type: 'list', name: 'tag', message: 'How should this pre-release version be tagged in npm?', - when: answers => options.publish && !pkg.private && version.isPrereleaseOrIncrement(answers.version) && !options.tag, + when: answers => options.runPublish && version.isPrereleaseOrIncrement(answers.version) && !options.tag, choices: async () => { const existingPrereleaseTags = await prereleaseTags(pkg.name); @@ -124,7 +123,7 @@ module.exports = async (options, pkg) => { type: 'input', name: 'tag', message: 'Tag', - when: answers => options.publish && !pkg.private && version.isPrereleaseOrIncrement(answers.version) && !options.tag && !answers.tag, + when: answers => options.runPublish && version.isPrereleaseOrIncrement(answers.version) && !options.tag && !answers.tag, validate: input => { if (input.length === 0) { return 'Please specify a tag, for example, `next`.'; @@ -140,7 +139,7 @@ module.exports = async (options, pkg) => { { type: 'confirm', name: 'publishScoped', - when: isScoped(pkg.name) && !options.availability.isAvailable && !options.availability.isUnknown && options.publish && !pkg.private, + when: isScoped(pkg.name) && !options.availability.isAvailable && !options.availability.isUnknown && options.runPublish && (pkg.publishConfig && pkg.publishConfig.access !== 'restricted'), message: `This scoped repo ${chalk.bold.magenta(pkg.name)} hasn't been published. Do you want to publish it publicly?`, default: false } @@ -177,7 +176,7 @@ module.exports = async (options, pkg) => { const answers = await inquirer.prompt([{ type: 'confirm', name: 'confirm', - when: isScoped(pkg.name) && options.publish && !pkg.private, + when: isScoped(pkg.name) && options.runPublish, message: `Failed to check availability of scoped repo name ${chalk.bold.magenta(pkg.name)}. Do you want to try and publish it anyway?`, default: false }]); diff --git a/test/index.js b/test/index.js index acafdcc8..52ca95d0 100644 --- a/test/index.js +++ b/test/index.js @@ -1,23 +1,30 @@ import test from 'ava'; import np from '../source'; +const defaultOptions = { + cleanup: true, + tests: true, + publish: true, + runPublish: true +}; + test('version is invalid', async t => { const message = 'Version should be either patch, minor, major, prepatch, preminor, premajor, prerelease, or a valid semver version.'; - await t.throwsAsync(np('foo'), message); - await t.throwsAsync(np('4.x.3'), message); + await t.throwsAsync(np('foo', defaultOptions), message); + await t.throwsAsync(np('4.x.3', defaultOptions), message); }); test('version is pre-release', async t => { const message = 'You must specify a dist-tag using --tag when publishing a pre-release version. This prevents accidentally tagging unstable versions as "latest". https://docs.npmjs.com/cli/dist-tag'; - await t.throwsAsync(np('premajor'), message); - await t.throwsAsync(np('preminor'), message); - await t.throwsAsync(np('prepatch'), message); - await t.throwsAsync(np('prerelease'), message); - await t.throwsAsync(np('10.0.0-0'), message); - await t.throwsAsync(np('10.0.0-beta'), message); + await t.throwsAsync(np('premajor', defaultOptions), message); + await t.throwsAsync(np('preminor', defaultOptions), message); + await t.throwsAsync(np('prepatch', defaultOptions), message); + await t.throwsAsync(np('prerelease', defaultOptions), message); + await t.throwsAsync(np('10.0.0-0', defaultOptions), message); + await t.throwsAsync(np('10.0.0-beta', defaultOptions), message); }); test('errors on too low version', async t => { - await t.throwsAsync(np('1.0.0'), /New version `1\.0\.0` should be higher than current version `\d+\.\d+\.\d+`/); - await t.throwsAsync(np('1.0.0-beta'), /New version `1\.0\.0-beta` should be higher than current version `\d+\.\d+\.\d+`/); + await t.throwsAsync(np('1.0.0', defaultOptions), /New version `1\.0\.0` should be higher than current version `\d+\.\d+\.\d+`/); + await t.throwsAsync(np('1.0.0-beta', defaultOptions), /New version `1\.0\.0-beta` should be higher than current version `\d+\.\d+\.\d+`/); });