Skip to content

Commit

Permalink
feat(workspaces): add support for npm, pnpm, bolt (#52)
Browse files Browse the repository at this point in the history
  • Loading branch information
betaboon committed Mar 8, 2021
1 parent e77905d commit 68986d2
Show file tree
Hide file tree
Showing 47 changed files with 645 additions and 128 deletions.
57 changes: 56 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand All @@ -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 <dave@shax.com",
"version": "0.0.0-semantically-released",
"private": true,
"license": "0BSD",
"engines": {
"node": ">=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:

Expand Down Expand Up @@ -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.

Expand Down
8 changes: 4 additions & 4 deletions bin/runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand All @@ -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(
Expand Down
56 changes: 56 additions & 0 deletions lib/getPackagePaths.js
Original file line number Diff line number Diff line change
@@ -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;
47 changes: 0 additions & 47 deletions lib/getWorkspacesYarn.js

This file was deleted.

5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
]
},
"dependencies": {
"@manypkg/get-packages": "^1.1.1",
"blork": "^9.2.2",
"cosmiconfig": "^7.0.0",
"debug": "^4.3.1",
Expand All @@ -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",
Expand Down
22 changes: 22 additions & 0 deletions test/fixtures/boltWorkspaces/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"name": "msr-test-bolt",
"author": "Dave Houlbrooke <dave@shax.com>",
"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
}
}
8 changes: 8 additions & 0 deletions test/fixtures/boltWorkspaces/packages/a/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"name": "msr-test-a",
"version": "0.0.0",
"peerDependencies": {
"msr-test-c": "*",
"left-pad": "latest"
}
}
11 changes: 11 additions & 0 deletions test/fixtures/boltWorkspaces/packages/b/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"name": "msr-test-b",
"version": "0.0.0",
"dependencies": {
"msr-test-a": "*"
},
"devDependencies": {
"msr-test-c": "*",
"left-pad": "latest"
}
}
3 changes: 3 additions & 0 deletions test/fixtures/boltWorkspaces/packages/c/.releaserc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"tagFormat": "multi-semantic-release-test-c@v${version}"
}
8 changes: 8 additions & 0 deletions test/fixtures/boltWorkspaces/packages/c/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"name": "msr-test-c",
"version": "0.0.0",
"devDependencies": {
"msr-test-b": "*",
"msr-test-d": "*"
}
}
4 changes: 4 additions & 0 deletions test/fixtures/boltWorkspaces/packages/d/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"name": "msr-test-d",
"version": "0.0.0"
}
23 changes: 23 additions & 0 deletions test/fixtures/boltWorkspacesIgnore/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"name": "msr-test-bolt",
"author": "Dave Houlbrooke <dave@shax.com",
"version": "0.0.0-semantically-released",
"private": true,
"license": "0BSD",
"engines": {
"node": ">=8.3"
},
"bolt": {
"workspaces": [
"packages/*",
"!packages/d/**"
]
},
"release": {
"plugins": [
"@semantic-release/commit-analyzer",
"@semantic-release/release-notes-generator"
],
"noCi": true
}
}
8 changes: 8 additions & 0 deletions test/fixtures/boltWorkspacesIgnore/packages/a/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"name": "msr-test-a",
"version": "0.0.0",
"peerDependencies": {
"msr-test-c": "*",
"left-pad": "latest"
}
}
12 changes: 12 additions & 0 deletions test/fixtures/boltWorkspacesIgnore/packages/b/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@

{
"name": "msr-test-b",
"version": "0.0.0",
"dependencies": {
"msr-test-a": "*"
},
"devDependencies": {
"msr-test-c": "*",
"left-pad": "latest"
}
}
3 changes: 3 additions & 0 deletions test/fixtures/boltWorkspacesIgnore/packages/c/.releaserc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"tagFormat": "multi-semantic-release-test-c@v${version}"
}
8 changes: 8 additions & 0 deletions test/fixtures/boltWorkspacesIgnore/packages/c/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"name": "msr-test-c",
"version": "0.0.0",
"devDependencies": {
"msr-test-b": "*",
"msr-test-d": "*"
}
}
4 changes: 4 additions & 0 deletions test/fixtures/boltWorkspacesIgnore/packages/d/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"name": "msr-test-d",
"version": "0.0.0"
}
19 changes: 19 additions & 0 deletions test/fixtures/boltWorkspacesUndefined/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "msr-test-bolt",
"author": "Dave Houlbrooke <dave@shax.com>",
"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
}
}
8 changes: 8 additions & 0 deletions test/fixtures/boltWorkspacesUndefined/packages/a/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"name": "msr-test-a",
"version": "0.0.0",
"peerDependencies": {
"msr-test-c": "*",
"left-pad": "latest"
}
}

0 comments on commit 68986d2

Please sign in to comment.