Skip to content

Commit

Permalink
feat: Make sure published packages have a license
Browse files Browse the repository at this point in the history
  • Loading branch information
honzajavorek committed Jun 15, 2018
1 parent 02ac0ec commit 8fb8073
Show file tree
Hide file tree
Showing 43 changed files with 2,122 additions and 1,657 deletions.
3 changes: 2 additions & 1 deletion README.md
Expand Up @@ -298,7 +298,8 @@ More specifically, this command will:
3. Update the `package.json` of all updated packages to their new versions.
4. Update all dependencies of the updated packages with the new versions, specified with a [caret (^)](https://docs.npmjs.com/files/package.json#dependencies).
5. Create a new git commit and tag for the new version.
6. Publish updated packages to npm.
6. Make sure the updated packages contain license files before publishing. Use root license file if the packages do not contain their own.
7. Publish updated packages to npm.

> Lerna won't publish packages which are marked as private (`"private": true` in the `package.json`).
Expand Down
19 changes: 17 additions & 2 deletions commands/__mocks__/@lerna/npm-publish.js
@@ -1,12 +1,27 @@
"use strict";

const fs = require("fs-extra");
const path = require("path");

const registry = new Map();

// by default, act like a spy that populates registry
const mockNpmPublish = jest.fn((pkg, tag) => {
registry.set(pkg.name, tag);
const entry = { tag };
registry.set(pkg.name, entry);

return Promise.resolve()
.then(() => fs.readdir(pkg.location))
.then(filenames => {
entry.licenseBasename = filenames.find(f => f.match(/^licen[cs]e/i));

return Promise.resolve();
if (entry.licenseBasename) {
return fs.readFile(path.join(pkg.location, entry.licenseBasename), { encoding: "utf8" });
}
})
.then(licenseText => {
entry.licenseText = licenseText;
});
});

// keep test data isolated
Expand Down
@@ -0,0 +1,3 @@
{
"version": "1.0.0"
}
@@ -0,0 +1,4 @@
{
"name": "licenses-missing",
"version": "0.0.0-monorepo"
}
@@ -0,0 +1,4 @@
{
"name": "package-1",
"version": "1.0.0"
}
@@ -0,0 +1,3 @@
Copyright (c) 2018 Tester McPerson <test@example.com>

XYZ License
@@ -0,0 +1,4 @@
{
"name": "package-2",
"version": "1.0.0"
}
@@ -0,0 +1,4 @@
{
"name": "package-3",
"version": "1.0.0"
}
@@ -0,0 +1,4 @@
{
"name": "licenses-names",
"version": "0.0.0-monorepo"
}
@@ -0,0 +1,3 @@
Copyright (c) 2018 Tester McPerson <test@example.com>

ABC License
@@ -0,0 +1,4 @@
{
"name": "package-1",
"version": "1.0.0"
}
@@ -0,0 +1,3 @@
Copyright (c) 2018 Tester McPerson <test@example.com>

ABC License
@@ -0,0 +1,4 @@
{
"name": "package-2",
"version": "1.0.0"
}
@@ -0,0 +1,3 @@
Copyright (c) 2018 Tester McPerson <test@example.com>

ABC License
@@ -0,0 +1,4 @@
{
"name": "package-3",
"version": "1.0.0"
}
@@ -0,0 +1,3 @@
Copyright (c) 2018 Tester McPerson <test@example.com>

ABC License
@@ -0,0 +1,4 @@
{
"name": "package-4",
"version": "1.0.0"
}
@@ -0,0 +1,3 @@
Copyright (c) 2018 Tester McPerson <test@example.com>

ABC License
@@ -0,0 +1,3 @@
Copyright (c) 2018 Tester McPerson <test@example.com>

ABC License
@@ -0,0 +1,4 @@
{
"name": "package-5",
"version": "1.0.0"
}
3 changes: 3 additions & 0 deletions commands/publish/__tests__/__fixtures__/licenses/LICENSE
@@ -0,0 +1,3 @@
Copyright (c) 2018 Tester McPerson <test@example.com>

ABC License
3 changes: 3 additions & 0 deletions commands/publish/__tests__/__fixtures__/licenses/lerna.json
@@ -0,0 +1,3 @@
{
"version": "1.0.0"
}
4 changes: 4 additions & 0 deletions commands/publish/__tests__/__fixtures__/licenses/package.json
@@ -0,0 +1,4 @@
{
"name": "licenses",
"version": "0.0.0-monorepo"
}
@@ -0,0 +1,4 @@
{
"name": "package-1",
"version": "1.0.0"
}
@@ -0,0 +1,3 @@
Copyright (c) 2018 Tester McPerson <test@example.com>

XYZ License
@@ -0,0 +1,7 @@
{
"name": "package-2",
"version": "1.0.0",
"dependencies": {
"package-1": "^1.0.0"
}
}
Expand Up @@ -50,10 +50,26 @@ Map {

exports[`publish --canary --independent: npm published 1`] = `
Map {
"package-1" => "canary",
"package-3" => "canary",
"package-4" => "canary",
"package-2" => "canary",
"package-1" => Object {
"licenseBasename": undefined,
"licenseText": undefined,
"tag": "canary",
},
"package-3" => Object {
"licenseBasename": undefined,
"licenseText": undefined,
"tag": "canary",
},
"package-4" => Object {
"licenseBasename": undefined,
"licenseText": undefined,
"tag": "canary",
},
"package-2" => Object {
"licenseBasename": undefined,
"licenseText": undefined,
"tag": "canary",
},
}
`;

Expand Down Expand Up @@ -101,10 +117,26 @@ Map {

exports[`publish --canary: npm published 1`] = `
Map {
"package-1" => "canary",
"package-3" => "canary",
"package-4" => "canary",
"package-2" => "canary",
"package-1" => Object {
"licenseBasename": undefined,
"licenseText": undefined,
"tag": "canary",
},
"package-3" => Object {
"licenseBasename": undefined,
"licenseText": undefined,
"tag": "canary",
},
"package-4" => Object {
"licenseBasename": undefined,
"licenseText": undefined,
"tag": "canary",
},
"package-2" => Object {
"licenseBasename": undefined,
"licenseText": undefined,
"tag": "canary",
},
}
`;

Expand Down
Expand Up @@ -75,10 +75,26 @@ Successfully published:

exports[`PublishCommand independent mode publishes changed packages: npm published 1`] = `
Map {
"package-1" => undefined,
"package-3" => undefined,
"package-4" => undefined,
"package-2" => undefined,
"package-1" => Object {
"licenseBasename": undefined,
"licenseText": undefined,
"tag": undefined,
},
"package-3" => Object {
"licenseBasename": undefined,
"licenseText": undefined,
"tag": undefined,
},
"package-4" => Object {
"licenseBasename": undefined,
"licenseText": undefined,
"tag": undefined,
},
"package-2" => Object {
"licenseBasename": undefined,
"licenseText": undefined,
"tag": undefined,
},
}
`;

Expand Down Expand Up @@ -243,10 +259,26 @@ Successfully published:

exports[`PublishCommand normal mode publishes changed packages: npm published 1`] = `
Map {
"package-1" => undefined,
"package-3" => undefined,
"package-4" => undefined,
"package-2" => undefined,
"package-1" => Object {
"licenseBasename": undefined,
"licenseText": undefined,
"tag": undefined,
},
"package-3" => Object {
"licenseBasename": undefined,
"licenseText": undefined,
"tag": undefined,
},
"package-4" => Object {
"licenseBasename": undefined,
"licenseText": undefined,
"tag": undefined,
},
"package-2" => Object {
"licenseBasename": undefined,
"licenseText": undefined,
"tag": undefined,
},
}
`;

Expand Down
33 changes: 33 additions & 0 deletions commands/publish/__tests__/create-temp-licenses.test.js
@@ -0,0 +1,33 @@
"use strict";

const fs = require("fs-extra");
const path = require("path");

const initFixture = require("@lerna-test/init-fixture")(__dirname);
const createTempLicenses = require("../lib/create-temp-licenses");

test("creates temporary copy of the source license", async () => {
const cwd = await initFixture("licenses");

const pkg = { name: "package-1", location: path.join(cwd, "packages", "package-1") };
await createTempLicenses(path.join(cwd, "LICENSE"), [pkg]);

expect(fs.exists(path.join(pkg.location, "LICENSE"))).resolves.toBe(true);
});

test("resolves when source license path is missing", async () => {
const cwd = await initFixture("licenses");

const pkg = { name: "package-1", location: path.join(cwd, "packages", "package-1") };
await createTempLicenses(null, [pkg]);

expect(fs.exists(path.join(pkg.location, "LICENSE"))).resolves.toBe(false);
});

test("resolves when there are no packages", async () => {
const cwd = await initFixture("licenses");

await createTempLicenses(path.join(cwd, "LICENSE"), []);

expect(fs.exists(path.join(cwd, "packages", "package-1", "LICENSE"))).resolves.toBe(false);
});
36 changes: 36 additions & 0 deletions commands/publish/__tests__/get-license-path.test.js
@@ -0,0 +1,36 @@
"use strict";

const path = require("path");

const initFixture = require("@lerna-test/init-fixture")(__dirname);
const getLicensePath = require("../lib/get-license-path");

test("recognizes American spelling", async () => {
const cwd = await initFixture("licenses-names");

expect(getLicensePath(path.join(cwd, "packages", "package-1"))).resolves.toBe("LICENSE");
});

test("recognizes British spelling", async () => {
const cwd = await initFixture("licenses-names");

expect(getLicensePath(path.join(cwd, "packages", "package-2"))).resolves.toBe("licence");
});

test("doesn't mind upper or lower case", async () => {
const cwd = await initFixture("licenses-names");

expect(getLicensePath(path.join(cwd, "packages", "package-3"))).resolves.toBe("LiCeNSe");
});

test("resolves to null if there is no license file", async () => {
const cwd = await initFixture("licenses-names");

expect(getLicensePath(path.join(cwd, "packages", "package-4"))).resolves.toBeNull();
});

test("resolves to the first license file, alphabetically", async () => {
const cwd = await initFixture("licenses-names");

expect(getLicensePath(path.join(cwd, "packages", "package-5"))).resolves.toBe("LICENCE");
});
15 changes: 15 additions & 0 deletions commands/publish/__tests__/get-packages-without-license.test.js
@@ -0,0 +1,15 @@
"use strict";

const path = require("path");

const initFixture = require("@lerna-test/init-fixture")(__dirname);
const getPackagesWithoutLicense = require("../lib/get-packages-without-license");

test("getPackagesWithoutLicense", async () => {
const cwd = await initFixture("licenses");

const pkg1 = { name: "package-1", location: path.join(cwd, "packages", "package-1") };
const pkg2 = { name: "package-2", location: path.join(cwd, "packages", "package-2") };

expect(getPackagesWithoutLicense([pkg1, pkg2])).resolves.toEqual(expect.arrayContaining([pkg1]));
});

0 comments on commit 8fb8073

Please sign in to comment.