diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 33aff010c02..4aea508d7e6 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -27,5 +27,5 @@ For example: - [ ] I've updated the test suite for new or updated code as appropriate - [ ] I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate -- [ ] I've communicated my changes to consumers by [updating changelogs for packages I've changed](https://github.com/MetaMask/core/tree/main/docs/contributing.md#updating-changelogs) -- [ ] I've introduced [breaking changes](https://github.com/MetaMask/core/tree/main/docs/breaking-changes.md) in this PR and have prepared draft pull requests for clients and consumer packages to resolve them +- [ ] I've communicated my changes to consumers by [updating changelogs for packages I've changed](https://github.com/MetaMask/core/tree/main/docs/processes/updating-changelogs.md) +- [ ] I've introduced [breaking changes](https://github.com/MetaMask/core/tree/main/docs/processes/breaking-changes.md) in this PR and have prepared draft pull requests for clients and consumer packages to resolve them diff --git a/.gitignore b/.gitignore index f6a3711b1a2..c19f8765313 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,7 @@ examples/*/docs packages/*/coverage packages/*/dist packages/*/docs +!packages/core-backend/docs scripts/coverage # yarn v3 (w/o zero-install) diff --git a/README.md b/README.md index b69b9d629fb..d160aa00324 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ This monorepo is a collection of packages used across multiple MetaMask clients ## Contributing -See the [Contributor Guide](./docs/contributing.md) for help on: +See the [Contributor Documentation](./docs) for help on: - Setting up your development environment - Working with the monorepo diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 00000000000..81c02397664 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,32 @@ +# Contributor Documentation + +Hi! Welcome to the contributor documentation for the `core` monorepo. + +## Getting started + +- [Setting up your development environment](./getting-started/setting-up-your-environment.md) +- [Codeownership](./getting-started/codeownership.md) +- [Code guidelines for this repo](#code-guidelines) + +## Processes + +- [Performing operations across the monorepo](./processes/general-monorepo-operations.md) +- [Writing and running tests](./processes/testing.md) +- [Linting and formatting](./processes/linting-and-formatting.md) +- [Updating changelogs](./processes/updating-changelogs.md) +- [Creating pull requests](./processes/creating-pull-requests.md) +- [Releasing changes](./processes/releasing.md) + - [Preparing and releasing breaking changes](./processes/breaking-changes.md) + - [Reviewing release PRs](./processes/reviewing-release-prs.md) +- [Testing changes to packages in other projects](./processes/testing-changes-in-other-projects.md) +- [Building packages](./processes/building.md) +- [Adding new packages to the monorepo](./processes/adding-new-packages.md) +- [Migrating external packages to the monorepo](./processes/package-migration-process-guide.md) + - [Migrating tags](./processes/migrate-tags.md) + +## Code guidelines + +- [General MetaMask code guidelines](https://github.com/MetaMask/contributor-docs) +- [General guidelines for all packages](./code-guidelines/package-guidelines.md) +- [Writing controllers](./code-guidelines/controller-guidelines.md) +- [Writing data services](./code-guidelines/data-services.md) diff --git a/docs/controller-guidelines.md b/docs/code-guidelines/controller-guidelines.md similarity index 98% rename from docs/controller-guidelines.md rename to docs/code-guidelines/controller-guidelines.md index f4db78d4580..368a31a204d 100644 --- a/docs/controller-guidelines.md +++ b/docs/code-guidelines/controller-guidelines.md @@ -1,4 +1,4 @@ -# Guidelines for Writing Controllers +# Guidelines for writing controllers ## Understand the purpose of the controller pattern @@ -64,7 +64,7 @@ class FooController extends BaseController { ## Provide a default representation of state -Each controller needs a default representation in order to fully initialize itself when [receiving a partial representation of state](#accept-a-partial-representation-of-state). A default representation of state is also useful when testing interactions with a controller's `*:stateChange` event. +Each controller needs a default representation in order to fully initialize itself when [receiving a partial representation of state](#accept-an-optional-partial-representation-of-state). A default representation of state is also useful when testing interactions with a controller's `*:stateChange` event. A function which returns this default representation should be defined and exported. It should be called `getDefault${ControllerName}State`. @@ -637,7 +637,7 @@ export type FooControllerMessenger = Messenger< >; ``` -If, in a test, you need to access all of the actions supported by a messenger, use the [`MessengerActions` utility type](../packages/messenger/src/Messenger.ts): +If, in a test, you need to access all of the actions supported by a messenger, use the [`MessengerActions` utility type](../../packages/messenger/src/Messenger.ts): ```typescript import type { MessengerActions, MessengerEvents } from '@metamask/messenger'; @@ -716,7 +716,7 @@ export type FooControllerMessenger = Messenger< >; ``` -If, in a test, you need to access all of the events supported by a messenger, use the [`MessengerEvents` utility type](../packages/messenger/src/Messenger.ts): +If, in a test, you need to access all of the events supported by a messenger, use the [`MessengerEvents` utility type](../../packages/messenger/src/Messenger.ts): ```typescript import type { MessengerActions, MessengerEvents } from '@metamask/messenger'; @@ -1432,7 +1432,7 @@ export const selectActiveAccounts = createSelector( ## Treat state-mutating methods as actions -Just as each property of state [does not require a getter method to be accessed](#remove-getters-in-favor-of-direct-state-access), each property of state does not require a setter method to be updated, either. +Just as each property of state [does not require a getter method to be accessed](#expose-derived-state-using-selectors-instead-of-getters), each property of state does not require a setter method to be updated, either. Methods that change the state of the controller do not need to represent granular, low-level operations such as adding, updating, or deleting a single property from state. Rather, they should be designed to support a higher-level task that the consumer wants to carry out. This is ultimately dictated by the needs of the client UI, and so they should also be given a name that reflects the behavior in the UI. diff --git a/docs/data-services.md b/docs/code-guidelines/data-services.md similarity index 98% rename from docs/data-services.md rename to docs/code-guidelines/data-services.md index cfd3967d3dc..554109ddf72 100644 --- a/docs/data-services.md +++ b/docs/code-guidelines/data-services.md @@ -1,4 +1,4 @@ -# Data Services +# Data services ## What is a data service? @@ -480,4 +480,4 @@ class SendController extends BaseController { ## Learning more -The [`sample-controllers`](../packages/sample-controllers) package has a full example of the data service pattern. including JSDoc for all types, classes, and methods. Check it out and feel free to copy and paste the code you see to your own project. +The [`sample-controllers`](../../packages/sample-controllers) package has a full example of the data service pattern. including JSDoc for all types, classes, and methods. Check it out and feel free to copy and paste the code you see to your own project. diff --git a/docs/package-guidelines.md b/docs/code-guidelines/package-guidelines.md similarity index 98% rename from docs/package-guidelines.md rename to docs/code-guidelines/package-guidelines.md index e3cb63f97eb..75b26215e8c 100644 --- a/docs/package-guidelines.md +++ b/docs/code-guidelines/package-guidelines.md @@ -1,4 +1,4 @@ -# Guidelines for Packages +# Guidelines for packages ## List exports explicitly diff --git a/docs/contributing.md b/docs/contributing.md deleted file mode 100644 index b7c94829e70..00000000000 --- a/docs/contributing.md +++ /dev/null @@ -1,401 +0,0 @@ -# Contributor Guide - -## Table of contents - -- [Setting up your development environment](#setting-up-your-development-environment) -- [Understanding codeowners](#understanding-codeowners) -- [Understanding code guidelines](#understanding-code-guidelines) -- [Writing and running tests](#writing-and-running-tests) -- [Linting](#linting) -- [Building](#building) -- [Creating pull requests](#creating-pull-requests) -- [Testing changes to packages in another project](#testing-changes-to-packages-in-another-project) -- [Releasing changes](#releasing-changes) - - [Preparing and releasing breaking changes](./breaking-changes.md) -- [Performing operations across the monorepo](#performing-operations-across-the-monorepo) -- [Adding new packages to the monorepo](#adding-new-packages-to-the-monorepo) - -## Setting up your development environment - -1. Install the current LTS version of [Node](https://nodejs.org). - - If you are using [NVM](https://github.com/creationix/nvm#installation) (recommended), running `nvm install` will install the latest version, and running `nvm use` will automatically choose the right Node version for you. -2. Run `corepack enable` to install [Yarn](https://yarnpkg.com) via [Corepack](https://github.com/nodejs/corepack?tab=readme-ov-file#how-to-install). - - If you have Yarn installed globally via Homebrew or NPM, you'll need to uninstall it before running this command. -3. Run `yarn install` to install dependencies and run any required post-install scripts. -4. Run `yarn simple-git-hooks` to add a [Git hook](https://github.com/toplenboren/simple-git-hooks#what-is-a-git-hook) to your local development environment which will ensure that all files pass linting before you push a branch. - -## Understanding codeowners - -Although maintenance of this repository is superintended by the Wallet Framework team, the responsibility of maintenance is expected to be shared among multiple teams at MetaMask. In fact, some teams have codeownership over specific packages. The exact allocation is governed by the [`CODEOWNERS`](../.github/CODEOWNERS) file. - -**If your team is listed as a codeowner for a package, you may change, approve pull requests, and create releases without consulting the Wallet Framework team.** Alternatively, if you feel that your team should be granted codeownership over a specific package, you can submit a pull request to change `CODEOWNERS`. - -## Understanding code guidelines - -All code in this repo should not only follow the [MetaMask contributor guidelines](https://github.com/MetaMask/contributor-docs) but also the guidelines contained in this repo: - -- [Package guidelines](./package-guidelines.md) -- [Controller guidelines](./controller-guidelines.md) - -## Writing and running tests - -[Jest](https://jestjs.io/) is used to ensure that code is working as expected. Ideally, all packages should have 100% test coverage. - -Please follow the [MetaMask unit testing guidelines](https://github.com/MetaMask/contributor-docs/blob/main/docs/testing/unit-testing.md) when writing tests. - -If you need to customize the behavior of Jest for a package, see `jest.config.js` within that package. - -- Run `yarn workspace run test` to run all tests for a package. -- Run `yarn workspace run jest --no-coverage ` to run a test file within the context of a package. -- Run `yarn test` to run tests for all packages. - -> **Note** -> -> `workspaceName` in these commands is the `name` field within a package's `package.json`, e.g., `@metamask/address-book-controller`, not the directory where it is located, e.g., `packages/address-book-controller`. - -## Linting - -[ESLint](https://eslint.org) v9 (via [MetaMask's shared ESLint configurations](https://github.com/MetaMask/eslint-config)) is used to check for code quality issues, and [Prettier](https://prettier.io/docs/en/) is used to format files. - -If you need to customize the behavior of ESLint, see `eslint.config.mjs` in the root. - -- Run `yarn lint` to lint all files and show possible violations across the monorepo. -- Run `yarn lint:fix` to fix any automatically fixable violations. - -## Building - -[`ts-bridge`](https://github.com/ts-bridge/ts-bridge) is used to publish packages in both CommonJS- and ESM-compatible formats. - -Built files show up in the `dist/` directory in each package. These are the files which will ultimately be published to NPM. - -- Run `yarn build` to build all packages in the monorepo. -- Run `yarn workspace run build` to build a single package. - -## Updating changelogs - -Each package in this repo has a file called `CHANGELOG.md` which is used to record consumer-facing changes that have been published over time. This file is useful for other engineers who are upgrading to new versions of packages so that they know how to use new features they are expecting, they know when bugs have been addressed, and they understand how to adapt to breaking changes (if any). All changelogs follow the ["Keep a Changelog"](https://keepachangelog.com/) specification (enforced by `@metamask/auto-changelog`). - -As you make changes to packages, make sure to update their changelogs in the same branch. - -We will offer more guidance here in the future, but in general: - -- Place new entries under the "Unreleased" section. -- Place changes into categories. Consult the ["Keep a Changelog"](https://keepachangelog.com/en/1.1.0/#how) specification for the list. -- Highlight breaking changes by prefixing them with `**BREAKING:**`. -- Omit non-consumer facing changes from the changelog. -- Do not simply reuse the commit message, but describe exact changes to the API or usable surface area of the project. -- Use a list nested under a changelog entry to enumerate more details about a change if need be. -- Include links to pull request(s) that introduced each change. (Most likely, this is the very same pull request in which you are updating the changelog.) -- Combine like changes from multiple pull requests into a single changelog entry if necessary. -- Split disparate changes from the same pull request into multiple entries if necessary. -- Omit reverted changes from the changelog. - -## Creating pull requests - -When submitting a pull request for this repo, take some a bit of extra time to fill out its description. Use the provided template as a guide, paying particular attention to the **Explanation** section. This section is intended for you to explain the purpose and scope of your changes and share knowledge that other engineers might not be able to see from reading the PR alone. Some questions you should seek to answer are: - -- What is the motivator for these changes? What need are the changes satisfying? Is there a ticket you can share or can you provide some more context for people who might not be familiar with the domain? -- Are there any changes in particular whose purpose might not be obvious or whose implementation might be difficult to decipher? How do they work? -- If your primary goal was to update one package but you found you had to update another one along the way, why did you do so? -- If you had to upgrade a dependency, why did you do so? - -## Testing changes to packages in another project - -If you have a project that depends on a package in this monorepo, you may want to load those changes into the project without having to create a whole new monorepo release. How you do this depends on your use case. - -### Testing changes to packages locally - -If you're developing your project locally and want to test changes to a package, you can follow these steps: - -1. First, you must build the monorepo, by running `yarn build`. -2. Next, you need to connect the package to your project by overriding the resolution logic in your package manager to replace the published version of the package with the local version. - - 1. Open `package.json` in the project and locate the dependency entry for the package. - 2. Locate the section responsible for resolution overrides (or create it if it doesn't exist). If you're using Yarn, this is `resolutions`; if you're using NPM or any other package manager, this is `overrides`. - 3. Add a line to this section that mirrors the dependency entry on the left-hand side and points to the local path on the right-hand side: - - ``` - "@metamask/@": "file:/packages/" - ``` - - > **Example:** - > - > - If your project uses Yarn, `@metamask/controller-utils` is listed in dependencies at `^1.1.4`, and your clone of the `core` repo is at the same level as your project, add the following to `resolutions`: - > - > ``` - > "@metamask/controller-utils@^1.1.4": "file:../core/packages/controller-utils" - > ``` - - 4. Run `yarn install`. - -3. Due to the use of Yarn's `file:` protocol, if you update the package in the monorepo, then you'll need to run `yarn install` in the project again. - -### Testing changes to packages with preview builds - -If you want to test changes to a package where it would be unwieldy or impossible to use a local version, such as on CI, you can publish a preview build and configure your project to use it. - -#### Publishing preview builds as a MetaMask contributor - -If you're a member of the MetaMask organization, you can create preview builds based on a pull request by following these steps: - -1. Post a comment on the pull request with the text `@metamaskbot publish-preview`. This starts the `publish-preview` GitHub action, which will create preview builds for all packages in the monorepo. -2. After a few minutes, the action should complete and you will see a new comment that lists the newly published packages along with their versions. - - Note two things about each package: - - - The name is scoped to `@metamask-previews` instead of `@metamask`. - - The ID of the last commit in the branch is appended to the version, e.g. `1.2.3-preview-e2df9b4` instead of `1.2.3`. - -Now you can [use these preview builds in your project](#using-preview-builds). - -If you make more changes to a package, follow step 2 again, making sure to update the reference to the package in your project's `package.json` to use the newly published preview version. - -#### Publishing preview builds as an independent contributor - -If you've forked this repository, you can create preview builds based on a branch by following these steps: - -1. First, since an NPM scope is used to host preview build releases, you'll need access to one. If you do not, you can either [create a new organization](https://www.npmjs.com/org/create) or [convert your existing username into an organization](https://www.npmjs.com/org/upgrade). - -2. Once you've done this, open the `package.json` for each package that you want to publish and change the scope in the name from `@metamask` to `@`, replacing `NPM_ORG` with your NPM organization. - -3. Next, run the following command to create and publish the preview builds (again, replacing `NPM_ORG` as appropriate): - - ``` - yarn prepare-preview-builds "@" "$(git rev-parse --short HEAD)" && yarn build && yarn publish-previews - ``` - - You should be able to see the published version of each package in the output. Note two things: - - - The name is scoped to the NPM organization you entered instead of `@metamask`. - - The ID of the last commit in the branch is appended to the version, e.g. `1.2.3-preview-e2df9b4` instead of `1.2.3`. - -Now you can [use these preview builds in your project](#using-preview-builds). - -If you make more changes to a package, follow step 3 again, making sure to update the reference to the package in your project's `package.json` to use the newly published preview version. - -#### Using preview builds - -To use a preview build for a package within a project, you need to override the resolution logic for your package manager so that the "production" version of that package is replaced with the preview version. Here's how you do that: - -1. Open `package.json` in the project and locate the dependency entry for the core package for which you want to use a preview build. -2. Locate the section responsible for resolution overrides (or create it if it doesn't exist). If you're using Yarn, this is `resolutions`; if you're using NPM or any other package manager, this is `overrides`. -3. Add a line to this section that mirrors the dependency entry on the left-hand side and points to the preview version on the right-hand side: - - ``` - "@metamask/@": "npm:@/@" - ``` - - > **Example:** - > - > - If your project uses Yarn, `@metamask/controller-utils` is listed in dependencies at `^1.1.4`, and you want to use the preview version `1.2.3-preview-e2df9b4`, add the following to `resolutions`: - > - > ``` - > "@metamask/controller-utils@^1.1.4": "npm:@metamask-previews/controller-utils@1.2.3-preview-e2df9b4" - > ``` - -4. Run `yarn install`. - -## Releasing changes - -Have changes that you need to release? There are a few things to understand: - -- The responsibility of maintenance is not the only thing shared among multiple teams at MetaMask; releases are as well. That means **if you work on a team that has codeownership over a package, you are free to create a new release without needing the Wallet Framework team to do so.** -- Unlike clients, releases are not issued on a schedule; **anyone may create a release at any time**. Because of this, you may wish to review the Pull Requests tab on GitHub and ensure that no one else has a release candidate already in progress. If not, then you are free to start the process. -- The release process is a work in progress. Further improvements to simplify the process are planned, but in the meantime, if you encounter any issues, please reach out to the Wallet Framework team. -- Breaking changes take special consideration. [Read the guide](./breaking-changes.md) on how to prepare and handle them effectively. - -Now for the process itself, you have two options: using our interactive UI (recommended for most users) or manual specification. - -### Option A: Interactive Mode (Recommended) - -This option provides a visual interface to streamline the release process: - -1. **Start the interactive release tool.** - - On the `main` branch, run: - - ``` - yarn create-release-branch -i - ``` - - This will start a local web server (default port 3000) and open a browser interface. - -2. **Select packages to release.** - - The UI will show all packages with changes since their last release. For each package: - - - Choose whether to include it in the release - - Select an appropriate version bump (patch, minor, or major) following SemVer rules - - The UI will automatically validate your selections and identify dependencies that need to be included - -3. **Review and resolve dependency requirements.** - - The UI automatically analyzes your selections and identifies potential dependency issues that need to be addressed before proceeding. You'll need to review and resolve these issues by either: - - - Including the suggested additional packages - - Confirming that you want to skip certain packages (if you're certain they don't need to be updated) - - Common types of dependency issues you might encounter: - - - **Missing dependencies**: If you're releasing Package A that depends on Package B, the UI will prompt you to include Package B - - **Breaking change impacts**: If you're releasing Package B with breaking changes, the UI will identify packages that have peer dependencies on Package B that need to be updated - - **Version incompatibilities**: The UI will flag if your selected version bumps don't follow semantic versioning rules relative to dependent packages - - Unlike the manual workflow where you need to repeatedly edit a YAML file, in the interactive mode you can quickly resolve these issues by checking boxes and selecting version bumps directly in the UI. - -4. **Confirm your selections.** - - Once you're satisfied with your package selections and version bumps, confirm them in the UI. This will: - - - Create a new branch named `release/` - - Update the version in each package's `package.json` - - Add a new section to each package's `CHANGELOG.md` for the new version - -5. **Review and update changelogs.** - - Each selected package will have a new changelog section. Review these entries to ensure they are helpful for consumers: - - - Categorize entries appropriately following the ["Keep a Changelog"](https://keepachangelog.com/en/1.0.0/) guidelines. Ensure that no changes are listed under "Uncategorized". - - Remove changelog entries that don't affect consumers of the package (e.g. lockfile changes or development environment changes). Exceptions may be made for changes that might be of interest despite not having an effect upon the published package (e.g. major test improvements, security improvements, improved documentation, etc.). - - Reword changelog entries to explain changes in terms that users of the package will understand (e.g., avoid referencing internal variables/concepts). - - Consolidate related changes into single entries where appropriate. - - Run `yarn changelog:validate` when you're done to ensure all changelogs are correctly formatted. - -6. **Push and submit a pull request.** - - Create a PR for the release branch so that it can be reviewed and tested. - Release PRs can be approved by codeowners of affected packages, so as long as the above guidelines have been followed, there is no need to reach out to the Wallet Framework team for approval. - -7. **Incorporate any new changes from `main`.** - - If you see the "Update branch" button on your release PR, stop and look over the most recent commits made to `main`. If there are new changes to packages you are releasing, make sure they are reflected in the appropriate changelogs. - -8. **Merge the release PR and wait for approval.** - - "Squash & Merge" the release PR when it's approved. - - Merging triggers the [`publish-release` GitHub action](https://github.com/MetaMask/action-publish-release) workflow to tag the final release commit and publish the release on GitHub. Before packages are published to NPM, this action will automatically notify the [`npm-publishers`](https://github.com/orgs/MetaMask/teams/npm-publishers) team in Slack to review and approve the release. - -9. **Verify publication.** - - Once the `npm-publishers` team has approved the release, you can click on the link in the Slack message to monitor the remainder of the process. - - After the action has completed, [check NPM](https://npms.io/search?q=scope%3Ametamask) to verify that all relevant packages have been published. - -> **Tip:** You can specify a different port if needed: `yarn create-release-branch -i -p 3001` - -### Option B: Manual Release Specification - -If you prefer more direct control over the release process: - -1. **Start by creating the release branch.** - - On the `main` branch, run `yarn create-release-branch`. This command creates a branch named `release/` which will represent the new release. - -2. **Specify packages to release along with their versions.** - - Unless you've made a lot of breaking changes, you probably don't want to publish a new version of every single package in this repo. Fortunately, you can choose a subset of packages to include in the next release. You do this by modifying a YAML file called a "release spec", which the tool has generated and opened it in your editor. Follow the instructions at the top of the file for more information. - - In addition to selecting a list of packages, you'll also want to tell the tool which new versions they ought to receive. Since you'll want to follow SemVer, how you bump a package depends on the nature of the changes. You can understand these changes better by opening the changelog for each package in your editor. - - Once you save and close the release spec, the tool will proceed. - -3. **Review and resolve dependency requirements.** - - The tool automatically analyzes your selections and identifies potential dependency issues that need to be addressed before proceeding. You'll need to review and resolve these issues by either: - - - Including the suggested additional packages - - Confirming that you want to skip certain packages (if you're certain they don't need to be updated) - - Common types of dependency issues you might encounter: - - - **Missing dependencies**: If you're releasing Package A that depends on Package B, the UI will prompt you to include Package B - - **Breaking change impacts**: If you're releasing Package B with breaking changes, the UI will identify packages that have peer dependencies on Package B that need to be updated - - **Version incompatibilities**: The UI will flag if your selected version bumps don't follow semantic versioning rules relative to dependent packages - - To address these issues, you will need to reopen the YAML file, modify it by either adding more packages to the release or omitting packages from the release you think are safe, and then re-running `yarn create-release-branch`. You may need to repeat this step multiple times until you don't see any more errors. - -4. **Review and update changelogs for relevant packages.** - - Once the tool proceeds without issue, you will be on the new release branch. In addition, each package you intend to release has been updated in two ways: - - - The version in `package.json` has been bumped. - - A new section has been added at the top of `CHANGELOG` for the new version. - - At this point, you need to review the changelog entries and ensure that they are helpful for consumers: - - - Categorize entries appropriately following the ["Keep a Changelog"](https://keepachangelog.com/en/1.0.0/) guidelines. Ensure that no changes are listed under "Uncategorized". - - Remove changelog entries that don't affect consumers of the package (e.g. lockfile changes or development environment changes). Exceptions may be made for changes that might be of interest despite not having an effect upon the published package (e.g. major test improvements, security improvements, improved documentation, etc.). - - Reword changelog entries to explain changes in terms that users of the package will understand (e.g., avoid referencing internal variables/concepts). - - Consolidate related changes into single entries where appropriate. - - Make sure to run `yarn changelog:validate` once you're done to ensure all changelogs are correctly formatted. - -5. **Push and submit a pull request.** - - Create a PR for the release branch so that it can be reviewed and tested. - Release PRs can be approved by codeowners of affected packages, so as long as the above guidelines have been followed, there is no need to reach out to the Wallet Framework team for approval. - -6. **Incorporate any new changes from `main`.** - - If you see the "Update branch" button on your release PR, stop and look over the most recent commits made to `main`. If there are new changes to packages you are releasing, make sure they are reflected in the appropriate changelogs. - -7. **Merge the release PR and wait for approval.** - - "Squash & Merge" the release PR when it's approved. - - Merging triggers the [`publish-release` GitHub action](https://github.com/MetaMask/action-publish-release) workflow to tag the final release commit and publish the release on GitHub. Before packages are published to NPM, this action will automatically notify the [`npm-publishers`](https://github.com/orgs/MetaMask/teams/npm-publishers) team in Slack to review and approve the release. - -8. **Verify publication.** - - Once the `npm-publishers` team has approved the release, you can click on the link in the Slack message to monitor the remainder of the process. - - After the action has completed, [check NPM](https://npms.io/search?q=scope%3Ametamask) to verify that all relevant packages have been published. - -## Performing operations across the monorepo - -This repository relies on Yarn's [workspaces feature](https://yarnpkg.com/features/workspaces) to provide a way to work with packages individually and collectively. Refer to the documentation for the following Yarn commands for usage instructions: - -- [`yarn workspace`](https://yarnpkg.com/cli/workspace) -- [`yarn workspaces foreach`](https://yarnpkg.com/cli/workspaces/foreach) - -> **Note** -> -> - `workspaceName` in the Yarn documentation is the `name` field within a package's `package.json`, e.g., `@metamask/address-book-controller`, not the directory where it is located, e.g., `packages/address-book-controller`. -> - `commandName` in the Yarn documentation is any sub-command that the `yarn` executable would usually take. Pay special attention to the difference between `run` vs `exec`. If you want to run a package script, you would use `run`, e.g., `yarn workspace @metamask/address-book-controller run changelog:validate`; but if you want to run _any_ shell command, you'd use `exec`, e.g. `yarn workspace @metamask/address-book-controller exec cat package.json | jq '.version'`. - -## Adding new packages to the monorepo - -> [!NOTE] -> If you're migrating an existing package to the monorepo, please see [the package migration documentation](./package-migration-process-guide.md). -> You may be able to make use of `create-package` when migrating your package, but there's a lot more to it. - -Manually creating a new monorepo package can be a tedious, even frustrating process. To alleviate that -problem, we have created a CLI that automates most of the job for us, creatively titled -[`create-package`](../scripts/create-package/). To create a new monorepo package, follow these steps: - -1. Create a new package using `yarn create-package`. - - Use the `--help` flag for usage information. - - Once this is done, you can find a package with your chosen name in `/packages`. -2. Make sure your license is correct. - - By default, `create-package` gives your package an MIT license. - - If your desired license is _not_ MIT, then you must update your `LICENSE` file and the - `license` field of `package.json`. -3. Update `.github/CODEOWNERS` and `teams.json` to assign a team as the owner of the new package. -4. Add your dependencies. - - Do this as normal using `yarn`. - - Remember, if you are adding other monorepo packages as dependents, don't forget to add them - to the `references` array in your package's `tsconfig.json` and `tsconfig.build.json`. - -And that's it! - -### Contributing to `create-package` - -Along with this documentation, `create-package` is intended to be the source of truth for the process of adding new packages to the monorepo. Consequently, to change that process, you will want to change `create-package`. - -The `create-package` directory contains a [template package](../scripts/create-package/package-template/). The CLI is not aware of the contents of the template, only that its files have [placeholder values](../scripts/create-package/constants.ts). When a new package is created, the template files are read from disk, the placeholder values are replaced with real ones, and the updated files are added to a new directory in `/packages`. To modify the template package: - -- If you need to add or modify any files or folders, just go ahead and make your changes in [`/scripts/create-package/package-template`](../scripts/create-package/package-template/). The CLI will read whatever's in that directory and write it to disk. -- If you need to add or modify any placeholders, make sure that your desired values are added to both the relevant file(s) and [`/scripts/create-package/constants.ts`](../scripts/create-package/constants.ts). Then, update the implementation of the CLI accordingly. -- As with placeholders, updating the monorepo files that the CLI interacts with begins by updating [`/scripts/create-package/constants.ts`](../scripts/create-package/constants.ts). diff --git a/docs/getting-started/codeownership.md b/docs/getting-started/codeownership.md new file mode 100644 index 00000000000..4be240c243a --- /dev/null +++ b/docs/getting-started/codeownership.md @@ -0,0 +1,5 @@ +# Understanding codeowners + +Although maintenance of this repository is superintended by the Wallet Framework team, the responsibility of maintenance is expected to be shared among multiple teams at MetaMask. In fact, some teams have codeownership over specific packages. The exact allocation is governed by the [`CODEOWNERS`](../../.github/CODEOWNERS) file. + +**If your team is listed as a codeowner for a package, you may change, approve pull requests, and create releases without consulting the Wallet Framework team.** Alternatively, if you feel that your team should be granted codeownership over a specific package, you can submit a pull request to change `CODEOWNERS`. diff --git a/docs/getting-started/setting-up-your-environment.md b/docs/getting-started/setting-up-your-environment.md new file mode 100644 index 00000000000..585ce17b5ac --- /dev/null +++ b/docs/getting-started/setting-up-your-environment.md @@ -0,0 +1,8 @@ +# Setting up your development environment + +1. Install the current LTS version of [Node](https://nodejs.org). + - If you are using [NVM](https://github.com/creationix/nvm#installation) (recommended), running `nvm install` will install the latest version, and running `nvm use` will automatically choose the right Node version for you. +2. Run `corepack enable` to install [Yarn](https://yarnpkg.com) via [Corepack](https://github.com/nodejs/corepack?tab=readme-ov-file#how-to-install). + - If you have Yarn installed globally via Homebrew or NPM, you'll need to uninstall it before running this command. +3. Run `yarn install` to install dependencies and run any required post-install scripts. +4. Run `yarn simple-git-hooks` to add a [Git hook](https://github.com/toplenboren/simple-git-hooks#what-is-a-git-hook) to your local development environment which will ensure that all files pass linting before you push a branch. diff --git a/docs/processes/adding-new-packages.md b/docs/processes/adding-new-packages.md new file mode 100644 index 00000000000..00d1e4047c8 --- /dev/null +++ b/docs/processes/adding-new-packages.md @@ -0,0 +1,29 @@ +# Adding new packages to the monorepo + +> [!NOTE] +> If you're migrating an existing package to the monorepo, please see [the package migration documentation](./package-migration-process-guide.md). You may be able to make use of `create-package` when migrating your package, but there's a lot more to it. + +Manually creating a new monorepo package can be a tedious, even frustrating process. To alleviate that problem, we have created a CLI that automates most of the job for us, creatively titled [`create-package`](../../scripts/create-package/). To create a new monorepo package, follow these steps: + +1. Create a new package using `yarn create-package`. + - Use the `--help` flag for usage information. + - Once this is done, you can find a package with your chosen name in `/packages`. +2. Make sure your license is correct. + - By default, `create-package` gives your package an MIT license. + - If your desired license is _not_ MIT, then you must update your `LICENSE` file and the `license` field of `package.json`. +3. Update `.github/CODEOWNERS` and `teams.json` to assign a team as the owner of the new package. +4. Add your dependencies. + - Do this as normal using `yarn`. + - Remember, if you are adding other monorepo packages as dependents, don't forget to add them to the `references` array in your package's `tsconfig.json` and `tsconfig.build.json`. + +And that's it! + +### Contributing to `create-package` + +Along with this documentation, `create-package` is intended to be the source of truth for the process of adding new packages to the monorepo. Consequently, to change that process, you will want to change `create-package`. + +The `create-package` directory contains a [template package](../../scripts/create-package/package-template/). The CLI is not aware of the contents of the template, only that its files have [placeholder values](../../scripts/create-package/constants.ts). When a new package is created, the template files are read from disk, the placeholder values are replaced with real ones, and the updated files are added to a new directory in `/packages`. To modify the template package: + +- If you need to add or modify any files or folders, just go ahead and make your changes in [`/scripts/create-package/package-template`](../../scripts/create-package/package-template/). The CLI will read whatever's in that directory and write it to disk. +- If you need to add or modify any placeholders, make sure that your desired values are added to both the relevant file(s) and [`/scripts/create-package/constants.ts`](../../scripts/create-package/constants.ts). Then, update the implementation of the CLI accordingly. +- As with placeholders, updating the monorepo files that the CLI interacts with begins by updating [`/scripts/create-package/constants.ts`](../../scripts/create-package/constants.ts). diff --git a/docs/breaking-changes.md b/docs/processes/breaking-changes.md similarity index 96% rename from docs/breaking-changes.md rename to docs/processes/breaking-changes.md index ddc4971e4b0..bc27e09c227 100644 --- a/docs/breaking-changes.md +++ b/docs/processes/breaking-changes.md @@ -1,4 +1,4 @@ -# Preparing & Releasing Breaking Changes +# Preparing and releasing breaking changes 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. @@ -73,7 +73,7 @@ For dependent packages located in `core`, you may get type errors immediately th For other projects that live outside of `core`, you can use the following process to verify the effects: -1. Create a [preview build](./contributing.md#testing-changes-to-packages-with-preview-builds) for your package. +1. Create a [preview build](./testing-changes-in-other-projects.md#testing-changes-to-packages-with-preview-builds) for your package. 2. Open draft PRs in the dependent projects. 3. In each draft PR, upgrade your package to the preview build. 4. Test the project, particularly the functionality that makes use of your package. diff --git a/docs/processes/building.md b/docs/processes/building.md new file mode 100644 index 00000000000..a4f1629331d --- /dev/null +++ b/docs/processes/building.md @@ -0,0 +1,8 @@ +# Building packages + +[`ts-bridge`](https://github.com/ts-bridge/ts-bridge) is used to build packages in both CommonJS- and ESM-compatible formats. + +Built files show up in the `dist/` directory in each package. These are the files which will ultimately be published to NPM. + +- Run `yarn build` to build all packages in the monorepo. +- Run `yarn workspace run build` to build a single package. diff --git a/docs/processes/creating-pull-requests.md b/docs/processes/creating-pull-requests.md new file mode 100644 index 00000000000..0e3f3d54161 --- /dev/null +++ b/docs/processes/creating-pull-requests.md @@ -0,0 +1,8 @@ +# Creating pull requests + +When submitting a pull request for this repo, take some a bit of extra time to fill out its description. Use the provided template as a guide, paying particular attention to the **Explanation** section. This section is intended for you to explain the purpose and scope of your changes and share knowledge that other engineers might not be able to see from reading the PR alone. Some questions you should seek to answer are: + +- What is the motivator for these changes? What need are the changes satisfying? Is there a ticket you can share or can you provide some more context for people who might not be familiar with the domain? +- Are there any changes in particular whose purpose might not be obvious or whose implementation might be difficult to decipher? How do they work? +- If your primary goal was to update one package but you found you had to update another one along the way, why did you do so? +- If you had to upgrade a dependency, why did you do so? diff --git a/docs/processes/general-monorepo-operations.md b/docs/processes/general-monorepo-operations.md new file mode 100644 index 00000000000..0eb7b16cf08 --- /dev/null +++ b/docs/processes/general-monorepo-operations.md @@ -0,0 +1,11 @@ +# Performing operations across the monorepo + +This repository relies on Yarn's [workspaces feature](https://yarnpkg.com/features/workspaces) to provide a way to work with packages individually and collectively. Refer to the documentation for the following Yarn commands for usage instructions: + +- [`yarn workspace`](https://yarnpkg.com/cli/workspace) +- [`yarn workspaces foreach`](https://yarnpkg.com/cli/workspaces/foreach) + +> **Note** +> +> - `workspaceName` in the Yarn documentation is the `name` field within a package's `package.json`, e.g., `@metamask/address-book-controller`, not the directory where it is located, e.g., `packages/address-book-controller`. +> - `commandName` in the Yarn documentation is any sub-command that the `yarn` executable would usually take. Pay special attention to the difference between `run` vs `exec`. If you want to run a package script, you would use `run`, e.g., `yarn workspace @metamask/address-book-controller run changelog:validate`; but if you want to run _any_ shell command, you'd use `exec`, e.g. `yarn workspace @metamask/address-book-controller exec cat package.json | jq '.version'`. diff --git a/docs/processes/linting-and-formatting.md b/docs/processes/linting-and-formatting.md new file mode 100644 index 00000000000..7d3c7b42750 --- /dev/null +++ b/docs/processes/linting-and-formatting.md @@ -0,0 +1,8 @@ +# Linting and formatting code + +[ESLint](https://eslint.org) v9 (via [MetaMask's shared ESLint configurations](https://github.com/MetaMask/eslint-config)) is used to check for code quality issues, and [Prettier](https://prettier.io/docs/en/) is used to format files. + +If you need to customize the behavior of ESLint, see `eslint.config.mjs` in the root. + +- Run `yarn lint` to lint all files and show possible violations across the monorepo. +- Run `yarn lint:fix` to fix any automatically fixable violations. diff --git a/docs/migrate-tags.md b/docs/processes/migrate-tags.md similarity index 95% rename from docs/migrate-tags.md rename to docs/processes/migrate-tags.md index ea820da9c14..58a7d836124 100644 --- a/docs/migrate-tags.md +++ b/docs/processes/migrate-tags.md @@ -1,6 +1,6 @@ -# `migrate-tags` +# Migrating tags from other repos -When migrating libraries into the core monorepo, the original git history is transferred using the `git-filter-repo` tool (instructions [here](https://github.com/MetaMask/core/issues/1079#issuecomment-1700126302)), but tags attached to release commits are excluded from the process. This is because the tag names (`v[major].[minor].[patch]`) first need to be adjusted to conform to the scheme used by the core repo (`@metamask/@[major].[minor].[patch]`). +When migrating libraries into the core monorepo, the original git history is transferred using the `git-filter-repo` tool (instructions [here](./package-migration-process-guide.md)), but tags attached to release commits are excluded from the process. This is because the tag names (`v[major].[minor].[patch]`) first need to be adjusted to conform to the scheme used by the core repo (`@metamask/@[major].[minor].[patch]`). The `./scripts/migrate-tags.sh` script automates the process of enumerating the tags and associated release commit messages in the original repo, searching the migrated git history in the core repo's `merged-packages/` directory for each commit message, creating tags with correctly-formatted names and attaching them to the found release commits, and pushing those tags to the core repo. diff --git a/docs/package-migration-process-guide.md b/docs/processes/package-migration-process-guide.md similarity index 99% rename from docs/package-migration-process-guide.md rename to docs/processes/package-migration-process-guide.md index cdaf15c9973..7cf4b60f07b 100644 --- a/docs/package-migration-process-guide.md +++ b/docs/processes/package-migration-process-guide.md @@ -1,4 +1,4 @@ -# Package Migration Process Guide +# Package migration process guide This document outlines the process for migrating a MetaMask library into the core monorepo. The migration target is assumed to comply with the requirements defined by [`metamask-module-template`](https://github.com/MetaMask/metamask-module-template) and [`module-lint`](https://github.com/MetaMask/module-lint). diff --git a/docs/processes/releasing.md b/docs/processes/releasing.md new file mode 100644 index 00000000000..23200f6bc33 --- /dev/null +++ b/docs/processes/releasing.md @@ -0,0 +1,157 @@ +# Releasing changes + +Have changes that you need to release? There are a few things to understand: + +- The responsibility of maintenance is not the only thing shared among multiple teams at MetaMask; releases are as well. That means **if you work on a team that has codeownership over a package, you are free to create a new release without needing the Wallet Framework team to do so.** +- Unlike clients, releases are not issued on a schedule; **anyone may create a release at any time**. Because of this, you may wish to review the Pull Requests tab on GitHub and ensure that no one else has a release candidate already in progress. If not, then you are free to start the process. +- The release process is a work in progress. Further improvements to simplify the process are planned, but in the meantime, if you encounter any issues, please reach out to the Wallet Framework team. +- Breaking changes take special consideration. [Read the guide](./breaking-changes.md) on how to prepare and handle them effectively. + +Now for the process itself, you have two options: using our interactive UI (recommended for most users) or manual specification. + +### Option A: Interactive Mode (Recommended) + +This option provides a visual interface to streamline the release process: + +1. **Start the interactive release tool.** + + On the `main` branch, run: + + ``` + yarn create-release-branch -i + ``` + + This will start a local web server (default port 3000) and open a browser interface. + +2. **Select packages to release.** + + The UI will show all packages with changes since their last release. For each package: + + - Choose whether to include it in the release + - Select an appropriate version bump (patch, minor, or major) following SemVer rules + - The UI will automatically validate your selections and identify dependencies that need to be included + +3. **Review and resolve dependency requirements.** + + The UI automatically analyzes your selections and identifies potential dependency issues that need to be addressed before proceeding. You'll need to review and resolve these issues by either: + + - Including the suggested additional packages + - Confirming that you want to skip certain packages (if you're certain they don't need to be updated) + + Common types of dependency issues you might encounter: + + - **Missing dependencies**: If you're releasing Package A that depends on Package B, the UI will prompt you to include Package B + - **Breaking change impacts**: If you're releasing Package B with breaking changes, the UI will identify packages that have peer dependencies on Package B that need to be updated + - **Version incompatibilities**: The UI will flag if your selected version bumps don't follow semantic versioning rules relative to dependent packages + + Unlike the manual workflow where you need to repeatedly edit a YAML file, in the interactive mode you can quickly resolve these issues by checking boxes and selecting version bumps directly in the UI. + +4. **Confirm your selections.** + + Once you're satisfied with your package selections and version bumps, confirm them in the UI. This will: + + - Create a new branch named `release/` + - Update the version in each package's `package.json` + - Add a new section to each package's `CHANGELOG.md` for the new version + +5. **Review and update changelogs.** + + Each selected package will have a new changelog section. Review these entries to ensure they are helpful for consumers: + + - Categorize entries appropriately following the ["Keep a Changelog"](https://keepachangelog.com/en/1.0.0/) guidelines. Ensure that no changes are listed under "Uncategorized". + - Remove changelog entries that don't affect consumers of the package (e.g. lockfile changes or development environment changes). Exceptions may be made for changes that might be of interest despite not having an effect upon the published package (e.g. major test improvements, security improvements, improved documentation, etc.). + - Reword changelog entries to explain changes in terms that users of the package will understand (e.g., avoid referencing internal variables/concepts). + - Consolidate related changes into single entries where appropriate. + + Run `yarn changelog:validate` when you're done to ensure all changelogs are correctly formatted. + +6. **Push and submit a pull request.** + + Create a PR for the release branch so that it can be reviewed and tested. + Release PRs can be approved by codeowners of affected packages, so as long as the above guidelines have been followed, there is no need to reach out to the Wallet Framework team for approval. + +7. **Incorporate any new changes from `main`.** + + If you see the "Update branch" button on your release PR, stop and look over the most recent commits made to `main`. If there are new changes to packages you are releasing, make sure they are reflected in the appropriate changelogs. + +8. **Merge the release PR and wait for approval.** + + "Squash & Merge" the release PR when it's approved. + + Merging triggers the [`publish-release` GitHub action](https://github.com/MetaMask/action-publish-release) workflow to tag the final release commit and publish the release on GitHub. Before packages are published to NPM, this action will automatically notify the [`npm-publishers`](https://github.com/orgs/MetaMask/teams/npm-publishers) team in Slack to review and approve the release. + +9. **Verify publication.** + + Once the `npm-publishers` team has approved the release, you can click on the link in the Slack message to monitor the remainder of the process. + + After the action has completed, [check NPM](https://npms.io/search?q=scope%3Ametamask) to verify that all relevant packages have been published. + +> **Tip:** You can specify a different port if needed: `yarn create-release-branch -i -p 3001` + +### Option B: Manual Release Specification + +If you prefer more direct control over the release process: + +1. **Start by creating the release branch.** + + On the `main` branch, run `yarn create-release-branch`. This command creates a branch named `release/` which will represent the new release. + +2. **Specify packages to release along with their versions.** + + Unless you've made a lot of breaking changes, you probably don't want to publish a new version of every single package in this repo. Fortunately, you can choose a subset of packages to include in the next release. You do this by modifying a YAML file called a "release spec", which the tool has generated and opened it in your editor. Follow the instructions at the top of the file for more information. + + In addition to selecting a list of packages, you'll also want to tell the tool which new versions they ought to receive. Since you'll want to follow SemVer, how you bump a package depends on the nature of the changes. You can understand these changes better by opening the changelog for each package in your editor. + + Once you save and close the release spec, the tool will proceed. + +3. **Review and resolve dependency requirements.** + + The tool automatically analyzes your selections and identifies potential dependency issues that need to be addressed before proceeding. You'll need to review and resolve these issues by either: + + - Including the suggested additional packages + - Confirming that you want to skip certain packages (if you're certain they don't need to be updated) + + Common types of dependency issues you might encounter: + + - **Missing dependencies**: If you're releasing Package A that depends on Package B, the UI will prompt you to include Package B + - **Breaking change impacts**: If you're releasing Package B with breaking changes, the UI will identify packages that have peer dependencies on Package B that need to be updated + - **Version incompatibilities**: The UI will flag if your selected version bumps don't follow semantic versioning rules relative to dependent packages + + To address these issues, you will need to reopen the YAML file, modify it by either adding more packages to the release or omitting packages from the release you think are safe, and then re-running `yarn create-release-branch`. You may need to repeat this step multiple times until you don't see any more errors. + +4. **Review and update changelogs for relevant packages.** + + Once the tool proceeds without issue, you will be on the new release branch. In addition, each package you intend to release has been updated in two ways: + + - The version in `package.json` has been bumped. + - A new section has been added at the top of `CHANGELOG` for the new version. + + At this point, you need to review the changelog entries and ensure that they are helpful for consumers: + + - Categorize entries appropriately following the ["Keep a Changelog"](https://keepachangelog.com/en/1.0.0/) guidelines. Ensure that no changes are listed under "Uncategorized". + - Remove changelog entries that don't affect consumers of the package (e.g. lockfile changes or development environment changes). Exceptions may be made for changes that might be of interest despite not having an effect upon the published package (e.g. major test improvements, security improvements, improved documentation, etc.). + - Reword changelog entries to explain changes in terms that users of the package will understand (e.g., avoid referencing internal variables/concepts). + - Consolidate related changes into single entries where appropriate. + + Make sure to run `yarn changelog:validate` once you're done to ensure all changelogs are correctly formatted. + +5. **Push and submit a pull request.** + + Create a PR for the release branch so that it can be reviewed and tested. + Release PRs can be approved by codeowners of affected packages, so as long as the above guidelines have been followed, there is no need to reach out to the Wallet Framework team for approval. + +6. **Incorporate any new changes from `main`.** + + If you see the "Update branch" button on your release PR, stop and look over the most recent commits made to `main`. If there are new changes to packages you are releasing, make sure they are reflected in the appropriate changelogs. + +7. **Merge the release PR and wait for approval.** + + "Squash & Merge" the release PR when it's approved. + + Merging triggers the [`publish-release` GitHub action](https://github.com/MetaMask/action-publish-release) workflow to tag the final release commit and publish the release on GitHub. Before packages are published to NPM, this action will automatically notify the [`npm-publishers`](https://github.com/orgs/MetaMask/teams/npm-publishers) team in Slack to review and approve the release. + +8. **Verify publication.** + + Once the `npm-publishers` team has approved the release, you can click on the link in the Slack message to monitor the remainder of the process. + + After the action has completed, [check NPM](https://npms.io/search?q=scope%3Ametamask) to verify that all relevant packages have been published. diff --git a/docs/reviewing-release-prs.md b/docs/processes/reviewing-release-prs.md similarity index 99% rename from docs/reviewing-release-prs.md rename to docs/processes/reviewing-release-prs.md index 2e7fdb8155e..7c45b729f75 100644 --- a/docs/reviewing-release-prs.md +++ b/docs/processes/reviewing-release-prs.md @@ -1,4 +1,4 @@ -# Reviewing Release PRs +# Reviewing release PRs In order to publish a new release of the monorepo, a release PR must be created. But before a release PR is merged, it is absolutely critical — even if you are the author of the PR — to review the changes that are about to be published and to ensure that consumers know about them effectively. diff --git a/docs/processes/testing-changes-in-other-projects.md b/docs/processes/testing-changes-in-other-projects.md new file mode 100644 index 00000000000..e9920567517 --- /dev/null +++ b/docs/processes/testing-changes-in-other-projects.md @@ -0,0 +1,95 @@ +# Testing changes to packages in other projects + +If you have a project that depends on a package in this monorepo, you may want to load those changes into the project without having to create a whole new monorepo release. How you do this depends on your use case. + +### Testing changes to packages locally + +If you're developing your project locally and want to test changes to a package, you can follow these steps: + +1. First, you must build the monorepo, by running `yarn build`. +2. Next, you need to connect the package to your project by overriding the resolution logic in your package manager to replace the published version of the package with the local version. + + 1. Open `package.json` in the project and locate the dependency entry for the package. + 2. Locate the section responsible for resolution overrides (or create it if it doesn't exist). If you're using Yarn, this is `resolutions`; if you're using NPM or any other package manager, this is `overrides`. + 3. Add a line to this section that mirrors the dependency entry on the left-hand side and points to the local path on the right-hand side: + + ``` + "@metamask/@": "file:/packages/" + ``` + + > **Example:** + > + > - If your project uses Yarn, `@metamask/controller-utils` is listed in dependencies at `^1.1.4`, and your clone of the `core` repo is at the same level as your project, add the following to `resolutions`: + > + > ``` + > "@metamask/controller-utils@^1.1.4": "file:../core/packages/controller-utils" + > ``` + + 4. Run `yarn install`. + +3. Due to the use of Yarn's `file:` protocol, if you update the package in the monorepo, then you'll need to run `yarn install` in the project again. + +### Testing changes to packages with preview builds + +If you want to test changes to a package where it would be unwieldy or impossible to use a local version, such as on CI, you can publish a preview build and configure your project to use it. + +#### Publishing preview builds as a MetaMask contributor + +If you're a member of the MetaMask organization, you can create preview builds based on a pull request by following these steps: + +1. Post a comment on the pull request with the text `@metamaskbot publish-preview`. This starts the `publish-preview` GitHub action, which will create preview builds for all packages in the monorepo. +2. After a few minutes, the action should complete and you will see a new comment that lists the newly published packages along with their versions. + + Note two things about each package: + + - The name is scoped to `@metamask-previews` instead of `@metamask`. + - The ID of the last commit in the branch is appended to the version, e.g. `1.2.3-preview-e2df9b4` instead of `1.2.3`. + +Now you can [use these preview builds in your project](#using-preview-builds). + +If you make more changes to a package, follow step 2 again, making sure to update the reference to the package in your project's `package.json` to use the newly published preview version. + +#### Publishing preview builds as an independent contributor + +If you've forked this repository, you can create preview builds based on a branch by following these steps: + +1. First, since an NPM scope is used to host preview build releases, you'll need access to one. If you do not, you can either [create a new organization](https://www.npmjs.com/org/create) or [convert your existing username into an organization](https://www.npmjs.com/org/upgrade). + +2. Once you've done this, open the `package.json` for each package that you want to publish and change the scope in the name from `@metamask` to `@`, replacing `NPM_ORG` with your NPM organization. + +3. Next, run the following command to create and publish the preview builds (again, replacing `NPM_ORG` as appropriate): + + ``` + yarn prepare-preview-builds "@" "$(git rev-parse --short HEAD)" && yarn build && yarn publish-previews + ``` + + You should be able to see the published version of each package in the output. Note two things: + + - The name is scoped to the NPM organization you entered instead of `@metamask`. + - The ID of the last commit in the branch is appended to the version, e.g. `1.2.3-preview-e2df9b4` instead of `1.2.3`. + +Now you can [use these preview builds in your project](#using-preview-builds). + +If you make more changes to a package, follow step 3 again, making sure to update the reference to the package in your project's `package.json` to use the newly published preview version. + +#### Using preview builds + +To use a preview build for a package within a project, you need to override the resolution logic for your package manager so that the "production" version of that package is replaced with the preview version. Here's how you do that: + +1. Open `package.json` in the project and locate the dependency entry for the core package for which you want to use a preview build. +2. Locate the section responsible for resolution overrides (or create it if it doesn't exist). If you're using Yarn, this is `resolutions`; if you're using NPM or any other package manager, this is `overrides`. +3. Add a line to this section that mirrors the dependency entry on the left-hand side and points to the preview version on the right-hand side: + + ``` + "@metamask/@": "npm:@/@" + ``` + + > **Example:** + > + > - If your project uses Yarn, `@metamask/controller-utils` is listed in dependencies at `^1.1.4`, and you want to use the preview version `1.2.3-preview-e2df9b4`, add the following to `resolutions`: + > + > ``` + > "@metamask/controller-utils@^1.1.4": "npm:@metamask-previews/controller-utils@1.2.3-preview-e2df9b4" + > ``` + +4. Run `yarn install`. diff --git a/docs/processes/testing.md b/docs/processes/testing.md new file mode 100644 index 00000000000..19ef0ed0699 --- /dev/null +++ b/docs/processes/testing.md @@ -0,0 +1,15 @@ +# Writing and running tests + +[Jest](https://jestjs.io/) is used to ensure that code is working as expected. Ideally, all packages should have 100% test coverage. + +Please follow the [MetaMask unit testing guidelines](https://github.com/MetaMask/contributor-docs/blob/main/docs/testing/unit-testing.md) when writing tests. + +If you need to customize the behavior of Jest for a package, see `jest.config.js` within that package. + +- Run `yarn workspace run test` to run all tests for a package. +- Run `yarn workspace run jest --no-coverage ` to run a test file within the context of a package. +- Run `yarn test` to run tests for all packages. + +> **Note** +> +> `workspaceName` in these commands is the `name` field within a package's `package.json`, e.g., `@metamask/address-book-controller`, not the directory where it is located, e.g., `packages/address-book-controller`. diff --git a/docs/processes/updating-changelogs.md b/docs/processes/updating-changelogs.md new file mode 100644 index 00000000000..4d01939d22d --- /dev/null +++ b/docs/processes/updating-changelogs.md @@ -0,0 +1,18 @@ +# Updating changelogs + +Each package in this repo has a file called `CHANGELOG.md` which is used to record consumer-facing changes that have been published over time. This file is useful for other engineers who are upgrading to new versions of packages so that they know how to use new features they are expecting, they know when bugs have been addressed, and they understand how to adapt to breaking changes (if any). All changelogs follow the ["Keep a Changelog"](https://keepachangelog.com/) specification (enforced by `@metamask/auto-changelog`). + +As you make changes to packages, make sure to update their changelogs in the same branch. + +We will offer more guidance here in the future, but in general: + +- Place new entries under the "Unreleased" section. +- Place changes into categories. Consult the ["Keep a Changelog"](https://keepachangelog.com/en/1.1.0/#how) specification for the list. +- Highlight breaking changes by prefixing them with `**BREAKING:**`. +- Omit non-consumer facing changes from the changelog. +- Do not simply reuse the commit message, but describe exact changes to the API or usable surface area of the project. +- Use a list nested under a changelog entry to enumerate more details about a change if need be. +- Include links to pull request(s) that introduced each change. (Most likely, this is the very same pull request in which you are updating the changelog.) +- Combine like changes from multiple pull requests into a single changelog entry if necessary. +- Split disparate changes from the same pull request into multiple entries if necessary. +- Omit reverted changes from the changelog. diff --git a/docs/real-time-balance-updates-flow.md b/packages/core-backend/docs/real-time-balance-updates-flow.md similarity index 100% rename from docs/real-time-balance-updates-flow.md rename to packages/core-backend/docs/real-time-balance-updates-flow.md diff --git a/scripts/create-package/README.md b/scripts/create-package/README.md index 1dca2866ad0..77ffdb44593 100644 --- a/scripts/create-package/README.md +++ b/scripts/create-package/README.md @@ -1,4 +1,4 @@ # `create-package` This directory contains our CLI for creating new monorepo packages. -For details, please see [the monorepo contributor documentation](../../docs/contributing.md#adding-new-packages). +For details, please see [the monorepo contributor documentation](../../docs/processes/adding-new-packages.md). diff --git a/scripts/generate-preview-build-message.ts b/scripts/generate-preview-build-message.ts index 9087a4ab3ca..ca00870aa0f 100644 --- a/scripts/generate-preview-build-message.ts +++ b/scripts/generate-preview-build-message.ts @@ -30,7 +30,7 @@ async function main(): Promise { } const previewBuildMessage = ` -Preview builds have been published. [See these instructions](https://github.com/MetaMask/core/blob/main/docs/contributing.md#using-packages-in-other-projects-during-developmenttesting) for more information about preview builds. +Preview builds have been published. [See these instructions](https://github.com/MetaMask/core/blob/main/docs/processes/testing-changes-in-other-projects.md#testing-changes-to-packages-with-preview-builds) for more information about preview builds.