diff --git a/__tests__/__mocks__/npm-registry.js b/__tests__/__mocks__/npm-registry.js new file mode 100644 index 0000000000..c5f54cb2a7 --- /dev/null +++ b/__tests__/__mocks__/npm-registry.js @@ -0,0 +1,10 @@ +/* @flow */ + +import Registry from '../../src/registries/base-registry.js'; +import type {RegistryRequestOptions} from '../../src/registries/base-registry.js'; + +export default class NpmRegistry extends Registry { + request(pathname: string, opts?: RegistryRequestOptions = {}, packageName: ?string): Promise<*> { + return new Promise(resolve => resolve()); + } +} diff --git a/__tests__/commands/publish.js b/__tests__/commands/publish.js new file mode 100644 index 0000000000..aaee892112 --- /dev/null +++ b/__tests__/commands/publish.js @@ -0,0 +1,101 @@ +/* @flow */ + +import {run as buildRun} from './_helpers.js'; +import {run as publish} from '../../src/cli/commands/publish.js'; +import {ConsoleReporter} from '../../src/reporters/index.js'; + +const path = require('path'); + +const fixturesLoc = path.join(__dirname, '..', 'fixtures', 'publish'); + +const setupMocks = function(config) { + // Mock actual network request so that no package is actually published. + // $FlowFixMe + config.registries.npm.request = jest.fn(); + config.registries.npm.request.mockReturnValue( + new Promise(resolve => { + resolve({status: 200}); + }), + ); + + // Mock the npm login name. Otherwise yarn will prompt for it and break CI. + // $FlowFixMe + config.registries.npm.getAuth = jest.fn(); + config.registries.npm.getAuth.mockReturnValue('test'); +}; + +const runPublish = buildRun.bind( + null, + ConsoleReporter, + fixturesLoc, + async (args, flags, config, reporter, lockfile, getStdout): Promise => { + setupMocks(config); + await publish(config, reporter, flags, args); + return getStdout(); + }, +); + +test.concurrent('publish should default access to undefined', () => { + return runPublish([], {newVersion: '0.0.1'}, 'minimal', config => { + expect(config.registries.npm.request).toBeCalledWith( + expect.any(String), + expect.objectContaining({ + body: expect.objectContaining({ + access: undefined, + }), + }), + ); + }); +}); + +test.concurrent('publish should accept `--access restricted` argument', () => { + return runPublish([], {newVersion: '0.0.1', access: 'restricted'}, 'minimal', config => { + expect(config.registries.npm.request).toBeCalledWith( + expect.any(String), + expect.objectContaining({ + body: expect.objectContaining({ + access: 'restricted', + }), + }), + ); + }); +}); + +test.concurrent('publish should accept `--access public` argument', () => { + return runPublish([], {newVersion: '0.0.1', access: 'public'}, 'minimal', config => { + expect(config.registries.npm.request).toBeCalledWith( + expect.any(String), + expect.objectContaining({ + body: expect.objectContaining({ + access: 'public', + }), + }), + ); + }); +}); + +test.concurrent('publish should use publishConfig.access in package manifest', () => { + return runPublish([], {newVersion: '0.0.1'}, 'public', config => { + expect(config.registries.npm.request).toBeCalledWith( + expect.any(String), + expect.objectContaining({ + body: expect.objectContaining({ + access: 'public', + }), + }), + ); + }); +}); + +test.concurrent('publish should allow `--access` to override publishConfig.access', () => { + return runPublish([], {newVersion: '0.0.1', access: 'restricted'}, 'public', config => { + expect(config.registries.npm.request).toBeCalledWith( + expect.any(String), + expect.objectContaining({ + body: expect.objectContaining({ + access: 'restricted', + }), + }), + ); + }); +}); diff --git a/__tests__/fixtures/publish/minimal/package.json b/__tests__/fixtures/publish/minimal/package.json new file mode 100644 index 0000000000..1545befa16 --- /dev/null +++ b/__tests__/fixtures/publish/minimal/package.json @@ -0,0 +1,4 @@ +{ + "name": "test", + "version": "0.0.0" +} diff --git a/__tests__/fixtures/publish/public/package.json b/__tests__/fixtures/publish/public/package.json new file mode 100644 index 0000000000..0de9c86d5d --- /dev/null +++ b/__tests__/fixtures/publish/public/package.json @@ -0,0 +1,7 @@ +{ + "name": "test", + "version": "0.0.0", + "publishConfig": { + "access": "public" + } +} diff --git a/src/cli/commands/publish.js b/src/cli/commands/publish.js index ee16431e4b..d53ed1ebe7 100644 --- a/src/cli/commands/publish.js +++ b/src/cli/commands/publish.js @@ -27,8 +27,15 @@ export function hasWrapper(commander: Object, args: Array): boolean { } async function publish(config: Config, pkg: any, flags: Object, dir: string): Promise { + let access = flags.access; + + // if no access level is provided, check package.json for `publishConfig.access` + // see: https://docs.npmjs.com/files/package.json#publishconfig + if (!access && pkg && pkg.publishConfig && pkg.publishConfig.access) { + access = pkg.publishConfig.access; + } + // validate access argument - const access = flags.access; if (access && access !== 'public' && access !== 'restricted') { throw new MessageError(config.reporter.lang('invalidAccess')); } @@ -69,7 +76,7 @@ async function publish(config: Config, pkg: any, flags: Object, dir: string): Pr // create body const root = { _id: pkg.name, - access: flags.access, + access, name: pkg.name, description: pkg.description, 'dist-tags': {