Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: preview builds #15

Merged
merged 7 commits into from
Sep 3, 2024
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
66 changes: 66 additions & 0 deletions .github/workflows/publish-preview.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
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
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:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_NUMBER: ${{ github.event.issue.number }}

publish-preview:
name: Publish build preview
needs: is-fork-pull-request
permissions:
pull-requests: write
# 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
steps:
- uses: actions/checkout@v4
- name: Check out pull request
run: gh pr checkout "${PR_NUMBER}"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_NUMBER: ${{ github.event.issue.number }}
- name: Install Node
uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
- name: Install Yarn
run: corepack enable
- name: Restore Yarn cache
uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: yarn
- run: yarn --immutable
- name: Get commit SHA
id: commit-sha
run: echo "COMMIT_SHA=$(git rev-parse --short HEAD)" >> "$GITHUB_OUTPUT"
- run: yarn prepare:preview @metamask-previews ${{ steps.commit-sha.outputs.COMMIT_SHA }}
- run: yarn build
- name: Publish preview build
run: yarn publish:preview
env:
YARN_NPM_AUTH_TOKEN: ${{ secrets.PUBLISH_PREVIEW_NPM_TOKEN }}
- name: Generate preview build message
run: yarn ts-node scripts/generate-preview-build-message.ts
- name: Post build preview in comment
run: gh pr comment "${PR_NUMBER}" --body-file preview-build-message.txt
env:
COMMIT_SHA: ${{ steps.commit-sha.outputs.COMMIT_SHA }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_NUMBER: ${{ github.event.issue.number }}
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@
"lint:fix": "yarn lint:eslint --fix && yarn lint:misc --write && yarn constraints --fix && yarn lint:dependencies:fix",
"lint:misc": "prettier '**/*.json' '**/*.md' '!**/CHANGELOG.old.md' '**/*.yml' '!.yarnrc.yml' '!merged-packages/**' --ignore-path .gitignore",
"prepack": "./scripts/prepack.sh",
"prepare:preview": "./scripts/prepare-preview-builds.sh",
"prepare:preview:local": "yarn prepare:preview @metamask-previews $(git rev-parse --short HEAD)",
"publish:preview": "yarn workspaces foreach --all --no-private --parallel --verbose run publish:preview",
"readme:update": "ts-node scripts/update-readme-content.ts",
"setup": "yarn install",
"test": "yarn test:packages",
Expand Down
1 change: 1 addition & 0 deletions packages/keyring-api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"changelog:update": "../../scripts/update-changelog.sh @metamask/keyring-api",
"changelog:validate": "../../scripts/validate-changelog.sh @metamask/keyring-api",
"prepack": "./scripts/prepack.sh",
"publish:preview": "yarn npm publish --tag preview",
"test": "yarn test:source && yarn test:types",
"test:clean": "jest --clearCache",
"test:source": "jest && jest-it-up",
Expand Down
1 change: 1 addition & 0 deletions packages/keyring-eth-hd/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"build:force": "",
"changelog:update": "../../scripts/update-changelog.sh @metamask/eth-hd-keyring",
"changelog:validate": "../../scripts/validate-changelog.sh @metamask/eth-hd-keyring",
"publish:preview": "yarn npm publish --tag preview",
"test": "jest",
"test:clean": "jest --clearCache",
"test:verbose": "jest --verbose"
Expand Down
1 change: 1 addition & 0 deletions packages/keyring-eth-ledger-bridge/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"changelog:update": "../../scripts/update-changelog.sh @metamask/eth-ledger-bridge-keyring",
"changelog:validate": "../../scripts/validate-changelog.sh @metamask/eth-ledger-bridge-keyring",
"prepack": "./scripts/prepack.sh",
"publish:preview": "yarn npm publish --tag preview",
"test": "jest && jest-it-up",
"test:clean": "jest --clearCache",
"test:verbose": "jest --verbose",
Expand Down
1 change: 1 addition & 0 deletions packages/keyring-eth-simple/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"changelog:update": "../../scripts/update-changelog.sh @metamask/eth-simple-keyring",
"changelog:validate": "../../scripts/validate-changelog.sh @metamask/eth-simple-keyring",
"prepack": "./scripts/prepack.sh",
"publish:preview": "yarn npm publish --tag preview",
"sample": "ts-node src/sample.ts",
"test": "jest",
"test:clean": "jest --clearCache",
Expand Down
1 change: 1 addition & 0 deletions packages/keyring-eth-trezor/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"changelog:update": "../../scripts/update-changelog.sh @metamask/eth-trezor-keyring",
"changelog:validate": "../../scripts/validate-changelog.sh @metamask/eth-trezor-keyring",
"prepack": "./scripts/prepack.sh",
"publish:preview": "yarn npm publish --tag preview",
"test": "jest && jest-it-up",
"test:clean": "jest --clearCache",
"test:verbose": "jest --verbose",
Expand Down
3 changes: 2 additions & 1 deletion packages/keyring-snap/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,14 @@
"dist/"
],
"scripts": {
"build": "yarn workspace @metamask/keyring-api build:force && tsc --build tsconfig.build.json",
"build": "yarn workspace $(jq -r '.name' ../keyring-api/package.json) build:force && tsc --build tsconfig.build.json",
"build:clean": "rimraf dist && yarn build",
"build:docs": "typedoc",
"build:force": "tsc --build tsconfig.build.json --force",
"changelog:update": "../../scripts/update-changelog.sh @metamask/eth-snap-keyring",
"changelog:validate": "../../scripts/validate-changelog.sh @metamask/eth-snap-keyring",
"prepack": "./scripts/prepack.sh",
"publish:preview": "yarn npm publish --tag preview",
"test": "jest && jest-it-up",
"test:clean": "jest --clearCache",
"test:verbose": "jest --verbose",
Expand Down
54 changes: 54 additions & 0 deletions scripts/generate-preview-build-message.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#!yarn ts-node

import execa from 'execa';
import fs from 'fs';
import path from 'path';

/**
* Write a preview build message to the path "preview-build-message.txt".
*/
async function main() {
const packageMap: Record<string, string> = {};

const { stdout } = await execa('yarn', [
'workspaces',
'list',
'--no-private',
'--json',
]);
const packages = stdout.split('\n').map((line) => JSON.parse(line));
const packageManifestPaths = packages.map(({ location }) =>
path.join(location, 'package.json'),
);
for (const manifestPath of packageManifestPaths) {
const rawManifest = await fs.promises.readFile(manifestPath, {
encoding: 'utf8',
});
const { name, version } = JSON.parse(rawManifest);

packageMap[name] = version;
}

const previewBuildMessage = `
Preview builds have been published. [See these instructions (from the \`core\` monorepo)](https://github.com/MetaMask/core/blob/main/docs/contributing.md#using-preview-builds) for more information about preview builds.

<details>

<summary>Expand for full list of packages and versions.</summary>


\`\`\`
${JSON.stringify(packageMap, null, 2)}
\`\`\`

</details>
`;

const messagePath = path.resolve(__dirname, '../preview-build-message.txt');
await fs.promises.writeFile(messagePath, previewBuildMessage);
}

main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
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-\($hash)"
39 changes: 39 additions & 0 deletions scripts/prepare-preview-builds.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#!/usr/bin/env bash

set -euo pipefail

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

if [[ $# -eq 0 ]]; then
echo "Missing 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.
npm_scope="$1"

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

prepare-preview-manifest() {
local manifest_file="$1"

# 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 hash "$shorthash" --from-file scripts/prepare-preview-builds.jq "$manifest_file" > temp.json
mv temp.json "$manifest_file"
}

echo "Preparing manifests..."
while IFS=$'\t' read -r location name; do
echo "- $name"
prepare-preview-manifest "$location/package.json"
done < <(yarn workspaces list --no-private --json | jq --slurp --raw-output 'map(select(.location != ".")) | map([.location, .name]) | map(@tsv) | .[]')

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