Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(unpublish): add workspace/dry-run support #3251

Merged
merged 1 commit into from
May 20, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions docs/content/commands/npm-unpublish.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,19 @@ passed.

<!-- AUTOGENERATED CONFIG DESCRIPTIONS START -->
<!-- automatically generated, do not edit manually -->
#### `dry-run`

* Default: false
* Type: Boolean

Indicates that you don't want npm to make any changes and that it should
only report what it would have done. This can be passed into any of the
commands that modify your local installation, eg, `install`, `update`,
`dedupe`, `uninstall`, as well as `pack` and `publish`.

Note: This is NOT honored by other network related commands, eg `dist-tags`,
`owner`, etc.

#### `force`

* Default: false
Expand All @@ -73,6 +86,38 @@ mistakes, unnecessary performance degradation, and malicious input.
If you don't have a clear idea of what you want to do, it is strongly
recommended that you do not use this option!

#### `workspace`

* Default:
* Type: String (can be set multiple times)

Enable running a command in the context of the configured workspaces of the
current project while filtering by running only the workspaces defined by
this configuration option.

Valid values for the `workspace` config are either:

* Workspace names
* Path to a workspace directory
* Path to a parent workspace directory (will result to selecting all of the
nested workspaces)

When set for the `npm init` command, this may be set to the folder of a
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this was copied over from npm init but should be updated to reflect usage for npm unpublish

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No this is automatically generated from the config definition https://github.com/npm/cli/blob/release-next/lib/utils/config/definitions.js#L2079-L2081

workspace which does not yet exist, to create the folder and set it up as a
brand new workspace within the project.

This value is not exported to the environment for child processes.

#### `workspaces`

* Default: false
* Type: Boolean

Enable running a command in the context of **all** the configured
workspaces.

This value is not exported to the environment for child processes.

<!-- AUTOGENERATED CONFIG DESCRIPTIONS END -->

### See Also
Expand Down
2 changes: 1 addition & 1 deletion lib/publish.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ class Publish extends BaseCommand {
if (args.length === 0)
args = ['.']
if (args.length !== 1)
throw this.usage
throw this.usageError()

log.verbose('publish', args)

Expand Down
58 changes: 40 additions & 18 deletions lib/unpublish.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
const path = require('path')
const util = require('util')
const log = require('npmlog')
const npa = require('npm-package-arg')
const libaccess = require('libnpmaccess')
const npmFetch = require('npm-registry-fetch')
const libunpub = require('libnpmpublish').unpublish
const readJson = util.promisify(require('read-package-json'))

const getWorkspaces = require('./workspaces/get-workspaces.js')
const otplease = require('./utils/otplease.js')
const getIdentity = require('./utils/get-identity.js')

Expand All @@ -22,13 +22,13 @@ class Unpublish extends BaseCommand {
}

/* istanbul ignore next - see test/lib/load-all-commands.js */
static get usage () {
return ['[<@scope>/]<pkg>[@<version>]']
static get params () {
return ['dry-run', 'force', 'workspace', 'workspaces']
}

/* istanbul ignore next - see test/lib/load-all-commands.js */
static get params () {
return ['force']
static get usage () {
return ['[<@scope>/]<pkg>[@<version>]']
}

async completion (args) {
Expand Down Expand Up @@ -67,25 +67,29 @@ class Unpublish extends BaseCommand {
this.unpublish(args).then(() => cb()).catch(cb)
}

execWorkspaces (args, filters, cb) {
this.unpublishWorkspaces(args, filters).then(() => cb()).catch(cb)
}

async unpublish (args) {
if (args.length > 1)
throw new Error(this.usage)
throw this.usageError()

const spec = args.length && npa(args[0])
const force = this.npm.config.get('force')
const silent = this.npm.config.get('silent')
const loglevel = this.npm.config.get('loglevel')
const silent = loglevel === 'silent'
const dryRun = this.npm.config.get('dry-run')
let pkgName
let pkgVersion

log.silly('unpublish', 'args[0]', args[0])
log.silly('unpublish', 'spec', spec)
this.npm.log.silly('unpublish', 'args[0]', args[0])
this.npm.log.silly('unpublish', 'spec', spec)

if (!spec.rawSpec && !force) {
throw new Error(
if ((!spec || !spec.rawSpec) && !force) {
throw this.usageError(
'Refusing to delete entire project.\n' +
'Run with --force to do this.\n' +
this.usage
'Run with --force to do this.'
)
}

Expand All @@ -101,25 +105,43 @@ class Unpublish extends BaseCommand {
if (err && err.code !== 'ENOENT' && err.code !== 'ENOTDIR')
throw err
else
throw new Error(`Usage: ${this.usage}`)
throw this.usageError()
}

log.verbose('unpublish', manifest)
this.npm.log.verbose('unpublish', manifest)

const { name, version, publishConfig } = manifest
const pkgJsonSpec = npa.resolve(name, version)
const optsWithPub = { ...opts, publishConfig }
await otplease(opts, opts => libunpub(pkgJsonSpec, optsWithPub))
if (!dryRun)
await otplease(opts, opts => libunpub(pkgJsonSpec, optsWithPub))
pkgName = name
pkgVersion = version ? `@${version}` : ''
} else {
await otplease(opts, opts => libunpub(spec, opts))
if (!dryRun)
await otplease(opts, opts => libunpub(spec, opts))
pkgName = spec.name
pkgVersion = spec.type === 'version' ? `@${spec.rawSpec}` : ''
}

if (!silent && loglevel !== 'silent')
if (!silent)
this.npm.output(`- ${pkgName}${pkgVersion}`)
}

async unpublishWorkspaces (args, filters) {
const workspaces =
await getWorkspaces(filters, { path: this.npm.localPrefix })

const force = this.npm.config.get('force')
if (!force) {
throw this.usageError(
'Refusing to delete entire project(s).\n' +
'Run with --force to do this.'
)
}

for (const [name] of workspaces.entries())
await this.unpublish([name])
}
}
module.exports = Unpublish
4 changes: 3 additions & 1 deletion tap-snapshots/test/lib/load-all-commands.js.test.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -1005,7 +1005,9 @@ Usage:
npm unpublish [<@scope>/]<pkg>[@<version>]

Options:
[-f|--force]
[--dry-run] [-f|--force]
[-w|--workspace <workspace-name> [-w|--workspace <workspace-name> ...]]
[-ws|--workspaces]

Run "npm help unpublish" for more info
`
Expand Down
23 changes: 21 additions & 2 deletions tap-snapshots/test/lib/publish.js.test.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
*/
'use strict'
exports[`test/lib/publish.js TAP shows usage with wrong set of arguments > should print usage 1`] = `
npm publish
Error:
Usage: npm publish

Publish a package

Expand All @@ -18,13 +19,16 @@ Options:
[-w|--workspace <workspace-name> [-w|--workspace <workspace-name> ...]]
[-ws|--workspaces]

Run "npm help publish" for more info
Run "npm help publish" for more info {
"code": "EUSAGE",
}
`

exports[`test/lib/publish.js TAP workspaces all workspaces > should output all publishes 1`] = `
Array [
"+ [email protected]",
"+ [email protected]",
"+ [email protected]",
]
`

Expand Down Expand Up @@ -54,6 +58,12 @@ Array [
},
"version": "1.2.3-n",
},
Object {
"_id": "[email protected]",
"name": "workspace-n",
"readme": "ERROR: No README data found!",
"version": "1.2.3-n",
},
]
`

Expand All @@ -66,6 +76,9 @@ Array [
},
"workspace-b": {
"id": "[email protected]"
},
"workspace-n": {
"id": "[email protected]"
}
}
),
Expand Down Expand Up @@ -98,6 +111,12 @@ Array [
},
"version": "1.2.3-n",
},
Object {
"_id": "[email protected]",
"name": "workspace-n",
"readme": "ERROR: No README data found!",
"version": "1.2.3-n",
},
]
`

Expand Down
14 changes: 14 additions & 0 deletions tap-snapshots/test/lib/unpublish.js.test.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/* IMPORTANT
* This snapshot file is auto-generated, but designed for humans.
* It should be checked into source control and tracked carefully.
* Re-generate by setting TAP_SNAPSHOT=1 and running tests.
* Make sure to inspect the output below. Do not ignore changes!
*/
'use strict'
exports[`test/lib/unpublish.js TAP workspaces all workspaces --force > should output all workspaces 1`] = `
- workspace-a- workspace-b- workspace-n
`

exports[`test/lib/unpublish.js TAP workspaces one workspace --force > should output one workspaces 1`] = `
- workspace-a
`
4 changes: 3 additions & 1 deletion tap-snapshots/test/lib/utils/npm-usage.js.test.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -1046,7 +1046,9 @@ All commands:
npm unpublish [<@scope>/]<pkg>[@<version>]

Options:
[-f|--force]
[--dry-run] [-f|--force]
[-w|--workspace <workspace-name> [-w|--workspace <workspace-name> ...]]
[-ws|--workspaces]

Run "npm help unpublish" for more info

Expand Down
8 changes: 4 additions & 4 deletions test/lib/publish.js
Original file line number Diff line number Diff line change
Expand Up @@ -538,12 +538,12 @@ t.test('workspaces', (t) => {
repository: 'https://github.com/npm/workspace-b',
}),
},
'workspace-c': JSON.stringify({
'package.json': {
'workspace-c': {
'package.json': JSON.stringify({
name: 'workspace-n',
version: '1.2.3-n',
},
}),
}),
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch 👍

})

const publishes = []
Expand Down
Loading