diff --git a/workspaces/libnpmpublish/lib/get-pathname.js b/workspaces/libnpmpublish/lib/get-pathname.js new file mode 100644 index 0000000000000..a0001465cfae6 --- /dev/null +++ b/workspaces/libnpmpublish/lib/get-pathname.js @@ -0,0 +1,22 @@ +'use strict' + +const { URL } = require('url') + +// given a tarball url and a registry url, returns just the +// relevant pathname portion of it, so that it can be handled +// elegantly by npm-registry-fetch which only expects pathnames +// and handles the registry hostname via opts +function getPathname (tarball, registry) { + const registryUrl = new URL(registry).pathname.substring(1) + let tarballUrl = new URL(tarball).pathname.substring(1) + + // test the tarball url to see if it starts with a possible + // pathname from the registry url, in that case strips that portion + // of it so that we only return the post-registry-url pathname + if (registryUrl) { + tarballUrl = tarballUrl.substring(registryUrl.length) + } + return tarballUrl +} + +module.exports = getPathname diff --git a/workspaces/libnpmpublish/lib/unpublish.js b/workspaces/libnpmpublish/lib/unpublish.js index 7fbeea503a337..7dc2bf0675b00 100644 --- a/workspaces/libnpmpublish/lib/unpublish.js +++ b/workspaces/libnpmpublish/lib/unpublish.js @@ -3,7 +3,7 @@ const npa = require('npm-package-arg') const npmFetch = require('npm-registry-fetch') const semver = require('semver') -const { URL } = require('url') +const getPathname = require('./get-pathname.js') const unpublish = async (spec, opts) => { spec = npa(spec) @@ -82,7 +82,7 @@ const unpublish = async (spec, opts) => { ...opts, query: { write: true }, }) - const tarballUrl = new URL(dist.tarball).pathname.substr(1) + const tarballUrl = getPathname(dist.tarball, opts.registry) await npmFetch(`${tarballUrl}/-rev/${_rev}`, { ...opts, method: 'DELETE', diff --git a/workspaces/libnpmpublish/test/get-pathname.js b/workspaces/libnpmpublish/test/get-pathname.js new file mode 100644 index 0000000000000..c2a60c7015b21 --- /dev/null +++ b/workspaces/libnpmpublish/test/get-pathname.js @@ -0,0 +1,20 @@ +'use strict' + +const t = require('tap') +const getPathname = require('../lib/get-pathname.js') + +const defaultRegistry = 'https://registry.npmjs.org/' +const pathnameRegistry = + 'https://artifactory.example.com/api/npm/npm-snapshots/' + +t.equal( + getPathname(`${defaultRegistry}foo/bar`, defaultRegistry), + 'foo/bar', + 'should match a pathname in default registry' +) + +t.equal( + getPathname(`${pathnameRegistry}foo/bar`, pathnameRegistry), + 'foo/bar', + 'should match a pathname in default registry' +) diff --git a/workspaces/libnpmpublish/test/unpublish.js b/workspaces/libnpmpublish/test/unpublish.js index 6fbe802766024..b59dad6d36a06 100644 --- a/workspaces/libnpmpublish/test/unpublish.js +++ b/workspaces/libnpmpublish/test/unpublish.js @@ -134,6 +134,61 @@ t.test('unpublish specific version', async t => { t.ok(ret, 'foo was unpublished') }) +t.test('unpublishing from a custom registry', async t => { + const opt = { + registry: 'https://artifactory.example.com/api/npm/npm-snapshots/', + } + const reg = opt.registry + const doc = { + _id: 'foo', + _rev: REV, + _revisions: [1, 2, 3], + _attachments: [1, 2, 3], + name: 'foo', + 'dist-tags': { + latest: '1.0.1', + }, + versions: { + '1.0.0': { + name: 'foo', + dist: { + tarball: `${reg}/foo/-/foo-1.0.0.tgz`, + }, + }, + '1.0.1': { + name: 'foo', + dist: { + tarball: `${reg}/foo/-/foo-1.0.1.tgz`, + }, + }, + }, + } + const postEdit = { + _id: 'foo', + _rev: REV, + name: 'foo', + 'dist-tags': { + latest: '1.0.0', + }, + versions: { + '1.0.0': { + name: 'foo', + dist: { + tarball: `${reg}/foo/-/foo-1.0.0.tgz`, + }, + }, + }, + } + + const srv = tnock(t, reg) + srv.get('/foo?write=true').reply(200, doc) + srv.put(`/foo/-rev/${REV}`, postEdit).reply(200) + srv.get('/foo?write=true').reply(200, postEdit) + srv.delete(`/foo/-/foo-1.0.1.tgz/-rev/${REV}`).reply(200) + const ret = await unpub('foo@1.0.1', opt) + t.ok(ret, 'foo was unpublished') +}) + t.test('404 considered a success', async t => { const srv = tnock(t, REG) srv.get('/foo?write=true').reply(404)