|
| 1 | +# Preparing & Releasing Breaking Changes |
| 2 | + |
| 3 | +When developing packages, it is always important to be intentional about the impact that changes have on projects which use those packages. However, special consideration must be given to breaking changes. |
| 4 | + |
| 5 | +This guide provides best practices for documenting, preparing, releasing, and adapting to breaking changes within `core` and in other projects. |
| 6 | + |
| 7 | +## What is a breaking change? |
| 8 | + |
| 9 | +A change to a package is "breaking" if upgrading a project to a version containing the change would require modifications to source code or configuration in order to avoid user- or developer-facing problems (an inability to use or build the project, a loss of functionality, etc.). |
| 10 | + |
| 11 | +There are many kinds of breaking changes. Here are some examples: |
| 12 | + |
| 13 | +- Removals |
| 14 | + - Removing a method from a class |
| 15 | + - Removing an export from a package (including a type export) |
| 16 | +- Functional changes that require code changes or change expectations |
| 17 | + - Changing the number of required arguments for a function or method |
| 18 | + - Throwing a new error in a function or method |
| 19 | + - Changing a function or method so that it no longer fires an event |
| 20 | +- Breaking changes to types |
| 21 | + - Adding external actions or events to a messenger type |
| 22 | + - Narrowing the type of an argument in a function or method |
| 23 | + - Changing the number of required properties in an object type |
| 24 | + - Narrowing the type of a property in an object type |
| 25 | + - Changing the number of type parameters for a type |
| 26 | + - Making any other change listed [here](https://www.semver-ts.org/formal-spec/2-breaking-changes.html) |
| 27 | +- Bumping the minimum supported Node.js version of a package |
| 28 | +- Upgrading a dependency referenced in published code to a version that causes any of the above |
| 29 | + |
| 30 | +## Introducing breaking changes safely |
| 31 | + |
| 32 | +Before merging a PR that introduces breaking changes, it is important to ensure that they are accounted for among projects. |
| 33 | + |
| 34 | +### 1. Document breaking changes |
| 35 | + |
| 36 | +To inform other maintainers now and in the future, make sure that breaking changes are documented in the changelog: |
| 37 | + |
| 38 | +1. Be explicit in your changelog entries about which classes, functions, types, etc. are affected. |
| 39 | +2. Prefix entries with `**BREAKING:**`. |
| 40 | +3. If relevant, provide details on how consuming code can adapt to the changes safely. |
| 41 | +4. Move entries for breaking changes above all other kinds of changes within the same section. |
| 42 | + |
| 43 | +For example: |
| 44 | + |
| 45 | +```markdown |
| 46 | +### Changed |
| 47 | + |
| 48 | +- **BREAKING:** Add a required `source` argument to `getTransactions` ([#1111](https://github.com/MetaMask/core/pull/1111)) |
| 49 | +- **BREAKING:** Rename `Prices` to `PricesResponse` ([#2222](https://github.com/MetaMask/core/pull/2222)) |
| 50 | +- **BREAKING:** `destroy` is now async ([#3333](https://github.com/MetaMask/core/pull/3333)) |
| 51 | +- Widen the type of `getNetworkClientId` to return `string` ([#4444](https://github.com/MetaMask/core/pull/4444)) |
| 52 | + |
| 53 | +### Removed |
| 54 | + |
| 55 | +- **BREAKING:** Remove `fetchGasPrices` from `GasPricesController` ([#5555](https://github.com/MetaMask/core/pull/5555)) |
| 56 | + - Please use `GasPriceService` instead. |
| 57 | +``` |
| 58 | + |
| 59 | +### 2. Audit dependents |
| 60 | + |
| 61 | +When you release your changes, which codebases will be affected? |
| 62 | + |
| 63 | +Using the changelog as a guide, locate all of the places across MetaMask that use the affected classes, functions, types, etc.: |
| 64 | + |
| 65 | +- To find dependents of your package within `core`, look in the package's `package.json`, or simply search across the repo. |
| 66 | +- To find dependents of your package across MetaMask, do a search on GitHub for import statements or, better, usages of the affected symbols. |
| 67 | + |
| 68 | +### 3. Prepare upgrade PRs for dependents |
| 69 | + |
| 70 | +Finally, how will dependent projects need to adapt to your breaking changes? |
| 71 | + |
| 72 | +For dependent packages located in `core`, you may get type errors immediately that you will have to fix in the same PR that introduces the breaking changes. Otherwise, create new PRs to migrate existing code. |
| 73 | + |
| 74 | +For other projects that live outside of `core`, you can use the following process to verify the effects: |
| 75 | + |
| 76 | +1. Create a [preview build](./contributing.md#testing-changes-to-packages-with-preview-builds) for your package. |
| 77 | +2. Open draft PRs in the dependent projects. |
| 78 | +3. In each draft PR, upgrade your package to the preview build. |
| 79 | +4. Test the project, particularly the functionality that makes use of your package. |
| 80 | +5. If you see compile-time or runtime errors, make changes to the project as necessary. |
| 81 | +6. If you discover new breaking changes in your package that you haven't yet listed in the changelog, go back and [document them](#1-document-breaking-changes). |
| 82 | +7. Once you've done this for all projects, check off the "I've followed the process for releasing breaking changes" item in the checklist at the bottom of your PR. |
| 83 | + |
| 84 | +This process serves as a check to help you understand the full impact of your changes. It will also save you time after you make a new release, because you can reuse the draft PRs later to complete upgrades. |
0 commit comments