Skip to content

Commit

Permalink
feat(npm-dist-tag): Remove figgy-pudding
Browse files Browse the repository at this point in the history
  • Loading branch information
evocateur committed Nov 20, 2020
1 parent 621b382 commit 1158f8e
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 60 deletions.
2 changes: 0 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

49 changes: 31 additions & 18 deletions utils/npm-dist-tag/__tests__/npm-dist-tag.test.js
Expand Up @@ -9,32 +9,30 @@ const fetch = require("npm-registry-fetch");
// file under test
const npmDistTag = require("..");

expect.extend(require("@lerna-test/figgy-pudding-matchers"));

const stubLog = {
verbose: jest.fn(),
info: jest.fn(),
warn: jest.fn(),
};
const baseOptions = new Map([
["log", stubLog],
["tag", "latest"],
]);
const baseOptions = Object.freeze({
log: stubLog,
defaultTag: "latest",
});

fetch.mockImplementation(() => Promise.resolve());
fetch.json.mockImplementation(() => Promise.resolve({}));

describe("npmDistTag.add()", () => {
it("adds a dist-tag for a given package@version", async () => {
const opts = new Map(baseOptions);
const opts = { ...baseOptions };
const tags = await npmDistTag.add("@scope/some-pkg@1.0.1", "added-tag", opts);

expect(tags).toEqual({
"added-tag": "1.0.1",
});
expect(fetch).toHaveBeenLastCalledWith(
"/-/package/@scope%2fsome-pkg/dist-tags/added-tag",
expect.figgyPudding({
expect.objectContaining({
method: "PUT",
body: JSON.stringify("1.0.1"),
headers: {
Expand All @@ -52,7 +50,7 @@ describe("npmDistTag.add()", () => {
})
);

const opts = new Map(baseOptions);
const opts = { ...baseOptions };
const tags = await npmDistTag.add("@scope/some-pkg@1.0.1", "dupe-tag", opts);

expect(tags).toEqual({
Expand All @@ -66,20 +64,35 @@ describe("npmDistTag.add()", () => {
);
});

it("defaults tag argument to opts.tag", async () => {
it("defaults tag argument to opts.defaultTag", async () => {
fetch.json.mockImplementationOnce(() =>
Promise.resolve({
latest: "1.0.0",
})
);

const opts = new Map(baseOptions);
const opts = { ...baseOptions };
const tags = await npmDistTag.add("@scope/some-pkg@1.0.1", undefined, opts);

expect(tags).toEqual({
latest: "1.0.1",
});
});

it("supports npm v6 opts.tag fallback", async () => {
fetch.json.mockImplementationOnce(() =>
Promise.resolve({
legacy: "1.0.0",
})
);

const opts = { log: stubLog, tag: "legacy" };
const tags = await npmDistTag.add("@scope/some-pkg@1.0.1", undefined, opts);

expect(tags).toEqual({
legacy: "1.0.1",
});
});
});

describe("npmDistTag.remove()", () => {
Expand All @@ -91,20 +104,20 @@ describe("npmDistTag.remove()", () => {
})
);

const opts = new Map(baseOptions);
const opts = { ...baseOptions };
const tags = await npmDistTag.remove("@scope/some-pkg@1.0.1", "removed-tag", opts);

expect(tags).not.toHaveProperty("removed-tag");
expect(fetch).toHaveBeenLastCalledWith(
"/-/package/@scope%2fsome-pkg/dist-tags/removed-tag",
expect.figgyPudding({
expect.objectContaining({
method: "DELETE",
})
);
});

it("does not attempt removal of nonexistent tag", async () => {
const opts = new Map(baseOptions);
const opts = { ...baseOptions };
const tags = await npmDistTag.remove("@scope/some-pkg@1.0.1", "missing-tag", opts);

expect(tags).toEqual({});
Expand All @@ -126,7 +139,7 @@ describe("npmDistTag.list()", () => {
})
);

const opts = new Map(baseOptions);
const opts = { ...baseOptions };
const tags = await npmDistTag.list("@scope/some-pkg", opts);

expect(tags).toEqual({
Expand All @@ -135,8 +148,8 @@ describe("npmDistTag.list()", () => {
});
expect(fetch.json).toHaveBeenLastCalledWith(
"/-/package/@scope%2fsome-pkg/dist-tags",
expect.figgyPudding({
"prefer-online": true,
expect.objectContaining({
preferOnline: true,
spec: expect.objectContaining({
name: "@scope/some-pkg",
}),
Expand All @@ -150,7 +163,7 @@ describe("npmDistTag.list()", () => {
Promise.resolve(null)
);

const opts = new Map(baseOptions);
const opts = { ...baseOptions };
const tags = await npmDistTag.list("@scope/some-pkg", opts);

expect(tags).toEqual({});
Expand Down
93 changes: 54 additions & 39 deletions utils/npm-dist-tag/npm-dist-tag.js
Expand Up @@ -3,35 +3,30 @@
const log = require("npmlog");
const npa = require("npm-package-arg");
const fetch = require("npm-registry-fetch");
const figgyPudding = require("figgy-pudding");
const otplease = require("@lerna/otplease");

exports.add = add;
exports.remove = remove;
exports.list = list;

const DistTagConfig = figgyPudding(
{
"dry-run": { default: false },
dryRun: "dry-run",
log: { default: log },
spec: {},
tag: {},
},
{
other() {
// open it up for the sake of tests
return true;
},
}
);

function add(spec, tag, _opts, otpCache) {
const opts = DistTagConfig(_opts, {
/**
* @typedef {fetch.FetchOptions & { defaultTag?: string; dryRun?: boolean; }} DistTagOptions
*/

/**
* Add a dist-tag to a package.
* @param {string} spec
* @param {string} [tag]
* @param {DistTagOptions} options
* @param {import("@lerna/otplease").OneTimePasswordCache} otpCache
*/
function add(spec, tag, options, otpCache) {
const opts = {
log,
...options,
spec: npa(spec),
tag,
});
const cleanTag = opts.tag.trim();
};
const cleanTag = (tag || opts.defaultTag || opts.tag).trim();

const { name, rawSpec: version } = opts.spec;

Expand All @@ -50,7 +45,8 @@ function add(spec, tag, _opts, otpCache) {
}

const uri = `/-/package/${opts.spec.escapedName}/dist-tags/${encodeURIComponent(cleanTag)}`;
const payload = opts.concat({
const payload = {
...opts,
method: "PUT",
body: JSON.stringify(version),
headers: {
Expand All @@ -59,7 +55,7 @@ function add(spec, tag, _opts, otpCache) {
"content-type": "application/json",
},
spec: opts.spec,
});
};

// success returns HTTP 204, thus no JSON to parse
return otplease((wrappedPayload) => fetch(uri, wrappedPayload), payload, otpCache).then(() => {
Expand All @@ -73,10 +69,19 @@ function add(spec, tag, _opts, otpCache) {
});
}

function remove(spec, tag, _opts, otpCache) {
const opts = DistTagConfig(_opts, {
/**
* Remove a dist-tag from a package.
* @param {string} spec
* @param {string} tag
* @param {DistTagOptions} options
* @param {import("@lerna/otplease").OneTimePasswordCache} otpCache
*/
function remove(spec, tag, options, otpCache) {
const opts = {
log,
...options,
spec: npa(spec),
});
};

opts.log.verbose("dist-tag", `removing "${tag}" from ${opts.spec.name}`);

Expand All @@ -95,10 +100,11 @@ function remove(spec, tag, _opts, otpCache) {
}

const uri = `/-/package/${opts.spec.escapedName}/dist-tags/${encodeURIComponent(tag)}`;
const payload = opts.concat({
const payload = {
...opts,
method: "DELETE",
spec: opts.spec,
});
};

// the delete properly returns a 204, so no json to parse
return otplease((wrappedPayload) => fetch(uri, wrappedPayload), payload, otpCache).then(() => {
Expand All @@ -112,10 +118,17 @@ function remove(spec, tag, _opts, otpCache) {
});
}

function list(spec, _opts) {
const opts = DistTagConfig(_opts, {
/**
* List dist-tags of a package.
* @param {string} spec
* @param {DistTagOptions} options
*/
function list(spec, options) {
const opts = {
log,
...options,
spec: npa(spec),
});
};

// istanbul ignore next
if (opts.dryRun) {
Expand All @@ -126,15 +139,17 @@ function list(spec, _opts) {
return fetchTags(opts);
}

/**
* Retrieve list of dist-tags for a package.
* @param {Omit<fetch.FetchOptions, 'spec'> & { spec: npa.Result }} opts
*/
function fetchTags(opts) {
return fetch
.json(
`/-/package/${opts.spec.escapedName}/dist-tags`,
opts.concat({
"prefer-online": true,
spec: opts.spec,
})
)
.json(`/-/package/${opts.spec.escapedName}/dist-tags`, {
...opts,
preferOnline: true,
spec: opts.spec,
})
.then((data) => {
if (data && typeof data === "object") {
// eslint-disable-next-line no-param-reassign, no-underscore-dangle
Expand Down
1 change: 0 additions & 1 deletion utils/npm-dist-tag/package.json
Expand Up @@ -33,7 +33,6 @@
},
"dependencies": {
"@lerna/otplease": "file:../../core/otplease",
"figgy-pudding": "^3.5.1",
"npm-package-arg": "^8.1.0",
"npm-registry-fetch": "^9.0.0",
"npmlog": "^4.1.2"
Expand Down

0 comments on commit 1158f8e

Please sign in to comment.