From 0bb857df3c589725cafb9fdb38e28df36f697ba0 Mon Sep 17 00:00:00 2001 From: Nicola Molinari Date: Tue, 14 Apr 2020 22:00:53 +0200 Subject: [PATCH] fix: nested packages detection --- package.json | 3 +- src/__mocks__/changelog.ts | 2 +- src/changelog.spec.ts | 22 +--- src/changelog.ts | 29 ++--- src/configuration.ts | 5 +- .../__snapshots__/markdown-empty.spec.ts.snap | 4 +- .../__snapshots__/markdown-full.spec.ts.snap | 24 ++-- src/functional/markdown-empty.spec.ts | 116 +++++++++++------- src/functional/markdown-full.spec.ts | 63 +++++++--- src/git.ts | 5 + src/packages.ts | 91 ++++++++++++++ tsconfig.json | 1 + yarn.lock | 101 +++++++++++++++ 13 files changed, 353 insertions(+), 113 deletions(-) create mode 100644 src/packages.ts diff --git a/package.json b/package.json index c9c31d2b..88f2fed4 100644 --- a/package.json +++ b/package.json @@ -36,6 +36,7 @@ "chalk": "^2.4.1", "cli-highlight": "^2.1.4", "execa": "^1.0.0", + "globby": "^11.0.0", "hosted-git-info": "^3.0.4", "make-fetch-happen": "^7.1.1", "p-map": "^3.0.0", @@ -99,4 +100,4 @@ "singleQuote": false, "trailingComma": "es5" } -} +} \ No newline at end of file diff --git a/src/__mocks__/changelog.ts b/src/__mocks__/changelog.ts index 8b424a26..f09cccf3 100644 --- a/src/__mocks__/changelog.ts +++ b/src/__mocks__/changelog.ts @@ -3,7 +3,7 @@ import { Configuration } from "../configuration"; const Changelog = require.requireActual("../changelog").default; const defaultConfig = { - rootPath: "../", + rootPath: "/path/to/project", repo: "lerna/lerna-changelog", labels: { "Type: New Feature": ":rocket: New Feature", diff --git a/src/changelog.spec.ts b/src/changelog.spec.ts index 460d7dd4..2a3d3cfb 100644 --- a/src/changelog.spec.ts +++ b/src/changelog.spec.ts @@ -3,29 +3,9 @@ jest.mock("../src/changelog"); jest.mock("../src/github-api"); jest.mock("./git"); jest.mock("./fetch"); +jest.mock("./packages"); describe("Changelog", () => { - describe("packageFromPath", () => { - const MockedChangelog = require("./changelog").default; - - const TESTS = [ - ["", ""], - ["foo.js", ""], - ["packages/foo.js", ""], - ["packages/foo/bar.js", "foo"], - ["packages/foo/bar/baz.js", "foo"], - ["packages/@foo/bar.js", "@foo"], - ["packages/@foo/bar/baz.js", "@foo/bar"], - ]; - - for (let [input, expected] of TESTS) { - it(`${input} -> ${expected}`, () => { - const changelog = new MockedChangelog(); - expect(changelog.packageFromPath(input)).toEqual(expected); - }); - } - }); - describe("getCommitInfos", () => { beforeEach(() => { require("./fetch").__resetMockResponses(); diff --git a/src/changelog.ts b/src/changelog.ts index 75f2aa49..a5cdb6f9 100644 --- a/src/changelog.ts +++ b/src/changelog.ts @@ -1,3 +1,4 @@ +const path = require("path"); const pMap = require("p-map"); import progressBar from "./progress-bar"; @@ -6,6 +7,7 @@ import findPullRequestId from "./find-pull-request-id"; import * as Git from "./git"; import GithubAPI, { GitHubUserResponse } from "./github-api"; import { CommitInfo, Release } from "./interfaces"; +import { getPackages, PackageInfo } from "./packages"; import MarkdownRenderer from "./markdown-renderer"; const UNRELEASED_TAG = "___unreleased___"; @@ -71,26 +73,20 @@ export default class Changelog { return releases; } - private async getListOfUniquePackages(sha: string): Promise { + private async getListOfUniquePackages(sha: string, workspacePackages: PackageInfo[]): Promise { return (await Git.changedPaths(sha)) - .map(path => this.packageFromPath(path)) + .map(filePath => { + const fullFilePath = path.join(this.config.rootPath, filePath); + const matchingPackageFromPath = workspacePackages.find(packageInfo => { + return fullFilePath.startsWith(packageInfo.location); + }); + if (matchingPackageFromPath) return matchingPackageFromPath.name; + return ""; + }) .filter(Boolean) .filter(onlyUnique); } - private packageFromPath(path: string): string { - const parts = path.split("/"); - if (parts[0] !== "packages" || parts.length < 3) { - return ""; - } - - if (parts.length >= 4 && parts[1][0] === "@") { - return `${parts[1]}/${parts[2]}`; - } - - return parts[1]; - } - private getListOfCommits(from: string, to: string): Git.CommitListItem[] { // Determine the tags range to get the commits for. Custom from/to can be // provided via command-line options. @@ -214,12 +210,13 @@ export default class Changelog { private async fillInPackages(commits: CommitInfo[]) { progressBar.init("Mapping commits to packages…", commits.length); + const workspacePackages = await getPackages(this.config); try { await pMap( commits, async (commit: CommitInfo) => { - commit.packages = await this.getListOfUniquePackages(commit.commitSHA); + commit.packages = await this.getListOfUniquePackages(commit.commitSHA, workspacePackages); progressBar.tick(); }, diff --git a/src/configuration.ts b/src/configuration.ts index ae82465c..52a81377 100644 --- a/src/configuration.ts +++ b/src/configuration.ts @@ -4,6 +4,7 @@ const execa = require("execa"); const hostedGitInfo = require("hosted-git-info"); import ConfigurationError from "./configuration-error"; +import { getRootPath } from "./git"; export interface Configuration { repo: string; @@ -20,9 +21,7 @@ export interface ConfigLoaderOptions { } export function load(options: ConfigLoaderOptions = {}): Configuration { - let cwd = process.cwd(); - let rootPath = execa.sync("git", ["rev-parse", "--show-toplevel"], { cwd }).stdout; - + let rootPath = getRootPath(); return fromPath(rootPath, options); } diff --git a/src/functional/__snapshots__/markdown-empty.spec.ts.snap b/src/functional/__snapshots__/markdown-empty.spec.ts.snap index bd1d5286..9fdd6c81 100644 --- a/src/functional/__snapshots__/markdown-empty.spec.ts.snap +++ b/src/functional/__snapshots__/markdown-empty.spec.ts.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`createMarkdown multiple tags outputs correct changelog 1`] = `""`; + exports[`createMarkdown single project outputs correct changelog 1`] = `""`; exports[`createMarkdown single tags outputs correct changelog 1`] = `""`; - -exports[`multiple tags outputs correct changelog 1`] = `""`; diff --git a/src/functional/__snapshots__/markdown-full.spec.ts.snap b/src/functional/__snapshots__/markdown-full.spec.ts.snap index d0b9f7d4..e177f3d6 100644 --- a/src/functional/__snapshots__/markdown-full.spec.ts.snap +++ b/src/functional/__snapshots__/markdown-full.spec.ts.snap @@ -5,7 +5,7 @@ exports[`createMarkdown multiple tags outputs correct changelog 1`] = ` ## a-new-hope@4.0.0 (1977-05-25) #### :rocket: New Feature -* \`a-new-hope\` +* \`@star-wars/a-new-hope\` * [#1](https://github.com/lerna/lerna-changelog/pull/1) feat: May the force be with you ([@luke](https://github.com/luke)) #### Committers: 1 @@ -15,7 +15,7 @@ exports[`createMarkdown multiple tags outputs correct changelog 1`] = ` ## empire-strikes-back@5.0.0 (1977-05-25) #### :rocket: New Feature -* \`a-new-hope\` +* \`@star-wars/a-new-hope\` * [#1](https://github.com/lerna/lerna-changelog/pull/1) feat: May the force be with you ([@luke](https://github.com/luke)) #### Committers: 1 @@ -25,7 +25,7 @@ exports[`createMarkdown multiple tags outputs correct changelog 1`] = ` ## return-of-the-jedi@6.0.0 (1977-05-25) #### :rocket: New Feature -* \`a-new-hope\` +* \`@star-wars/a-new-hope\` * [#1](https://github.com/lerna/lerna-changelog/pull/1) feat: May the force be with you ([@luke](https://github.com/luke)) #### Committers: 1 @@ -93,11 +93,11 @@ exports[`createMarkdown single tags outputs correct changelog 1`] = ` ## Unreleased (2099-01-01) #### :rocket: New Feature -* \`the-force-awakens\`, \`rogue-one\` +* \`@star-wars/the-force-awakens\`, \`@star-wars/rogue-one\` * [#7](https://github.com/lerna/lerna-changelog/pull/7) feat: that is not how the Force works! ([@han-solo](https://github.com/han-solo)) #### :nail_care: Enhancement -* \`the-force-awakens\`, \`rogue-one\` +* \`@star-wars/the-force-awakens\`, \`@star-wars/rogue-one\` * [#7](https://github.com/lerna/lerna-changelog/pull/7) feat: that is not how the Force works! ([@han-solo](https://github.com/han-solo)) #### Committers: 1 @@ -107,19 +107,19 @@ exports[`createMarkdown single tags outputs correct changelog 1`] = ` ## v6.0.0 (1983-05-25) #### :rocket: New Feature -* \`return-of-the-jedi\` +* \`@star-wars/return-of-the-jedi\` * [#5](https://github.com/lerna/lerna-changelog/pull/5) feat: I am your father ([@vader](https://github.com/vader)) #### :bug: Bug Fix -* \`return-of-the-jedi\` +* \`@star-wars/return-of-the-jedi\` * [#4](https://github.com/lerna/lerna-changelog/pull/4) fix: RRRAARRWHHGWWR ([@chewbacca](https://github.com/chewbacca)) #### :nail_care: Enhancement -* \`return-of-the-jedi\` +* \`@star-wars/return-of-the-jedi\` * [#6](https://github.com/lerna/lerna-changelog/pull/6) refactor: he is my brother ([@princess-leia](https://github.com/princess-leia)) #### :house: Maintenance -* \`return-of-the-jedi\` +* \`@star-wars/return-of-the-jedi\` * [#4](https://github.com/lerna/lerna-changelog/pull/4) fix: RRRAARRWHHGWWR ([@chewbacca](https://github.com/chewbacca)) #### Committers: 3 @@ -131,11 +131,11 @@ exports[`createMarkdown single tags outputs correct changelog 1`] = ` ## v5.0.0 (1980-05-17) #### :boom: Breaking Change -* \`empire-strikes-back\` +* \`@star-wars/empire-strikes-back\` * [#2](https://github.com/lerna/lerna-changelog/pull/2) chore: Terminate her... immediately! ([@gtarkin](https://github.com/gtarkin)) #### :bug: Bug Fix -* \`empire-strikes-back\` +* \`@star-wars/empire-strikes-back\` * [#3](https://github.com/lerna/lerna-changelog/pull/3) fix: Get me the rebels base! ([@vader](https://github.com/vader)) #### Committers: 2 @@ -146,7 +146,7 @@ exports[`createMarkdown single tags outputs correct changelog 1`] = ` ## v4.0.0 (1977-05-25) #### :rocket: New Feature -* \`a-new-hope\` +* \`@star-wars/a-new-hope\` * [#1](https://github.com/lerna/lerna-changelog/pull/1) feat: May the force be with you ([@luke](https://github.com/luke)) #### Committers: 1 diff --git a/src/functional/markdown-empty.spec.ts b/src/functional/markdown-empty.spec.ts index c14923ec..3b3c90ae 100644 --- a/src/functional/markdown-empty.spec.ts +++ b/src/functional/markdown-empty.spec.ts @@ -7,6 +7,7 @@ jest.mock("../../src/changelog"); jest.mock("../../src/github-api"); jest.mock("../git"); jest.mock("../fetch"); +jest.mock("../packages"); const listOfCommits: CommitListItem[] = []; @@ -15,18 +16,21 @@ const listOfTags = ["v6.0.0", "v5.0.0", "v4.0.0", "v3.0.0", "v2.0.0", "v1.0.0", const listOfPackagesForEachCommit: { [id: string]: string[] } = { a0000001: ["packages/random/foo.js"], a0000002: ["packages/random/package.json"], - a0000003: ["packages/a-new-hope/rebels.js"], - a0000004: ["packages/a-new-hope/package.json"], - a0000005: ["packages/empire-strikes-back/death-star.js"], - a0000006: ["packages/empire-strikes-back/death-star.js"], - a0000007: ["packages/empire-strikes-back/hoth.js"], - a0000008: ["packages/empire-strikes-back/hoth.js"], - a0000009: ["packages/empire-strikes-back/package.json"], - a0000010: ["packages/return-of-the-jedi/jabba-the-hutt.js"], - a0000011: ["packages/return-of-the-jedi/vader-luke.js"], - a0000012: ["packages/return-of-the-jedi/leia.js"], - a0000013: ["packages/return-of-the-jedi/package.json"], - a0000014: ["packages/the-force-awakens/mission.js", "packages/rogue-one/mission.js"], + a0000003: ["packages/star-wars/a-new-hope/rebels.js"], + a0000004: ["packages/star-wars/a-new-hope/package.json"], + a0000005: ["packages/star-wars/empire-strikes-back/death-star.js"], + a0000006: ["packages/star-wars/empire-strikes-back/death-star.js"], + a0000007: ["packages/star-wars/empire-strikes-back/hoth.js"], + a0000008: ["packages/star-wars/empire-strikes-back/hoth.js"], + a0000009: ["packages/star-wars/empire-strikes-back/package.json"], + a0000010: ["packages/star-wars/return-of-the-jedi/jabba-the-hutt.js"], + a0000011: ["packages/star-wars/return-of-the-jedi/vader-luke.js"], + a0000012: ["packages/star-wars/return-of-the-jedi/leia.js"], + a0000013: ["packages/star-wars/return-of-the-jedi/package.json"], + a0000014: [ + "packages/star-wars/the-force-awakens/mission.js", + "packages/star-wars/origin-stories/rogue-one/mission.js", + ], a0000015: ["packages/untitled/script.md"], }; @@ -106,45 +110,75 @@ const issuesCache = { }, }, }; - -describe("multiple tags", () => { - it("outputs correct changelog", async () => { - require("../git").changedPaths.mockImplementation((sha: string) => listOfPackagesForEachCommit[sha]); - require("../git").lastTag.mockImplementation(() => "v8.0.0"); - require("../git").listCommits.mockImplementation(() => listOfCommits); - require("../git").listTagNames.mockImplementation(() => [ - "a-new-hope@4.0.0", - "attack-of-the-clones@3.1.0", - "empire-strikes-back@5.0.0", - "return-of-the-jedi@6.0.0", - "revenge-of-the-sith@3.0.0", - "the-force-awakens@7.0.0", - "the-phantom-menace@1.0.0", - ]); - - require("../fetch").__setMockResponses({ - ...usersCache, - ...issuesCache, - }); - - const MockedChangelog = require("../changelog").default; - const changelog = new MockedChangelog(); - - const markdown = await changelog.createMarkdown(); - - expect(markdown).toMatchSnapshot(); - }); -}); +const listOfWorkspacePackages = [ + { + name: "random", + location: "/path/to/project/packages/random", + }, + { + name: "@star-wars/a-new-hope", + location: "/path/to/project/packages/star-wars/a-new-hope", + }, + { + name: "@star-wars/empire-strikes-back", + location: "/path/to/project/packages/star-wars/empire-strikes-back", + }, + { + name: "@star-wars/return-of-the-jedi", + location: "/path/to/project/packages/star-wars/return-of-the-jedi", + }, + { + name: "@star-wars/the-force-awakens", + location: "/path/to/project/packages/star-wars/the-force-awakens", + }, + { + name: "@star-wars/rogue-one", + location: "/path/to/project/packages/star-wars/origin-stories/rogue-one", + }, + { + name: "@star-wars/solo", + location: "/path/to/project/packages/star-wars/origin-stories/solo", + }, +]; describe("createMarkdown", () => { beforeEach(() => { require("../fetch").__resetMockResponses(); + require("../packages").getPackages.mockImplementation(() => listOfWorkspacePackages); }); afterEach(() => { jest.resetAllMocks(); }); + describe("multiple tags", () => { + it("outputs correct changelog", async () => { + require("../git").changedPaths.mockImplementation((sha: string) => listOfPackagesForEachCommit[sha]); + require("../git").lastTag.mockImplementation(() => "v8.0.0"); + require("../git").listCommits.mockImplementation(() => listOfCommits); + require("../git").listTagNames.mockImplementation(() => [ + "a-new-hope@4.0.0", + "attack-of-the-clones@3.1.0", + "empire-strikes-back@5.0.0", + "return-of-the-jedi@6.0.0", + "revenge-of-the-sith@3.0.0", + "the-force-awakens@7.0.0", + "the-phantom-menace@1.0.0", + ]); + + require("../fetch").__setMockResponses({ + ...usersCache, + ...issuesCache, + }); + + const MockedChangelog = require("../changelog").default; + const changelog = new MockedChangelog(); + + const markdown = await changelog.createMarkdown(); + + expect(markdown).toMatchSnapshot(); + }); + }); describe("single tags", () => { it("outputs correct changelog", async () => { require("../git").changedPaths.mockImplementation((sha: string) => listOfPackagesForEachCommit[sha]); diff --git a/src/functional/markdown-full.spec.ts b/src/functional/markdown-full.spec.ts index 4c9cb799..74cf70c9 100644 --- a/src/functional/markdown-full.spec.ts +++ b/src/functional/markdown-full.spec.ts @@ -1,5 +1,4 @@ /* tslint:disable:max-line-length */ - import { CommitListItem } from "../git"; jest.mock("../../src/progress-bar"); @@ -7,6 +6,7 @@ jest.mock("../../src/changelog"); jest.mock("../../src/github-api"); jest.mock("../git"); jest.mock("../fetch"); +jest.mock("../packages"); const listOfCommits: CommitListItem[] = [ { @@ -106,18 +106,21 @@ const listOfTags = ["v6.0.0", "v5.0.0", "v4.0.0", "v3.0.0", "v2.0.0", "v1.0.0", const listOfPackagesForEachCommit: { [id: string]: string[] } = { a0000001: ["packages/random/foo.js"], a0000002: ["packages/random/package.json"], - a0000003: ["packages/a-new-hope/rebels.js"], - a0000004: ["packages/a-new-hope/package.json"], - a0000005: ["packages/empire-strikes-back/death-star.js"], - a0000006: ["packages/empire-strikes-back/death-star.js"], - a0000007: ["packages/empire-strikes-back/hoth.js"], - a0000008: ["packages/empire-strikes-back/hoth.js"], - a0000009: ["packages/empire-strikes-back/package.json"], - a0000010: ["packages/return-of-the-jedi/jabba-the-hutt.js"], - a0000011: ["packages/return-of-the-jedi/vader-luke.js"], - a0000012: ["packages/return-of-the-jedi/leia.js"], - a0000013: ["packages/return-of-the-jedi/package.json"], - a0000014: ["packages/the-force-awakens/mission.js", "packages/rogue-one/mission.js"], + a0000003: ["packages/star-wars/a-new-hope/rebels.js"], + a0000004: ["packages/star-wars/a-new-hope/package.json"], + a0000005: ["packages/star-wars/empire-strikes-back/death-star.js"], + a0000006: ["packages/star-wars/empire-strikes-back/death-star.js"], + a0000007: ["packages/star-wars/empire-strikes-back/hoth.js"], + a0000008: ["packages/star-wars/empire-strikes-back/hoth.js"], + a0000009: ["packages/star-wars/empire-strikes-back/package.json"], + a0000010: ["packages/star-wars/return-of-the-jedi/jabba-the-hutt.js"], + a0000011: ["packages/star-wars/return-of-the-jedi/vader-luke.js"], + a0000012: ["packages/star-wars/return-of-the-jedi/leia.js"], + a0000013: ["packages/star-wars/return-of-the-jedi/package.json"], + a0000014: [ + "packages/star-wars/the-force-awakens/mission.js", + "packages/star-wars/origin-stories/rogue-one/mission.js", + ], a0000015: ["packages/untitled/script.md"], }; @@ -276,10 +279,41 @@ const issuesCache = { }, }, }; +const listOfWorkspacePackages = [ + { + name: "random", + location: "/path/to/project/packages/random", + }, + { + name: "@star-wars/a-new-hope", + location: "/path/to/project/packages/star-wars/a-new-hope", + }, + { + name: "@star-wars/empire-strikes-back", + location: "/path/to/project/packages/star-wars/empire-strikes-back", + }, + { + name: "@star-wars/return-of-the-jedi", + location: "/path/to/project/packages/star-wars/return-of-the-jedi", + }, + { + name: "@star-wars/the-force-awakens", + location: "/path/to/project/packages/star-wars/the-force-awakens", + }, + { + name: "@star-wars/rogue-one", + location: "/path/to/project/packages/star-wars/origin-stories/rogue-one", + }, + { + name: "@star-wars/solo", + location: "/path/to/project/packages/star-wars/origin-stories/solo", + }, +]; describe("createMarkdown", () => { beforeEach(() => { require("../fetch").__resetMockResponses(); + require("../packages").getPackages.mockImplementation(() => listOfWorkspacePackages); }); afterEach(() => { @@ -292,7 +326,6 @@ describe("createMarkdown", () => { require("../git").lastTag.mockImplementation(() => "v8.0.0"); require("../git").listCommits.mockImplementation(() => listOfCommits); require("../git").listTagNames.mockImplementation(() => listOfTags); - require("../fetch").__setMockResponses({ ...usersCache, ...issuesCache, @@ -346,7 +379,6 @@ describe("createMarkdown", () => { "the-force-awakens@7.0.0", "the-phantom-menace@1.0.0", ]); - require("../fetch").__setMockResponses({ ...usersCache, ...issuesCache, @@ -367,7 +399,6 @@ describe("createMarkdown", () => { require("../git").lastTag.mockImplementation(() => "v8.0.0"); require("../git").listCommits.mockImplementation(() => listOfCommits); require("../git").listTagNames.mockImplementation(() => listOfTags); - require("../fetch").__setMockResponses({ ...usersCache, ...issuesCache, diff --git a/src/git.ts b/src/git.ts index 0be7c7f7..bdaa4fe0 100644 --- a/src/git.ts +++ b/src/git.ts @@ -1,5 +1,10 @@ const execa = require("execa"); +export function getRootPath() { + const cwd = process.cwd(); + return execa.sync("git", ["rev-parse", "--show-toplevel"], { cwd }).stdout; +} + export async function changedPaths(sha: string): Promise { const result = await execa("git", ["show", "-m", "--name-only", "--pretty=format:", "--first-parent", sha]); return result.stdout.split("\n"); diff --git a/src/packages.ts b/src/packages.ts new file mode 100644 index 00000000..3cc11aa0 --- /dev/null +++ b/src/packages.ts @@ -0,0 +1,91 @@ +/* This file is an extracted version of the `getPackages` implementation from `@lerna/project`. */ + +import fs from "fs"; +import path from "path"; +import pMap from "p-map"; +import globby from "globby"; +import { Configuration } from "./configuration"; +import ConfigurationError from "./configuration-error"; + +export type PackageInfo = { + name: string; + location: string; +}; + +export function getPackages(config: Configuration) { + const packageLocations = getPackageLocations(config); + if (!packageLocations) return Promise.resolve([]); + + const mapper = (packageConfigPath: string): PackageInfo => { + const packageJson = require(packageConfigPath); + return { + name: packageJson.name, + location: path.dirname(packageConfigPath), + }; + }; + const fileFinder = makeFileFinder(config.rootPath, packageLocations); + return fileFinder("package.json", filePaths => pMap(filePaths, mapper, { concurrency: 50 })); +} + +function getPackageLocations(config: Configuration): string[] | undefined { + const rootPackageJson = require(path.join(config.rootPath, "package.json")); + const lernaJsonPath = path.join(config.rootPath, "lerna.json"); + + if (!fs.existsSync(lernaJsonPath) && !rootPackageJson.workspaces) { + // This is not a monorepo, fall back to single project. + return undefined; + } + + const lernaJson = require(path.join(config.rootPath, "lerna.json")); + if (lernaJson.useWorkspaces) { + const workspaces = rootPackageJson.workspaces; + if (!workspaces) { + throw new ConfigurationError( + `Yarn workspaces need to be defined in the root package.json.\nSee: https://github.com/lerna/lerna/blob/master/commands/bootstrap/README.md#--use-workspaces` + ); + } + return workspaces.packages || workspaces; + } + return lernaJson.packages || ["packages/*"]; +} + +function makeFileFinder(rootPath: string, packageLocations: string[]) { + const globOpts = { + cwd: rootPath, + absolute: true, + followSymlinkedDirectories: false, + // POSIX results always need to be normalized + transform: (filePath: string) => path.normalize(filePath), + }; + + if (packageLocations.some(locationPath => locationPath.indexOf("**") > -1)) { + if (packageLocations.some(locationPath => locationPath.indexOf("node_modules") > -1)) { + throw new Error("An explicit node_modules package path does not allow globstars (**)"); + } + + // @ts-ignore + globOpts.ignore = [ + // allow globs like "packages/**", + // but avoid picking up node_modules/**/package.json + "**/node_modules/**", + ]; + } + + return (fileName: string, fileMapper: (filePaths: string[]) => Promise): Promise => { + const promise = pMap( + packageLocations.sort(), + (globPath: string) => + globby(path.join(globPath, fileName), globOpts) + .then((results: string[]) => results.sort()) + .then(fileMapper), + { concurrency: 4 } + ); + + // always flatten the results + return promise.then(flattenResults); + }; +} + +function flattenResults(results: PackageInfo[][]) { + return results.reduce((acc, result) => acc.concat(result), []); +} diff --git a/tsconfig.json b/tsconfig.json index fcbbed25..db6bf79f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,6 +4,7 @@ "target": "es2015", "module": "CommonJS", "removeComments": true, + "esModuleInterop": true, "allowJs": true, "strict": true, "lib": ["es2015"] diff --git a/yarn.lock b/yarn.lock index d7cf9ef8..65b22e4c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -454,6 +454,27 @@ "@types/yargs" "^15.0.0" chalk "^3.0.0" +"@nodelib/fs.scandir@2.1.3": + version "2.1.3" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz#3a582bdb53804c6ba6d146579c46e52130cf4a3b" + integrity sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw== + dependencies: + "@nodelib/fs.stat" "2.0.3" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.3", "@nodelib/fs.stat@^2.0.2": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz#34dc5f4cabbc720f4e60f75a747e7ecd6c175bd3" + integrity sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA== + +"@nodelib/fs.walk@^1.2.3": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz#011b9202a70a6366e436ca5c065844528ab04976" + integrity sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ== + dependencies: + "@nodelib/fs.scandir" "2.1.3" + fastq "^1.6.0" + "@sinonjs/commons@^1.7.0": version "1.7.0" resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.7.0.tgz#f90ffc52a2e519f018b13b6c4da03cbff36ebed6" @@ -787,6 +808,11 @@ array-equal@^1.0.0: resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93" integrity sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM= +array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== + array-unique@^0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" @@ -1374,6 +1400,13 @@ diff-sequences@^25.2.6: resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-25.2.6.tgz#5f467c00edd35352b7bca46d7927d60e687a76dd" integrity sha512-Hq8o7+6GaZeoFjtpgvRBUknSXNeJiCx7V9Fr94ZMljNiCr9n9L8H8aJqgWOQiDDGdyn29fRNcDdRVJ5fdyihfg== +dir-glob@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" + integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== + dependencies: + path-type "^4.0.0" + doctrine@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" @@ -1710,6 +1743,18 @@ fast-diff@^1.1.2: resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w== +fast-glob@^3.1.1: + version "3.2.2" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.2.tgz#ade1a9d91148965d4bf7c51f72e1ca662d32e63d" + integrity sha512-UDV82o4uQyljznxwMxyVRJgZZt3O5wENYojjzbaGEGZgeOxkLFf+V4cnUD+krzb2F72E18RhamkMZ7AdeggF7A== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.0" + merge2 "^1.3.0" + micromatch "^4.0.2" + picomatch "^2.2.1" + fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" @@ -1720,6 +1765,13 @@ fast-levenshtein@~2.0.6: resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= +fastq@^1.6.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.7.0.tgz#fcd79a08c5bd7ec5b55cd3f5c4720db551929801" + integrity sha512-YOadQRnHd5q6PogvAR/x62BGituF2ufiEA6s8aavQANw5YKHERI4AREboX6KotzP8oX2klxYF2wcV/7bn1clfQ== + dependencies: + reusify "^1.0.4" + fb-watchman@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.0.tgz#54e9abf7dfa2f26cd9b1636c588c1afc05de5d58" @@ -1907,6 +1959,13 @@ glob-parent@^5.0.0: dependencies: is-glob "^4.0.1" +glob-parent@^5.1.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.1.tgz#b6c1ef417c4e5663ea498f1c45afac6916bbc229" + integrity sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ== + dependencies: + is-glob "^4.0.1" + glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: version "7.1.6" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" @@ -1931,6 +1990,18 @@ globals@^12.1.0: dependencies: type-fest "^0.8.1" +globby@^11.0.0: + version "11.0.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.0.tgz#56fd0e9f0d4f8fb0c456f1ab0dee96e1380bc154" + integrity sha512-iuehFnR3xu5wBBtm4xi0dMe92Ob87ufyu/dHwpDYfbcpYpIbrO5OnS8M1vWvrBhSGEJ3/Ecj7gnX76P8YxpPEg== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.1.1" + ignore "^5.1.4" + merge2 "^1.3.0" + slash "^3.0.0" + graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.2, graceful-fs@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423" @@ -2078,6 +2149,11 @@ ignore@^4.0.6: resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== +ignore@^5.1.4: + version "5.1.4" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.4.tgz#84b7b3dbe64552b6ef0eca99f6743dbec6d97adf" + integrity sha512-MzbUSahkTW1u7JpKKjY7LCARd1fU5W2rLdxlM4kdkayuCwZImjkpluF9CM1aLewYJguPDqewLam18Y6AU69A8A== + import-fresh@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-2.0.0.tgz#d81355c15612d386c61f9ddd3922d4304822a546" @@ -3014,6 +3090,11 @@ merge-stream@^2.0.0: resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== +merge2@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.3.0.tgz#5b366ee83b2f1582c48f87e47cf1a9352103ca81" + integrity sha512-2j4DAdlBOkiSZIsaXk4mTE3sRS02yBHAtfy127xRV3bQUFqXkjHCHLW6Scv7DwNRbIWNHH8zpnz9zMaKXIdvYw== + micromatch@4.x, micromatch@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.2.tgz#4fcb0999bf9fbc2fcbdd212f6d629b9a56c39259" @@ -3444,6 +3525,11 @@ path-parse@^1.0.6: resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + performance-now@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" @@ -3454,6 +3540,11 @@ picomatch@^2.0.4, picomatch@^2.0.5: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.1.tgz#21bac888b6ed8601f831ce7816e335bc779f0a4a" integrity sha512-ISBaA8xQNmwELC7eOjqFKMESB2VIqt4PPDD0nsS95b/9dZXvVKOlz9keMSnoGGKcOHXfTvDD6WMaRoSc9UuhRA== +picomatch@^2.2.1: + version "2.2.2" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad" + integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg== + pirates@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.1.tgz#643a92caf894566f91b2b986d2c66950a8e2fb87" @@ -3729,6 +3820,11 @@ retry@^0.10.0: resolved "https://registry.yarnpkg.com/retry/-/retry-0.10.1.tgz#e76388d217992c252750241d3d3956fed98d8ff4" integrity sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q= +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + rimraf@2.6.3: version "2.6.3" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" @@ -3762,6 +3858,11 @@ run-async@^2.2.0: dependencies: is-promise "^2.1.0" +run-parallel@^1.1.9: + version "1.1.9" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.9.tgz#c9dd3a7cf9f4b2c4b6244e173a6ed866e61dd679" + integrity sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q== + run-queue@^1.0.0, run-queue@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/run-queue/-/run-queue-1.0.3.tgz#e848396f057d223f24386924618e25694161ec47"