diff --git a/README.md b/README.md index 35f2067..a9f7933 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,10 @@ _But_ in multi-semantic-release this configuration can be done globally (in your multi-semantic-release does not support any command line arguments (this wasn't possible without duplicating files from semantic-release, which I've tried to avoid). +multi-semantic-release automatically detects packages within workspaces for the following package-managers: + +### yarn / npm (Version 7.x) + Make sure to have a `workspaces` attribute inside your `package.json` project file. In there, you can set a list of packages that you might want to process in the msr process, as well as ignore others. For example, let's say your project has 4 packages (i.e. a, b, c and d) and you want to process only a and d (ignore b and c). You can set the following structure in your `package.json` file: ```json { @@ -58,6 +62,52 @@ Make sure to have a `workspaces` attribute inside your `package.json` project fi } ``` +### pnpm + +Make sure to have a `packages` attribute inside your `pnpm-workspace.yaml` in the root of your project. +In there, you can set a list of packages that you might want to process in the msr process, as well as ignore others. +For example, let's say your project has 4 packages (i.e. a, b, c and d) and you want to process only a and d (ignore b and c). You can set the following structure in your `pnpm-workspace.yaml` file: + +```yaml +packages: + - 'packages/**' + - '!packages/b/**' + - '!packages/c/**' +``` + +### bolt + +Make sure to have a `bolt.workspaces` attribute inside your `package.json` project file. +In there, you can set a list of packages that you might want to process in the msr process, as well as ignore others. +For example, let's say your project has 4 packages (i.e. a, b, c and d) and you want to process only a and d (ignore b and c). You can set the following structure in your `package.json` file: + +```json +{ + "name": "msr-test-bolt", + "author": "Dave Houlbrooke =8.3" + }, + "bolt": { + "workspaces": [ + "packages/*", + "!packages/b/**", + "!packages/c/**" + ] + }, + "release": { + "plugins": [ + "@semantic-release/commit-analyzer", + "@semantic-release/release-notes-generator" + ], + "noCi": true + } +} +``` + ## CLI There are several tweaks to adapt **msr** to some corner cases: @@ -103,7 +153,12 @@ multirelease([ ### Support for monorepos -Automatically finds packages as long as workspaces are configured as-per [Yarn workspaces](https://yarnpkg.com/lang/en/docs/workspaces/). _You don't need to use Yarn but the way they define monorepos seems intuitive, and is likely what NPM will copy when they add this functionality (as rumoured)._ +Automatically finds packages as long as workspaces are configured as-per the workspace-feature of one of the support package managers. + +- [Yarn workspaces](https://yarnpkg.com/lang/en/docs/workspaces/). +- [Npm workspaces (Version 7.x)](https://docs.npmjs.com/cli/v7/using-npm/workspaces) +- [pnpm workspace](https://pnpm.js.org/workspaces/) +- [bolt workspaces](https://github.com/boltpkg/bolt#configuration) I'm aware Lerna is the best-known tool right now, but in future it seems clear it will be replaced by functionality in Yarn and NPM directly. If you use Yarn workspaces today (January 2019), then publishing is the only remaining feature Lerna is _really_ required for (though it'd be lovely if Yarn added parallel script execution). Thus using multi-semantic-release means you can probably remove Lerna entirely from your project. diff --git a/bin/runner.js b/bin/runner.js index 74009ea..a052230 100644 --- a/bin/runner.js +++ b/bin/runner.js @@ -4,7 +4,7 @@ module.exports = (flags) => { } // Imports. - const getWorkspacesYarn = require("../lib/getWorkspacesYarn"); + const getPackagePaths = require("../lib/getPackagePaths"); const multiSemanticRelease = require("../lib/multiSemanticRelease"); const multisemrelPkgJson = require("../package.json"); const semrelPkgJson = require("semantic-release/package.json"); @@ -18,9 +18,9 @@ module.exports = (flags) => { console.log(`semantic-release version: ${semrelPkgJson.version}`); console.log(`flags: ${JSON.stringify(flags, null, 2)}`); - // Get list of package.json paths according to Yarn workspaces. - const paths = getWorkspacesYarn(cwd, flags.ignorePackages); - console.log("yarn paths", paths); + // Get list of package.json paths according to workspaces. + const paths = getPackagePaths(cwd, flags.ignorePackages); + console.log("package paths", paths); // Do multirelease (log out any errors). multiSemanticRelease(paths, {}, { cwd }, flags).then( diff --git a/lib/getPackagePaths.js b/lib/getPackagePaths.js new file mode 100644 index 0000000..39d8b31 --- /dev/null +++ b/lib/getPackagePaths.js @@ -0,0 +1,56 @@ +const getManifest = require("./getManifest"); +const glob = require("./glob"); +const path = require("path"); +const { getPackagesSync } = require("@manypkg/get-packages"); + +/** + * Return array of package.json for workspace packages. + * + * @param {string} cwd The current working directory where a package.json file can be found. + * @param {string[]|null} ignorePackages (Optional) Packages to be ignored passed via cli. + * @returns {string[]} An array of package.json files corresponding to the workspaces setting in package.json + */ +function getPackagePaths(cwd, ignorePackages = null) { + let workspace; + // Ignore exceptions as we will rely on `getManifest` validation + try { + workspace = getPackagesSync(cwd); + } catch (e) { + /**/ + } + workspace = workspace || { + tool: "root", + root: { dir: cwd }, + }; + workspace.root.packageJson = getManifest(path.join(workspace.root.dir, "package.json")); + + if (workspace.tool === "root") { + workspace.packages = []; + } + + // remove cwd from results + const packages = workspace.packages.map((p) => path.relative(cwd, p.dir)); + + // If packages to be ignored come from CLI, we need to combine them with the ones from manifest workspaces + if (Array.isArray(ignorePackages)) packages.push(...ignorePackages.map((p) => `!${p}`)); + + // Turn workspaces into list of package.json files. + const workspacePackages = glob( + packages.map((p) => p.replace(/\/?$/, "/package.json")), + { + cwd: cwd, + absolute: true, + gitignore: true, + } + ); + + // Must have at least one workspace-package. + if (!workspacePackages.length) + throw new TypeError("package.json: Project must contain one or more workspace-packages"); + + // Return. + return workspacePackages; +} + +// Exports. +module.exports = getPackagePaths; diff --git a/lib/getWorkspacesYarn.js b/lib/getWorkspacesYarn.js deleted file mode 100644 index f98727d..0000000 --- a/lib/getWorkspacesYarn.js +++ /dev/null @@ -1,47 +0,0 @@ -const getManifest = require("./getManifest"); -const glob = require("./glob"); -const { checker } = require("./blork"); - -/** - * Return array of package.json for Yarn workspaces. - * - * @param {string} cwd The current working directory where a package.json file can be found. - * @param {string[]|null} ignorePackages (Optional) Packages to be ignored passed via cli. - * @returns {string[]} An array of package.json files corresponding to the workspaces setting in package.json - */ -function getWorkspacesYarn(cwd, ignorePackages = null) { - // Load package.json - const manifest = getManifest(`${cwd}/package.json`); - - let packages = manifest.workspaces; - if (packages && packages.packages) { - packages = packages.packages; - } - - // Only continue if manifest.workspaces or manifest.workspaces.packages is an array of strings. - if (!checker("string[]+")(packages)) { - throw new TypeError("package.json: workspaces or workspaces.packages: Must be non-empty array of string"); - } - - // If packages to be ignored come from CLI, we need to combine them with the ones from manifest workspaces - if (Array.isArray(ignorePackages)) packages.push(...ignorePackages.map((p) => `!${p}`)); - - // Turn workspaces into list of package.json files. - const workspaces = glob( - packages.map((p) => p.replace(/\/?$/, "/package.json")), - { - cwd: cwd, - absolute: true, - gitignore: true, - } - ); - - // Must have at least one workspace. - if (!workspaces.length) throw new TypeError("package.json: workspaces: Must contain one or more workspaces"); - - // Return. - return workspaces; -} - -// Exports. -module.exports = getWorkspacesYarn; diff --git a/package.json b/package.json index ad2aca1..d07e281 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ ] }, "dependencies": { + "@manypkg/get-packages": "^1.1.1", "blork": "^9.2.2", "cosmiconfig": "^7.0.0", "debug": "^4.3.1", @@ -70,11 +71,11 @@ "eslint": "^7.14.0", "eslint-config-prettier": "^6.15.0", "eslint-plugin-prettier": "^3.1.4", - "tempy": "^1.0.0", "file-url": "^3.0.0", "husky": "^4.3.0", "jest": "^26.6.3", - "prettier": "^2.2.0" + "prettier": "^2.2.0", + "tempy": "^1.0.0" }, "repository": { "type": "git", diff --git a/test/fixtures/boltWorkspaces/package.json b/test/fixtures/boltWorkspaces/package.json new file mode 100644 index 0000000..aa142d6 --- /dev/null +++ b/test/fixtures/boltWorkspaces/package.json @@ -0,0 +1,22 @@ +{ + "name": "msr-test-bolt", + "author": "Dave Houlbrooke ", + "version": "0.0.0-semantically-released", + "private": true, + "license": "0BSD", + "engines": { + "node": ">=8.3" + }, + "bolt": { + "workspaces": [ + "packages/*" + ] + }, + "release": { + "plugins": [ + "@semantic-release/commit-analyzer", + "@semantic-release/release-notes-generator" + ], + "noCi": true + } +} diff --git a/test/fixtures/boltWorkspaces/packages/a/package.json b/test/fixtures/boltWorkspaces/packages/a/package.json new file mode 100644 index 0000000..92d8046 --- /dev/null +++ b/test/fixtures/boltWorkspaces/packages/a/package.json @@ -0,0 +1,8 @@ +{ + "name": "msr-test-a", + "version": "0.0.0", + "peerDependencies": { + "msr-test-c": "*", + "left-pad": "latest" + } +} \ No newline at end of file diff --git a/test/fixtures/boltWorkspaces/packages/b/package.json b/test/fixtures/boltWorkspaces/packages/b/package.json new file mode 100644 index 0000000..1812781 --- /dev/null +++ b/test/fixtures/boltWorkspaces/packages/b/package.json @@ -0,0 +1,11 @@ +{ + "name": "msr-test-b", + "version": "0.0.0", + "dependencies": { + "msr-test-a": "*" + }, + "devDependencies": { + "msr-test-c": "*", + "left-pad": "latest" + } +} \ No newline at end of file diff --git a/test/fixtures/boltWorkspaces/packages/c/.releaserc.json b/test/fixtures/boltWorkspaces/packages/c/.releaserc.json new file mode 100644 index 0000000..64f41b1 --- /dev/null +++ b/test/fixtures/boltWorkspaces/packages/c/.releaserc.json @@ -0,0 +1,3 @@ +{ + "tagFormat": "multi-semantic-release-test-c@v${version}" +} \ No newline at end of file diff --git a/test/fixtures/boltWorkspaces/packages/c/package.json b/test/fixtures/boltWorkspaces/packages/c/package.json new file mode 100644 index 0000000..0bdb127 --- /dev/null +++ b/test/fixtures/boltWorkspaces/packages/c/package.json @@ -0,0 +1,8 @@ +{ + "name": "msr-test-c", + "version": "0.0.0", + "devDependencies": { + "msr-test-b": "*", + "msr-test-d": "*" + } +} \ No newline at end of file diff --git a/test/fixtures/boltWorkspaces/packages/d/package.json b/test/fixtures/boltWorkspaces/packages/d/package.json new file mode 100644 index 0000000..222eb15 --- /dev/null +++ b/test/fixtures/boltWorkspaces/packages/d/package.json @@ -0,0 +1,4 @@ +{ + "name": "msr-test-d", + "version": "0.0.0" +} diff --git a/test/fixtures/boltWorkspacesIgnore/package.json b/test/fixtures/boltWorkspacesIgnore/package.json new file mode 100644 index 0000000..859177a --- /dev/null +++ b/test/fixtures/boltWorkspacesIgnore/package.json @@ -0,0 +1,23 @@ +{ + "name": "msr-test-bolt", + "author": "Dave Houlbrooke =8.3" + }, + "bolt": { + "workspaces": [ + "packages/*", + "!packages/d/**" + ] + }, + "release": { + "plugins": [ + "@semantic-release/commit-analyzer", + "@semantic-release/release-notes-generator" + ], + "noCi": true + } +} diff --git a/test/fixtures/boltWorkspacesIgnore/packages/a/package.json b/test/fixtures/boltWorkspacesIgnore/packages/a/package.json new file mode 100644 index 0000000..92d8046 --- /dev/null +++ b/test/fixtures/boltWorkspacesIgnore/packages/a/package.json @@ -0,0 +1,8 @@ +{ + "name": "msr-test-a", + "version": "0.0.0", + "peerDependencies": { + "msr-test-c": "*", + "left-pad": "latest" + } +} \ No newline at end of file diff --git a/test/fixtures/boltWorkspacesIgnore/packages/b/package.json b/test/fixtures/boltWorkspacesIgnore/packages/b/package.json new file mode 100644 index 0000000..d4b1ec7 --- /dev/null +++ b/test/fixtures/boltWorkspacesIgnore/packages/b/package.json @@ -0,0 +1,12 @@ + +{ + "name": "msr-test-b", + "version": "0.0.0", + "dependencies": { + "msr-test-a": "*" + }, + "devDependencies": { + "msr-test-c": "*", + "left-pad": "latest" + } +} \ No newline at end of file diff --git a/test/fixtures/boltWorkspacesIgnore/packages/c/.releaserc.json b/test/fixtures/boltWorkspacesIgnore/packages/c/.releaserc.json new file mode 100644 index 0000000..64f41b1 --- /dev/null +++ b/test/fixtures/boltWorkspacesIgnore/packages/c/.releaserc.json @@ -0,0 +1,3 @@ +{ + "tagFormat": "multi-semantic-release-test-c@v${version}" +} \ No newline at end of file diff --git a/test/fixtures/boltWorkspacesIgnore/packages/c/package.json b/test/fixtures/boltWorkspacesIgnore/packages/c/package.json new file mode 100644 index 0000000..0bdb127 --- /dev/null +++ b/test/fixtures/boltWorkspacesIgnore/packages/c/package.json @@ -0,0 +1,8 @@ +{ + "name": "msr-test-c", + "version": "0.0.0", + "devDependencies": { + "msr-test-b": "*", + "msr-test-d": "*" + } +} \ No newline at end of file diff --git a/test/fixtures/boltWorkspacesIgnore/packages/d/package.json b/test/fixtures/boltWorkspacesIgnore/packages/d/package.json new file mode 100644 index 0000000..fa64f23 --- /dev/null +++ b/test/fixtures/boltWorkspacesIgnore/packages/d/package.json @@ -0,0 +1,4 @@ +{ + "name": "msr-test-d", + "version": "0.0.0" +} \ No newline at end of file diff --git a/test/fixtures/boltWorkspacesUndefined/package.json b/test/fixtures/boltWorkspacesUndefined/package.json new file mode 100644 index 0000000..0b1b3dd --- /dev/null +++ b/test/fixtures/boltWorkspacesUndefined/package.json @@ -0,0 +1,19 @@ +{ + "name": "msr-test-bolt", + "author": "Dave Houlbrooke ", + "version": "0.0.0-semantically-released", + "private": true, + "license": "0BSD", + "engines": { + "node": ">=8.3" + }, + "bolt": { + }, + "release": { + "plugins": [ + "@semantic-release/commit-analyzer", + "@semantic-release/release-notes-generator" + ], + "noCi": true + } +} diff --git a/test/fixtures/boltWorkspacesUndefined/packages/a/package.json b/test/fixtures/boltWorkspacesUndefined/packages/a/package.json new file mode 100644 index 0000000..92d8046 --- /dev/null +++ b/test/fixtures/boltWorkspacesUndefined/packages/a/package.json @@ -0,0 +1,8 @@ +{ + "name": "msr-test-a", + "version": "0.0.0", + "peerDependencies": { + "msr-test-c": "*", + "left-pad": "latest" + } +} \ No newline at end of file diff --git a/test/fixtures/boltWorkspacesUndefined/packages/b/package.json b/test/fixtures/boltWorkspacesUndefined/packages/b/package.json new file mode 100644 index 0000000..1812781 --- /dev/null +++ b/test/fixtures/boltWorkspacesUndefined/packages/b/package.json @@ -0,0 +1,11 @@ +{ + "name": "msr-test-b", + "version": "0.0.0", + "dependencies": { + "msr-test-a": "*" + }, + "devDependencies": { + "msr-test-c": "*", + "left-pad": "latest" + } +} \ No newline at end of file diff --git a/test/fixtures/boltWorkspacesUndefined/packages/c/.releaserc.json b/test/fixtures/boltWorkspacesUndefined/packages/c/.releaserc.json new file mode 100644 index 0000000..64f41b1 --- /dev/null +++ b/test/fixtures/boltWorkspacesUndefined/packages/c/.releaserc.json @@ -0,0 +1,3 @@ +{ + "tagFormat": "multi-semantic-release-test-c@v${version}" +} \ No newline at end of file diff --git a/test/fixtures/boltWorkspacesUndefined/packages/c/package.json b/test/fixtures/boltWorkspacesUndefined/packages/c/package.json new file mode 100644 index 0000000..0bdb127 --- /dev/null +++ b/test/fixtures/boltWorkspacesUndefined/packages/c/package.json @@ -0,0 +1,8 @@ +{ + "name": "msr-test-c", + "version": "0.0.0", + "devDependencies": { + "msr-test-b": "*", + "msr-test-d": "*" + } +} \ No newline at end of file diff --git a/test/fixtures/boltWorkspacesUndefined/packages/d/package.json b/test/fixtures/boltWorkspacesUndefined/packages/d/package.json new file mode 100644 index 0000000..222eb15 --- /dev/null +++ b/test/fixtures/boltWorkspacesUndefined/packages/d/package.json @@ -0,0 +1,4 @@ +{ + "name": "msr-test-d", + "version": "0.0.0" +} diff --git a/test/fixtures/pnpmWorkspace/package.json b/test/fixtures/pnpmWorkspace/package.json new file mode 100644 index 0000000..2c05115 --- /dev/null +++ b/test/fixtures/pnpmWorkspace/package.json @@ -0,0 +1,17 @@ +{ + "name": "msr-test-pnpm", + "author": "Dave Houlbrooke ", + "version": "0.0.0-semantically-released", + "private": true, + "license": "0BSD", + "engines": { + "node": ">=8.3" + }, + "release": { + "plugins": [ + "@semantic-release/commit-analyzer", + "@semantic-release/release-notes-generator" + ], + "noCi": true + } +} diff --git a/test/fixtures/pnpmWorkspace/packages/a/package.json b/test/fixtures/pnpmWorkspace/packages/a/package.json new file mode 100644 index 0000000..92d8046 --- /dev/null +++ b/test/fixtures/pnpmWorkspace/packages/a/package.json @@ -0,0 +1,8 @@ +{ + "name": "msr-test-a", + "version": "0.0.0", + "peerDependencies": { + "msr-test-c": "*", + "left-pad": "latest" + } +} \ No newline at end of file diff --git a/test/fixtures/pnpmWorkspace/packages/b/package.json b/test/fixtures/pnpmWorkspace/packages/b/package.json new file mode 100644 index 0000000..1812781 --- /dev/null +++ b/test/fixtures/pnpmWorkspace/packages/b/package.json @@ -0,0 +1,11 @@ +{ + "name": "msr-test-b", + "version": "0.0.0", + "dependencies": { + "msr-test-a": "*" + }, + "devDependencies": { + "msr-test-c": "*", + "left-pad": "latest" + } +} \ No newline at end of file diff --git a/test/fixtures/pnpmWorkspace/packages/c/.releaserc.json b/test/fixtures/pnpmWorkspace/packages/c/.releaserc.json new file mode 100644 index 0000000..64f41b1 --- /dev/null +++ b/test/fixtures/pnpmWorkspace/packages/c/.releaserc.json @@ -0,0 +1,3 @@ +{ + "tagFormat": "multi-semantic-release-test-c@v${version}" +} \ No newline at end of file diff --git a/test/fixtures/pnpmWorkspace/packages/c/package.json b/test/fixtures/pnpmWorkspace/packages/c/package.json new file mode 100644 index 0000000..0bdb127 --- /dev/null +++ b/test/fixtures/pnpmWorkspace/packages/c/package.json @@ -0,0 +1,8 @@ +{ + "name": "msr-test-c", + "version": "0.0.0", + "devDependencies": { + "msr-test-b": "*", + "msr-test-d": "*" + } +} \ No newline at end of file diff --git a/test/fixtures/pnpmWorkspace/packages/d/package.json b/test/fixtures/pnpmWorkspace/packages/d/package.json new file mode 100644 index 0000000..222eb15 --- /dev/null +++ b/test/fixtures/pnpmWorkspace/packages/d/package.json @@ -0,0 +1,4 @@ +{ + "name": "msr-test-d", + "version": "0.0.0" +} diff --git a/test/fixtures/pnpmWorkspace/pnpm-workspace.yaml b/test/fixtures/pnpmWorkspace/pnpm-workspace.yaml new file mode 100644 index 0000000..18ec407 --- /dev/null +++ b/test/fixtures/pnpmWorkspace/pnpm-workspace.yaml @@ -0,0 +1,2 @@ +packages: + - 'packages/*' diff --git a/test/fixtures/pnpmWorkspaceIgnore/package.json b/test/fixtures/pnpmWorkspaceIgnore/package.json new file mode 100644 index 0000000..3db4054 --- /dev/null +++ b/test/fixtures/pnpmWorkspaceIgnore/package.json @@ -0,0 +1,17 @@ +{ + "name": "msr-test-pnpm", + "author": "Dave Houlbrooke =8.3" + }, + "release": { + "plugins": [ + "@semantic-release/commit-analyzer", + "@semantic-release/release-notes-generator" + ], + "noCi": true + } +} diff --git a/test/fixtures/pnpmWorkspaceIgnore/packages/a/package.json b/test/fixtures/pnpmWorkspaceIgnore/packages/a/package.json new file mode 100644 index 0000000..92d8046 --- /dev/null +++ b/test/fixtures/pnpmWorkspaceIgnore/packages/a/package.json @@ -0,0 +1,8 @@ +{ + "name": "msr-test-a", + "version": "0.0.0", + "peerDependencies": { + "msr-test-c": "*", + "left-pad": "latest" + } +} \ No newline at end of file diff --git a/test/fixtures/pnpmWorkspaceIgnore/packages/b/package.json b/test/fixtures/pnpmWorkspaceIgnore/packages/b/package.json new file mode 100644 index 0000000..d4b1ec7 --- /dev/null +++ b/test/fixtures/pnpmWorkspaceIgnore/packages/b/package.json @@ -0,0 +1,12 @@ + +{ + "name": "msr-test-b", + "version": "0.0.0", + "dependencies": { + "msr-test-a": "*" + }, + "devDependencies": { + "msr-test-c": "*", + "left-pad": "latest" + } +} \ No newline at end of file diff --git a/test/fixtures/pnpmWorkspaceIgnore/packages/c/.releaserc.json b/test/fixtures/pnpmWorkspaceIgnore/packages/c/.releaserc.json new file mode 100644 index 0000000..64f41b1 --- /dev/null +++ b/test/fixtures/pnpmWorkspaceIgnore/packages/c/.releaserc.json @@ -0,0 +1,3 @@ +{ + "tagFormat": "multi-semantic-release-test-c@v${version}" +} \ No newline at end of file diff --git a/test/fixtures/pnpmWorkspaceIgnore/packages/c/package.json b/test/fixtures/pnpmWorkspaceIgnore/packages/c/package.json new file mode 100644 index 0000000..0bdb127 --- /dev/null +++ b/test/fixtures/pnpmWorkspaceIgnore/packages/c/package.json @@ -0,0 +1,8 @@ +{ + "name": "msr-test-c", + "version": "0.0.0", + "devDependencies": { + "msr-test-b": "*", + "msr-test-d": "*" + } +} \ No newline at end of file diff --git a/test/fixtures/pnpmWorkspaceIgnore/packages/d/package.json b/test/fixtures/pnpmWorkspaceIgnore/packages/d/package.json new file mode 100644 index 0000000..fa64f23 --- /dev/null +++ b/test/fixtures/pnpmWorkspaceIgnore/packages/d/package.json @@ -0,0 +1,4 @@ +{ + "name": "msr-test-d", + "version": "0.0.0" +} \ No newline at end of file diff --git a/test/fixtures/pnpmWorkspaceIgnore/pnpm-workspace.yaml b/test/fixtures/pnpmWorkspaceIgnore/pnpm-workspace.yaml new file mode 100644 index 0000000..26e9c9f --- /dev/null +++ b/test/fixtures/pnpmWorkspaceIgnore/pnpm-workspace.yaml @@ -0,0 +1,3 @@ +packages: + - 'packages/*' + - '!packages/d/**' diff --git a/test/fixtures/pnpmWorkspaceUndefined/package.json b/test/fixtures/pnpmWorkspaceUndefined/package.json new file mode 100644 index 0000000..2c05115 --- /dev/null +++ b/test/fixtures/pnpmWorkspaceUndefined/package.json @@ -0,0 +1,17 @@ +{ + "name": "msr-test-pnpm", + "author": "Dave Houlbrooke ", + "version": "0.0.0-semantically-released", + "private": true, + "license": "0BSD", + "engines": { + "node": ">=8.3" + }, + "release": { + "plugins": [ + "@semantic-release/commit-analyzer", + "@semantic-release/release-notes-generator" + ], + "noCi": true + } +} diff --git a/test/fixtures/pnpmWorkspaceUndefined/packages/a/package.json b/test/fixtures/pnpmWorkspaceUndefined/packages/a/package.json new file mode 100644 index 0000000..92d8046 --- /dev/null +++ b/test/fixtures/pnpmWorkspaceUndefined/packages/a/package.json @@ -0,0 +1,8 @@ +{ + "name": "msr-test-a", + "version": "0.0.0", + "peerDependencies": { + "msr-test-c": "*", + "left-pad": "latest" + } +} \ No newline at end of file diff --git a/test/fixtures/pnpmWorkspaceUndefined/packages/b/package.json b/test/fixtures/pnpmWorkspaceUndefined/packages/b/package.json new file mode 100644 index 0000000..1812781 --- /dev/null +++ b/test/fixtures/pnpmWorkspaceUndefined/packages/b/package.json @@ -0,0 +1,11 @@ +{ + "name": "msr-test-b", + "version": "0.0.0", + "dependencies": { + "msr-test-a": "*" + }, + "devDependencies": { + "msr-test-c": "*", + "left-pad": "latest" + } +} \ No newline at end of file diff --git a/test/fixtures/pnpmWorkspaceUndefined/packages/c/.releaserc.json b/test/fixtures/pnpmWorkspaceUndefined/packages/c/.releaserc.json new file mode 100644 index 0000000..64f41b1 --- /dev/null +++ b/test/fixtures/pnpmWorkspaceUndefined/packages/c/.releaserc.json @@ -0,0 +1,3 @@ +{ + "tagFormat": "multi-semantic-release-test-c@v${version}" +} \ No newline at end of file diff --git a/test/fixtures/pnpmWorkspaceUndefined/packages/c/package.json b/test/fixtures/pnpmWorkspaceUndefined/packages/c/package.json new file mode 100644 index 0000000..0bdb127 --- /dev/null +++ b/test/fixtures/pnpmWorkspaceUndefined/packages/c/package.json @@ -0,0 +1,8 @@ +{ + "name": "msr-test-c", + "version": "0.0.0", + "devDependencies": { + "msr-test-b": "*", + "msr-test-d": "*" + } +} \ No newline at end of file diff --git a/test/fixtures/pnpmWorkspaceUndefined/packages/d/package.json b/test/fixtures/pnpmWorkspaceUndefined/packages/d/package.json new file mode 100644 index 0000000..222eb15 --- /dev/null +++ b/test/fixtures/pnpmWorkspaceUndefined/packages/d/package.json @@ -0,0 +1,4 @@ +{ + "name": "msr-test-d", + "version": "0.0.0" +} diff --git a/test/fixtures/pnpmWorkspaceUndefined/pnpm-workspace.yaml b/test/fixtures/pnpmWorkspaceUndefined/pnpm-workspace.yaml new file mode 100644 index 0000000..e69de29 diff --git a/test/lib/getPackagePaths.test.js b/test/lib/getPackagePaths.test.js new file mode 100644 index 0000000..0782afc --- /dev/null +++ b/test/lib/getPackagePaths.test.js @@ -0,0 +1,118 @@ +const { resolve } = require("path"); +const getPackagePaths = require("../../lib/getPackagePaths"); + +// Tests. +describe("getPackagePaths()", () => { + test("yarn: Works correctly with workspaces", () => { + const resolved = resolve(`${__dirname}/../fixtures/yarnWorkspaces`); + expect(getPackagePaths(resolved)).toEqual([ + `${resolved}/packages/a/package.json`, + `${resolved}/packages/b/package.json`, + `${resolved}/packages/c/package.json`, + `${resolved}/packages/d/package.json`, + ]); + }); + test("yarn: Should ignore some packages", () => { + const resolved = resolve(`${__dirname}/../fixtures/yarnWorkspacesIgnore`); + expect(getPackagePaths(resolved)).toEqual([ + `${resolved}/packages/a/package.json`, + `${resolved}/packages/b/package.json`, + `${resolved}/packages/c/package.json`, + ]); + + const resolvedSplit = resolve(`${__dirname}/../fixtures/yarnWorkspacesIgnoreSplit`); + expect(getPackagePaths(resolvedSplit)).toEqual([ + `${resolvedSplit}/packages/a/package.json`, + `${resolvedSplit}/packages/c/package.json`, + ]); + }); + test("yarn: Should ignore some packages via CLI", () => { + const resolved = resolve(`${__dirname}/../fixtures/yarnWorkspacesIgnore`); + expect(getPackagePaths(resolved, ["packages/a/**", "packages/b/**"])).toEqual([ + `${resolved}/packages/c/package.json`, + ]); + + const resolvedSplit = resolve(`${__dirname}/../fixtures/yarnWorkspacesIgnoreSplit`); + expect(getPackagePaths(resolvedSplit, ["packages/b", "packages/d"])).toEqual([ + `${resolvedSplit}/packages/a/package.json`, + `${resolvedSplit}/packages/c/package.json`, + ]); + }); + test("yarn: Should throw when ignored packages from CLI and workspaces sets an empty workspace list to be processed", () => { + const resolved = resolve(`${__dirname}/../fixtures/yarnWorkspacesIgnore`); + expect(() => getPackagePaths(resolved, ["packages/a/**", "packages/b/**", "packages/c/**"])).toThrow(TypeError); + expect(() => getPackagePaths(resolved, ["packages/a/**", "packages/b/**", "packages/c/**"])).toThrow( + "package.json: Project must contain one or more workspace-packages" + ); + }); + test("yarn: Error if no workspaces setting", () => { + const resolved = resolve(`${__dirname}/../fixtures/emptyYarnWorkspaces`); + expect(() => getPackagePaths(resolved)).toThrow(Error); + expect(() => getPackagePaths(resolved)).toThrow("contain one or more workspace-packages"); + }); + test("yarn: Works correctly with workspaces.packages", () => { + const resolved = resolve(`${__dirname}/../fixtures/yarnWorkspacesPackages`); + expect(getPackagePaths(resolved)).toEqual([ + `${resolved}/packages/a/package.json`, + `${resolved}/packages/b/package.json`, + `${resolved}/packages/c/package.json`, + `${resolved}/packages/d/package.json`, + ]); + }); + test("pnpm: Works correctly with workspace", () => { + const resolved = resolve(`${__dirname}/../fixtures/pnpmWorkspace`); + expect(getPackagePaths(resolved)).toEqual([ + `${resolved}/packages/a/package.json`, + `${resolved}/packages/b/package.json`, + `${resolved}/packages/c/package.json`, + `${resolved}/packages/d/package.json`, + ]); + }); + test("pnpm: Error if no workspaces setting", () => { + const resolved = resolve(`${__dirname}/../fixtures/pnpmWorkspaceUndefined`); + expect(() => getPackagePaths(resolved)).toThrow(Error); + expect(() => getPackagePaths(resolved)).toThrow("contain one or more workspace-packages"); + }); + test("pnpm: Should ignore some packages", () => { + const resolved = resolve(`${__dirname}/../fixtures/pnpmWorkspaceIgnore`); + expect(getPackagePaths(resolved)).toEqual([ + `${resolved}/packages/a/package.json`, + `${resolved}/packages/b/package.json`, + `${resolved}/packages/c/package.json`, + ]); + }); + test("pnpm: Should ignore some packages via CLI", () => { + const resolved = resolve(`${__dirname}/../fixtures/pnpmWorkspaceIgnore`); + expect(getPackagePaths(resolved, ["packages/a/**", "packages/b/**"])).toEqual([ + `${resolved}/packages/c/package.json`, + ]); + }); + test("bolt: Works correctly with workspaces", () => { + const resolved = resolve(`${__dirname}/../fixtures/boltWorkspaces`); + expect(getPackagePaths(resolved)).toEqual([ + `${resolved}/packages/a/package.json`, + `${resolved}/packages/b/package.json`, + `${resolved}/packages/c/package.json`, + `${resolved}/packages/d/package.json`, + ]); + }); + test("bolt: Error if no workspaces setting", () => { + const resolved = resolve(`${__dirname}/../fixtures/boltWorkspacesUndefined`); + expect(() => getPackagePaths(resolved)).toThrow(Error); + expect(() => getPackagePaths(resolved)).toThrow("contain one or more workspace-packages"); + }); + test("bolt: Should ignore some packages", () => { + const resolved = resolve(`${__dirname}/../fixtures/boltWorkspacesIgnore`); + expect(getPackagePaths(resolved)).toEqual([ + `${resolved}/packages/a/package.json`, + `${resolved}/packages/b/package.json`, + `${resolved}/packages/c/package.json`, + ]); + }); + test("bolt: Should ignore some packages via CLI", () => { + const resolved = resolve(`${__dirname}/../fixtures/boltWorkspacesIgnore`); + expect(getPackagePaths(resolved, ["packages/a/**", "packages/b/**"])).toEqual([ + `${resolved}/packages/c/package.json`, + ]); + }); +}); diff --git a/test/lib/getWorkspacesYarn.test.js b/test/lib/getWorkspacesYarn.test.js deleted file mode 100644 index 1aa34cf..0000000 --- a/test/lib/getWorkspacesYarn.test.js +++ /dev/null @@ -1,74 +0,0 @@ -const { resolve } = require("path"); -const getWorkspacesYarn = require("../../lib/getWorkspacesYarn"); - -// Tests. -describe("getWorkspacesYarn()", () => { - test("Works correctly with workspaces", () => { - const resolved = resolve(`${__dirname}/../fixtures/yarnWorkspaces`); - expect(getWorkspacesYarn(resolved)).toEqual([ - `${resolved}/packages/a/package.json`, - `${resolved}/packages/b/package.json`, - `${resolved}/packages/c/package.json`, - `${resolved}/packages/d/package.json`, - ]); - }); - test("Should ignore some packages", () => { - const resolved = resolve(`${__dirname}/../fixtures/yarnWorkspacesIgnore`); - expect(getWorkspacesYarn(resolved)).toEqual([ - `${resolved}/packages/a/package.json`, - `${resolved}/packages/b/package.json`, - `${resolved}/packages/c/package.json`, - ]); - - const resolvedSplit = resolve(`${__dirname}/../fixtures/yarnWorkspacesIgnoreSplit`); - expect(getWorkspacesYarn(resolvedSplit)).toEqual([ - `${resolvedSplit}/packages/a/package.json`, - `${resolvedSplit}/packages/c/package.json`, - ]); - }); - test("Should ignore some packages via CLI", () => { - const resolved = resolve(`${__dirname}/../fixtures/yarnWorkspacesIgnore`); - expect(getWorkspacesYarn(resolved, ["packages/a/**", "packages/b/**"])).toEqual([ - `${resolved}/packages/c/package.json`, - ]); - - const resolvedSplit = resolve(`${__dirname}/../fixtures/yarnWorkspacesIgnoreSplit`); - expect(getWorkspacesYarn(resolvedSplit, ["packages/b", "packages/d"])).toEqual([ - `${resolvedSplit}/packages/a/package.json`, - `${resolvedSplit}/packages/c/package.json`, - ]); - }); - test("Should throw when ignored packages from CLI and workspaces sets an empty workspace list to be processed", () => { - const resolved = resolve(`${__dirname}/../fixtures/yarnWorkspacesIgnore`); - expect(() => getWorkspacesYarn(resolved, ["packages/a/**", "packages/b/**", "packages/c/**"])).toThrow( - TypeError - ); - expect(() => getWorkspacesYarn(resolved, ["packages/a/**", "packages/b/**", "packages/c/**"])).toThrow( - "package.json: workspaces: Must contain one or more workspaces" - ); - }); - test("TypeError if bad workspaces setting", () => { - const resolved = resolve(`${__dirname}/../fixtures/badYarnWorkspaces`); - expect(() => getWorkspacesYarn(resolved)).toThrow(TypeError); - expect(() => getWorkspacesYarn(resolved)).toThrow("non-empty array of string"); - }); - test("TypeError if no workspaces setting", () => { - const resolved = resolve(`${__dirname}/../fixtures/undefinedYarnWorkspaces`); - expect(() => getWorkspacesYarn(resolved)).toThrow(TypeError); - expect(() => getWorkspacesYarn(resolved)).toThrow("non-empty array of string"); - }); - test("Error if no workspaces setting", () => { - const resolved = resolve(`${__dirname}/../fixtures/emptyYarnWorkspaces`); - expect(() => getWorkspacesYarn(resolved)).toThrow(Error); - expect(() => getWorkspacesYarn(resolved)).toThrow("contain one or more workspaces"); - }); - test("Works correctly with workspaces.packages", () => { - const resolved = resolve(`${__dirname}/../fixtures/yarnWorkspacesPackages`); - expect(getWorkspacesYarn(resolved)).toEqual([ - `${resolved}/packages/a/package.json`, - `${resolved}/packages/b/package.json`, - `${resolved}/packages/c/package.json`, - `${resolved}/packages/d/package.json`, - ]); - }); -}); diff --git a/yarn.lock b/yarn.lock index 7b75f10..740064e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -240,6 +240,13 @@ dependencies: regenerator-runtime "^0.13.4" +"@babel/runtime@^7.5.5": + version "7.13.9" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.13.9.tgz#97dbe2116e2630c489f22e0656decd60aaa1fcee" + integrity sha512-aY2kU+xgJ3dJ1eU6FMB9EH8dIe8dmusF1xEku52joLvw6eAFN0AI+WxCLDnpev2LEejWBAy2sBvBOBAjI3zmvA== + dependencies: + regenerator-runtime "^0.13.4" + "@babel/template@^7.10.4", "@babel/template@^7.3.3": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.10.4.tgz#3251996c4200ebc71d1a8fc405fba940f36ba278" @@ -634,6 +641,27 @@ "@types/yargs" "^15.0.0" chalk "^4.0.0" +"@manypkg/find-root@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@manypkg/find-root/-/find-root-1.1.0.tgz#a62d8ed1cd7e7d4c11d9d52a8397460b5d4ad29f" + integrity sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA== + dependencies: + "@babel/runtime" "^7.5.5" + "@types/node" "^12.7.1" + find-up "^4.1.0" + fs-extra "^8.1.0" + +"@manypkg/get-packages@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@manypkg/get-packages/-/get-packages-1.1.1.tgz#7c7e72d0061ab2e61d2ce4da58ce91290a60ac8d" + integrity sha512-J6VClfQSVgR6958eIDTGjfdCrELy1eT+SHeoSMomnvRQVktZMnEA5edIr5ovRFNw5y+Bk/jyoevPzGYod96mhw== + dependencies: + "@babel/runtime" "^7.5.5" + "@manypkg/find-root" "^1.1.0" + fs-extra "^8.1.0" + globby "^11.0.0" + read-yaml-file "^1.1.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" @@ -922,6 +950,11 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.7.tgz#8ea1e8f8eae2430cf440564b98c6dfce1ec5945d" integrity sha512-Zw1vhUSQZYw+7u5dAwNbIA9TuTotpzY/OF7sJM9FqPOF3SPjKnxrjoTktXDZgUjybf4cWVBP7O8wvKdSaGHweg== +"@types/node@^12.7.1": + version "12.20.4" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.4.tgz#73687043dd00fcb6962c60fbf499553a24d6bdf2" + integrity sha512-xRCgeE0Q4pT5UZ189TJ3SpYuX/QGl6QIAOAIeDSbAVAd2gX1NxSZup4jNVK7cxIeP8KDSbJgcckun495isP1jQ== + "@types/normalize-package-data@^2.4.0": version "2.4.0" resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz#e486d0d97396d79beedd0a6e33f4534ff6b4973e" @@ -2872,6 +2905,15 @@ from2@^2.1.0, from2@^2.3.0: inherits "^2.0.1" readable-stream "^2.0.0" +fs-extra@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" + integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^4.0.0" + universalify "^0.1.0" + fs-extra@^9.0.0: version "9.0.1" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.0.1.tgz#910da0062437ba4c39fedd863f1675ccfefcb9fc" @@ -3146,6 +3188,11 @@ graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6 resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb" integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw== +graceful-fs@^4.1.5: + version "4.2.6" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.6.tgz#ff040b2b0853b23c3d31027523706f1885d76bee" + integrity sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ== + growly@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" @@ -4239,6 +4286,14 @@ js-yaml@^3.13.1: argparse "^1.0.7" esprima "^4.0.0" +js-yaml@^3.6.1: + version "3.14.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" + integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + jsbn@~0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" @@ -4318,6 +4373,13 @@ json5@^2.1.2: dependencies: minimist "^1.2.5" +jsonfile@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" + integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= + optionalDependencies: + graceful-fs "^4.1.6" + jsonfile@^6.0.1: version "6.1.0" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" @@ -5852,6 +5914,11 @@ pify@^3.0.0: resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= +pify@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" + integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== + pirates@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.1.tgz#643a92caf894566f91b2b986d2c66950a8e2fb87" @@ -6148,6 +6215,16 @@ read-pkg@^5.0.0, read-pkg@^5.2.0: parse-json "^5.0.0" type-fest "^0.6.0" +read-yaml-file@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/read-yaml-file/-/read-yaml-file-1.1.0.tgz#9362bbcbdc77007cc8ea4519fe1c0b821a7ce0d8" + integrity sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA== + dependencies: + graceful-fs "^4.1.5" + js-yaml "^3.6.1" + pify "^4.0.1" + strip-bom "^3.0.0" + read@1, read@~1.0.1, read@~1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/read/-/read-1.0.7.tgz#b3da19bd052431a97671d44a42634adf710b40c4" @@ -7390,6 +7467,11 @@ universal-user-agent@^6.0.0: resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-6.0.0.tgz#3381f8503b251c0d9cd21bc1de939ec9df5480ee" integrity sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w== +universalify@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== + universalify@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/universalify/-/universalify-1.0.0.tgz#b61a1da173e8435b2fe3c67d29b9adf8594bd16d"