Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 82 additions & 0 deletions .github/workflows/publish-preview.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
name: Publish a preview build

on:
issue_comment:
types: created

jobs:
is-fork-pull-request:
name: Determine whether this issue comment was on a pull request from a fork
if: ${{ github.event.issue.pull_request && startsWith(github.event.comment.body, '@metamaskbot publish-preview') }}
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: read
outputs:
IS_FORK: ${{ steps.is-fork.outputs.IS_FORK }}
steps:
- uses: actions/checkout@v4
- name: Determine whether this PR is from a fork
id: is-fork
run: echo "IS_FORK=$(gh pr view --json isCrossRepository --jq '.isCrossRepository' "${PR_NUMBER}" )" >> "$GITHUB_OUTPUT"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_NUMBER: ${{ github.event.issue.number }}

react-to-comment:
name: React to the comment
needs: is-fork-pull-request
# This ensures we don't publish on forks. We can't trust forks with this token.
if: ${{ needs.is-fork-pull-request.outputs.IS_FORK == 'false' }}
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
steps:
- uses: actions/checkout@v4
- name: React to the comment
run: |
gh api \
--method POST \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
"/repos/${REPO}/issues/comments/${COMMENT_ID}/reactions" \
-f content='+1'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
COMMENT_ID: ${{ github.event.comment.id }}
REPO: ${{ github.repository }}

publish-preview:
name: Publish build preview
needs: react-to-comment
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
steps:
- uses: actions/checkout@v4
- name: Check out pull request
run: gh pr checkout "${PR_NUMBER}"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_NUMBER: ${{ github.event.issue.number }}
- name: Checkout and setup environment
uses: MetaMask/action-checkout-and-setup@v1
with:
is-high-risk-environment: true
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Incorrect branch checkout defeats preview builds.

The MetaMask/action-checkout-and-setup@v1 action likely performs a repository checkout that overwrites the PR branch checked out in the previous step (line 60). This would cause the workflow to build and publish from the default branch instead of the PR branch, defeating the purpose of preview builds. The action should either be removed or configured to skip the checkout step if that's supported.

Fix in Cursor Fix in Web

- name: Get commit SHA
id: commit-sha
run: echo "COMMIT_SHA=$(git rev-parse --short HEAD)" >> "$GITHUB_OUTPUT"
- run: ./scripts/prepare-preview-builds.sh @metamask-previews ${{ steps.commit-sha.outputs.COMMIT_SHA }}
- run: yarn build
- name: Publish preview build
run: yarn npm publish --tag preview
env:
YARN_NPM_AUTH_TOKEN: ${{ secrets.PUBLISH_PREVIEW_NPM_TOKEN }}
- name: Post build preview in comment
run: ./scripts/generate-preview-build-message.sh | gh pr comment "${PR_NUMBER}" --body-file -
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
COMMIT_SHA: ${{ steps.commit-sha.outputs.COMMIT_SHA }}
PR_NUMBER: ${{ github.event.issue.number }}
39 changes: 39 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,42 @@ The project follows the same release process as the other libraries in the MetaM
- Wait for the `publish-release` GitHub Action workflow to finish. This should trigger a second job (`publish-npm`), which will wait for a run approval by the [`npm publishers`](https://github.com/orgs/MetaMask/teams/npm-publishers) team.
- Approve the `publish-npm` job (or ask somebody on the npm publishers team to approve it for you).
- Once the `publish-npm` job has finished, check npm to verify that it has been published.

### Testing changes in other projects using preview builds

If you are working on a pull request and want to test changes in another project before you publish them, you can create a _preview build_ and then configure your project to use it.

#### Creating a preview build

1. Within your pull request, post a comment with the text `@metamaskbot publish-preview`. This starts the `publish-preview` GitHub action, which will create a preview build and publish it to NPM.
2. After a few minutes, the action should complete and you will see a new comment. Note two things:
- 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`.

#### Using a preview build

To use a preview build 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 entry for this package in `dependencies`.
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. Note the exact format of the left-hand side will differ based on which version of Yarn or NPM you are using. For example:
- For Yarn Modern, you will add something like this to `resolutions`:
```
"@metamask/create-release-branch@^1.2.3": "npm:@metamask-previews/[email protected]"
```
- For Yarn Classic, you will add something like this to `resolutions`:
```
"@metamask/create-release-branch": "npm:@metamask-previews/[email protected]"
```
- For NPM, you will add something like this to `overrides`:
```
"@metamask/create-release-branch": "npm:@metamask-previews/[email protected]"
```
4. Run `yarn install`.

#### Updating a preview build

If you make more changes to your pull request and want to create a new preview build:

1. Post another `@metamaskbot` comment on the pull request and wait for the response.
2. Update the version of the preview build in your project's `package.json`. Make sure to re-run `yarn install`!
23 changes: 23 additions & 0 deletions scripts/generate-preview-build-message.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/usr/bin/env bash

main() {
local package_name
local package_version

package_name="$(jq -r '.name' < package.json)"
package_version="$(jq -r '.version' < package.json)"

local preview_build_message="\
A preview build for this branch has been published.

You can configure your project to use the preview build with this identifier:

npm:${package_name}@${package_version}

[See these instructions](https://github.com/MetaMask/create-release-branch/blob/main/README.md#testing-changes-in-other-projects-using-preview-builds) for more information about preview builds.\
"

echo "$preview_build_message"
}

main "$@"
9 changes: 9 additions & 0 deletions scripts/prepare-preview-builds.jq
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# The name is overwritten, causing the package to get published under a
# different NPM scope than non-preview builds.
.name |= sub("@metamask/"; "\($npm_scope)/") |

# The prerelease version is overwritten, preserving the non-prerelease portion
# of the version. Technically we'd want to bump the non-prerelease portion as
# well if we wanted this to be SemVer-compliant, but it was simpler not to.
# This is just for testing, it doesn't need to strictly follow SemVer.
.version |= split("-")[0] + "-preview-\($short_commit_id)"
41 changes: 41 additions & 0 deletions scripts/prepare-preview-builds.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#!/usr/bin/env bash

# This script prepares a package to be published as a preview build to NPM.

set -euo pipefail

prepare-preview-manifest() {
local manifest_file="$1"
local npm_scope="$2"
local short_commit_id="$3"

# jq does not support in-place modification of files, so a temporary file is
# used to store the result of the operation. The original file is then
# overwritten with the temporary file.
jq --raw-output --arg npm_scope "$npm_scope" --arg short_commit_id "$short_commit_id" --from-file scripts/prepare-preview-builds.jq "$manifest_file" > temp.json
mv temp.json "$manifest_file"
}

main() {
if [[ $# -lt 2 ]]; then
echo "USAGE: $0 NPM_SCOPE SHORT_GIT_COMMIT_HASH"
exit 1
fi

# We don't want to assume that preview builds will be published alongside
# "production" versions. There are security- and aesthetic-based advantages to
# keeping them separate.
local npm_scope="$1"

# We use the short commit ID as the prerelease version. This ensures each
# preview build is unique and can be linked to a specific commit.
local short_commit_id="$2"

echo "Preparing manifest..."
prepare-preview-manifest "package.json" "$npm_scope" "$short_commit_id"

echo "Installing dependencies..."
yarn install --no-immutable
}

main "$@"
Loading