1 | # semantic-release-monorepo
|
2 |
|
3 | ![Tests workflow](https://github.com/pmowrer/semantic-release-monorepo/actions/workflows/tests.yml/badge.svg) [![npm](https://img.shields.io/npm/v/semantic-release-monorepo.svg)](https://www.npmjs.com/package/semantic-release-monorepo) [![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)
|
4 |
|
5 | Apply [`semantic-release`'s](https://github.com/semantic-release/semantic-release) automatic publishing to a monorepo.
|
6 |
|
7 | ## Why
|
8 |
|
9 | The default configuration of `semantic-release` assumes a one-to-one relationship between a GitHub repository and an `npm` package.
|
10 |
|
11 | This library allows using `semantic-release` with a single GitHub repository containing many `npm` packages.
|
12 |
|
13 | ## How
|
14 |
|
15 | Instead of attributing all commits to a single package, commits are assigned to packages based on the files that a commit touched.
|
16 |
|
17 | 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.
|
18 |
|
19 | In order to avoid version collisions, generated git tags are namespaced using the given package's name: `<package-name>-<version>`.
|
20 |
|
21 | ## Install
|
22 |
|
23 | Both `semantic-release` and `semantic-release-monorepo` must be accessible in each monorepo package.
|
24 |
|
25 | ```bash
|
26 | npm install -D semantic-release semantic-release-monorepo
|
27 | ```
|
28 |
|
29 | ## Usage
|
30 |
|
31 | Run `semantic-release` in an **individual 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.
|
32 |
|
33 | On the command line:
|
34 |
|
35 | ```bash
|
36 | $ npm run semantic-release -e semantic-release-monorepo
|
37 | ```
|
38 |
|
39 | Or in the [release config](https://github.com/semantic-release/semantic-release/blob/master/docs/usage/configuration.md#configuration-file):
|
40 |
|
41 | ```json
|
42 | {
|
43 | "extends": "semantic-release-monorepo"
|
44 | }
|
45 | ```
|
46 |
|
47 | NOTE: This library **CAN'T** be applied via the `plugins` option.
|
48 |
|
49 | ```json
|
50 | {
|
51 | "plugins": [
|
52 | "semantic-release-monorepo" // This WON'T work
|
53 | ]
|
54 | }
|
55 | ```
|
56 |
|
57 | ### With Yarn Workspaces
|
58 |
|
59 | ```bash
|
60 | $ yarn workspaces run semantic-release -e semantic-release-monorepo
|
61 | ```
|
62 |
|
63 | ### With Lerna
|
64 |
|
65 | 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:
|
66 |
|
67 | ```bash
|
68 | lerna exec --concurrency 1 -- npx --no-install semantic-release -e semantic-release-monorepo
|
69 | ```
|
70 |
|
71 | ### With pnpm
|
72 |
|
73 | [pnpm](https://pnpm.io/) has built-in [workspace](https://pnpm.io/workspaces) functionality for monorepos. Similarly to the above, you can use pnpm to make release in all packages:
|
74 |
|
75 | ```bash
|
76 | pnpm -r --workspace-concurrency=1 exec -- npx --no-install semantic-release -e semantic-release-monorepo
|
77 | ```
|
78 |
|
79 | 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.
|
80 |
|
81 | ## Advanced
|
82 |
|
83 | This library modifies the `context` object passed to `semantic-release` plugins in the following way to make them compatible with a monorepo.
|
84 |
|
85 | | Step | Description |
|
86 | | ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
87 | | `analyzeCommits` | Filters `context.commits` to only include the given monorepo package's commits. |
|
88 | | `generateNotes` | <ul><li>Filters `context.commits` to only include the given monorepo package's commits.</li><li>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.</li></ul> |
|
89 |
|
90 | ### tagFormat
|
91 |
|
92 | 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).
|
93 |
|
94 | If you are using Lerna, you can customize the format using the following command:
|
95 |
|
96 | ```
|
97 | "semantic-release": "lerna exec --concurrency 1 -- semantic-release -e semantic-release-monorepo --tag-format='${LERNA_PACKAGE_NAME}-v\\${version}'"
|
98 | ```
|
99 |
|
100 | Where `'${LERNA_PACKAGE_NAME}-v\\${version}'` is the string you want to customize. By default it will be `<PACKAGE_NAME>-v<VERSION>` (e.g. `foobar-v1.2.3`).
|