diff --git a/README.md b/README.md index 76235eb..a3daf04 100644 --- a/README.md +++ b/README.md @@ -5,20 +5,20 @@ Apply [`semantic-release`'s](https://github.com/semantic-release/semantic-release) automatic publishing to a monorepo. ## Why + The default configuration of `semantic-release` assumes a one-to-one relationship between a GitHub repository and an `npm` package. -The default configuration of `semantic-release` assumes a one-to-one relationship between a GitHub repository and an `npm` package. - -This set of plugins allows using `semantic-release` with a single GitHub repository containing many `npm` packages. +This library allows using `semantic-release` with a single GitHub repository containing many `npm` packages. ## How Instead of attributing all commits to a single package, commits are assigned to packages based on the files that a commit touched. -If a commit touched a file in or below a package's root, it will be considered for that package's next release. A single commit can belong to multiple packages and a merge may release multiple package versions. +If a commit touched a file in or below a package's root, it will be considered for that package's next release. A single commit can belong to multiple packages and may trigger the release of multiple packages. -In order to avoid version collisions, release git tags are namespaced using the given package's name: `-`. +In order to avoid version collisions, generated git tags are namespaced using the given package's name: `-`. ## Install +Both `semantic-release` and `semantic-release-monorepo` must be accessible in each monorepo package. ```bash npm install -D semantic-release semantic-release-monorepo @@ -26,60 +26,48 @@ npm install -D semantic-release semantic-release-monorepo ## Usage -Run `semantic-release-monorepo` for the package in the current working directory: +Run `semantic-release` in the **root of a monorepo package** and apply `semantic-release-monorepo` via the [`extends`](https://github.com/semantic-release/semantic-release/blob/master/docs/usage/configuration.md#extends) option. +On the command line: ```bash -npx semantic-release -e semantic-release-monorepo +$ npm run semantic-release -e semantic-release-monorepo ``` -It helps to think about `semantic-release-monorepo` as a variation on `semantic-release`'s default behavior, using the latter's plugin system to adapt it to work with a monorepo. - -### With Lerna - -The monorepo management tool [`lerna`](https://github.com/lerna/lerna) can be used to run `semantic-release-monorepo` across all packages in a monorepo: - -```bash -lerna exec --concurrency 1 -- npx --no-install semantic-release -e semantic-release-monorepo +Or in the [release config](https://github.com/semantic-release/semantic-release/blob/master/docs/usage/configuration.md#configuration-file): +```json +{ + "extends": "semantic-release-monorepo" +} ``` -Note that this requires installing `semantic-release` and `semantic-release-monorepo` for each package. - -Alternatively, thanks to how [`npx's package resolution works`](https://github.com/zkat/npx#description), if the repository root is in `$PATH` (typically true on CI), `semantic-release` and `semantic-release-monorepo` can be installed once in the repo root instead of in each individual package, likely saving both time and disk space. - -### Performance -Naturally, the more packages in a monorepo, the longer it takes `semantic-release` to run against all of them. If total runtime becomes a problem, consider the following optimization: +NOTE: This library **CAN'T** be applied via the `plugins` option. -#### Reduce expensive network calls (50%+ runtime reduction) -By default, `semantic-release`'s `verifyConditions` plugin configuration contains `@semantic-release/npm` and `@semantic-release/github`. These two plugins each make a network call to verify that credentials for the respective services are properly configured. When running in a monorepo, these verifications will be redundantly repeated for each and every package, greatly contributing to overall runtime. Optimally, we'd only want make these verification calls one time. - -By moving these plugins to the `verifyRelease` configuration, they will only run if `semantic-release` determines a release is to be made for a given package (at a time when the given verifications are actually relevant). Likely, most times `semantic-release` is run over a monorepo, only a small subset of all packages trigger releases. - -NOTE: To allow for dynamic code, this example defines the release configuration in [`.releaserc.js`](https://github.com/semantic-release/semantic-release/blob/caribou/docs/usage/configuration.md#configuration) instead of inside of `package.json`. - -```js -module.exports = { - verifyConditions: [], - verifyRelease: ['@semantic-release/npm', '@semantic-release/github'] - .map(require) - .map(x => x.verifyConditions), -}; +```json +{ + "plugins": [ + "semantic-release-monorepo" // This WON'T work + ] +} ``` -### Advanced - -The set of `semantic-release-monorepo` plugins wrap the default `semantic-release` workflow, augmenting it to work with a monorepo. - -#### analyzeCommits +### With Lerna +The monorepo management tool [`lerna`](https://github.com/lerna/lerna) can be used to run `semantic-release-monorepo` across all packages in a monorepo with a single command: -* Filters the repo commits to only include those that touched files in the given monorepo package. +```bash +lerna exec --concurrency 1 -- npx --no-install semantic-release -e semantic-release-monorepo +``` -#### generateNotes + Thanks to how [`npx's package resolution works`](https://github.com/npm/npx#description), if the repository root is in `$PATH` (typically true on CI), `semantic-release` and `semantic-release-monorepo` can be installed once in the repo root instead of in each individual package, likely saving both time and disk space. -* Filters the repo commits to only include those that touched files in the given monorepo package. +## Advanced +This library modifies the `context` object passed to `semantic-release` plugins in the following way to make them compatible with a monorepo. -* Maps the `version` field of `nextRelease` to use the [monorepo git tag format](#how). The wrapped (default) `generateNotes` implementation uses `version` as the header for the release notes. Since all release notes end up in the same Github repository, using just the version as a header introduces ambiguity. +| Step | Description | +| ------------------ | ----------------------------------------------------------------------------------------------------- | +| `analyzeCommits` | Filters `context.commits` to only include the given monorepo package's commits. | +| `generateNotes` |
  • Filters `context.commits` to only include the given monorepo package's commits.
  • Modifies `context.nextRelease.version` to use the [monorepo git tag format](#how). The wrapped (default) `generateNotes` implementation uses this variable as the header for the release notes. Since all release notes end up in the same Github repository, using just the version as a header introduces ambiguity.
| -#### tagFormat +### tagFormat Pre-configures the [`tagFormat` option](https://github.com/semantic-release/semantic-release/blob/caribou/docs/usage/configuration.md#tagformat) to use the [monorepo git tag format](#how). @@ -89,5 +77,4 @@ If you are using Lerna, you can customize the format using the following command "semantic-release": "lerna exec --concurrency 1 -- semantic-release -e semantic-release-monorepo --tag-format='${LERNA_PACKAGE_NAME}-v\\${version}'" ``` -Where `'${LERNA_PACKAGE_NAME}-v\\${version}'` is the string you want to customize. -By default it will be `-v` (e.g. `foobar-v1.2.3`). +Where `'${LERNA_PACKAGE_NAME}-v\\${version}'` is the string you want to customize. By default it will be `-v` (e.g. `foobar-v1.2.3`).