Skip to content

Commit 7d5f2c8

Browse files
authored
Add preview builds (#187)
1 parent b4d6fff commit 7d5f2c8

File tree

5 files changed

+194
-0
lines changed

5 files changed

+194
-0
lines changed
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
name: Publish a preview build
2+
3+
on:
4+
issue_comment:
5+
types: created
6+
7+
jobs:
8+
is-fork-pull-request:
9+
name: Determine whether this issue comment was on a pull request from a fork
10+
if: ${{ github.event.issue.pull_request && startsWith(github.event.comment.body, '@metamaskbot publish-preview') }}
11+
runs-on: ubuntu-latest
12+
permissions:
13+
contents: read
14+
pull-requests: read
15+
outputs:
16+
IS_FORK: ${{ steps.is-fork.outputs.IS_FORK }}
17+
steps:
18+
- uses: actions/checkout@v4
19+
- name: Determine whether this PR is from a fork
20+
id: is-fork
21+
run: echo "IS_FORK=$(gh pr view --json isCrossRepository --jq '.isCrossRepository' "${PR_NUMBER}" )" >> "$GITHUB_OUTPUT"
22+
env:
23+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
24+
PR_NUMBER: ${{ github.event.issue.number }}
25+
26+
react-to-comment:
27+
name: React to the comment
28+
needs: is-fork-pull-request
29+
# This ensures we don't publish on forks. We can't trust forks with this token.
30+
if: ${{ needs.is-fork-pull-request.outputs.IS_FORK == 'false' }}
31+
runs-on: ubuntu-latest
32+
permissions:
33+
contents: read
34+
pull-requests: write
35+
steps:
36+
- uses: actions/checkout@v4
37+
- name: React to the comment
38+
run: |
39+
gh api \
40+
--method POST \
41+
-H "Accept: application/vnd.github+json" \
42+
-H "X-GitHub-Api-Version: 2022-11-28" \
43+
"/repos/${REPO}/issues/comments/${COMMENT_ID}/reactions" \
44+
-f content='+1'
45+
env:
46+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
47+
COMMENT_ID: ${{ github.event.comment.id }}
48+
REPO: ${{ github.repository }}
49+
50+
publish-preview:
51+
name: Publish build preview
52+
needs: react-to-comment
53+
runs-on: ubuntu-latest
54+
permissions:
55+
contents: read
56+
pull-requests: write
57+
steps:
58+
- uses: actions/checkout@v4
59+
- name: Check out pull request
60+
run: gh pr checkout "${PR_NUMBER}"
61+
env:
62+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
63+
PR_NUMBER: ${{ github.event.issue.number }}
64+
- name: Checkout and setup environment
65+
uses: MetaMask/action-checkout-and-setup@v1
66+
with:
67+
is-high-risk-environment: true
68+
- name: Get commit SHA
69+
id: commit-sha
70+
run: echo "COMMIT_SHA=$(git rev-parse --short HEAD)" >> "$GITHUB_OUTPUT"
71+
- run: ./scripts/prepare-preview-builds.sh @metamask-previews ${{ steps.commit-sha.outputs.COMMIT_SHA }}
72+
- run: yarn build
73+
- name: Publish preview build
74+
run: yarn npm publish --tag preview
75+
env:
76+
YARN_NPM_AUTH_TOKEN: ${{ secrets.PUBLISH_PREVIEW_NPM_TOKEN }}
77+
- name: Post build preview in comment
78+
run: ./scripts/generate-preview-build-message.sh | gh pr comment "${PR_NUMBER}" --body-file -
79+
env:
80+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
81+
COMMIT_SHA: ${{ steps.commit-sha.outputs.COMMIT_SHA }}
82+
PR_NUMBER: ${{ github.event.issue.number }}

README.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,3 +76,42 @@ The project follows the same release process as the other libraries in the MetaM
7676
- 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.
7777
- Approve the `publish-npm` job (or ask somebody on the npm publishers team to approve it for you).
7878
- Once the `publish-npm` job has finished, check npm to verify that it has been published.
79+
80+
### Testing changes in other projects using preview builds
81+
82+
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.
83+
84+
#### Creating a preview build
85+
86+
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.
87+
2. After a few minutes, the action should complete and you will see a new comment. Note two things:
88+
- The name is scoped to `@metamask-previews` instead of `@metamask`.
89+
- 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`.
90+
91+
#### Using a preview build
92+
93+
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:
94+
95+
1. Open `package.json` in the project and locate the entry for this package in `dependencies`.
96+
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`.
97+
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:
98+
- For Yarn Modern, you will add something like this to `resolutions`:
99+
```
100+
"@metamask/create-release-branch@^1.2.3": "npm:@metamask-previews/[email protected]"
101+
```
102+
- For Yarn Classic, you will add something like this to `resolutions`:
103+
```
104+
"@metamask/create-release-branch": "npm:@metamask-previews/[email protected]"
105+
```
106+
- For NPM, you will add something like this to `overrides`:
107+
```
108+
"@metamask/create-release-branch": "npm:@metamask-previews/[email protected]"
109+
```
110+
4. Run `yarn install`.
111+
112+
#### Updating a preview build
113+
114+
If you make more changes to your pull request and want to create a new preview build:
115+
116+
1. Post another `@metamaskbot` comment on the pull request and wait for the response.
117+
2. Update the version of the preview build in your project's `package.json`. Make sure to re-run `yarn install`!
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#!/usr/bin/env bash
2+
3+
main() {
4+
local package_name
5+
local package_version
6+
7+
package_name="$(jq -r '.name' < package.json)"
8+
package_version="$(jq -r '.version' < package.json)"
9+
10+
local preview_build_message="\
11+
A preview build for this branch has been published.
12+
13+
You can configure your project to use the preview build with this identifier:
14+
15+
npm:${package_name}@${package_version}
16+
17+
[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.\
18+
"
19+
20+
echo "$preview_build_message"
21+
}
22+
23+
main "$@"

scripts/prepare-preview-builds.jq

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# The name is overwritten, causing the package to get published under a
2+
# different NPM scope than non-preview builds.
3+
.name |= sub("@metamask/"; "\($npm_scope)/") |
4+
5+
# The prerelease version is overwritten, preserving the non-prerelease portion
6+
# of the version. Technically we'd want to bump the non-prerelease portion as
7+
# well if we wanted this to be SemVer-compliant, but it was simpler not to.
8+
# This is just for testing, it doesn't need to strictly follow SemVer.
9+
.version |= split("-")[0] + "-preview-\($short_commit_id)"

scripts/prepare-preview-builds.sh

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#!/usr/bin/env bash
2+
3+
# This script prepares a package to be published as a preview build to NPM.
4+
5+
set -euo pipefail
6+
7+
prepare-preview-manifest() {
8+
local manifest_file="$1"
9+
local npm_scope="$2"
10+
local short_commit_id="$3"
11+
12+
# jq does not support in-place modification of files, so a temporary file is
13+
# used to store the result of the operation. The original file is then
14+
# overwritten with the temporary file.
15+
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
16+
mv temp.json "$manifest_file"
17+
}
18+
19+
main() {
20+
if [[ $# -lt 2 ]]; then
21+
echo "USAGE: $0 NPM_SCOPE SHORT_GIT_COMMIT_HASH"
22+
exit 1
23+
fi
24+
25+
# We don't want to assume that preview builds will be published alongside
26+
# "production" versions. There are security- and aesthetic-based advantages to
27+
# keeping them separate.
28+
local npm_scope="$1"
29+
30+
# We use the short commit ID as the prerelease version. This ensures each
31+
# preview build is unique and can be linked to a specific commit.
32+
local short_commit_id="$2"
33+
34+
echo "Preparing manifest..."
35+
prepare-preview-manifest "package.json" "$npm_scope" "$short_commit_id"
36+
37+
echo "Installing dependencies..."
38+
yarn install --no-immutable
39+
}
40+
41+
main "$@"

0 commit comments

Comments
 (0)