-
Notifications
You must be signed in to change notification settings - Fork 5.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
test: automatically install
anvil
during yarn install
via `foundr…
…yup.ts` (#28393) I've ported Foundry's foundryup bash script to TypeScript. It downloads a pinned version of the `anvil` binary on `yarn install`. While you don't need to do anything, other than run `yarn` (or `yarn install`), you can customize the installation options by running `yarn foundryup <options>`. Try running `yarn foundryup --help` to see all that it can do. An explanation of how it works: The `yarn foundryup` command caches (to `.metamask/cache/*`) the downloaded binaries (defaults to only `anvil`, but it _can_ install all the others) and symlinks them from the cache into `node_modules/.bin/<binary name>`. This makes successive installs nearly instant. In CI the cache itself is cached (same process as for the `.yarn/cache` cache), so that CI doesn't have to redownload binaries on every workflow. The `foundryup` code is intended to be generic, and could eventually be a partial replacement for the `ganache` package for most users (for cli users only, not for programmatic use cases). For this reason, the script uses defaults that are not tailored to our needs; instead we use a new `package.json` property _`foundryup`_ to describe what defaults we do want, and the script uses those values. In addition to the original `foundryup` bash script features, this script supports checksumming the downloaded binaries; a feature requested by the MM security team. See the `foundryup` property in our `package.json` for more details. A feature that is _missing_ from this script, but is in the original `foundryup` bash script,is support for downloading the `man` pages. I don't really care about this feature and don't think anyone would use it. This script _should_ support the following platforms, but I've only tested Linux+AMD: Linux on ARM and AMD Mac on ARM and AMD Windows on AMD (likely works on arm-based Windows machines via OS's emulation) -- This also adds a new yarn command: `anvil`. You can use it just like you did with `yarn ganache`, i.e., `yarn anvil`; note: the defaults and CLI options are not going to be exactly the same as `ganache`. <!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until the template has been completely filled out, and PR status checks have passed at least once. ## **Description** [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/28393?quickstart=1) ## **Related issues** Fixes: ## **Manual testing steps** 1. Go to this page... 2. 3. ## **Screenshots/Recordings** ### **Before** ### **After** ## **Pre-merge author checklist** - [ ] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Extension Coding Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've completed the PR template to the best of my ability - [ ] I’ve included tests if applicable - [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. --> --------- Co-authored-by: seaona <[email protected]> Co-authored-by: seaona <[email protected]> Co-authored-by: Howard Braham <[email protected]>
- Loading branch information
1 parent
fc20a80
commit df3931e
Showing
17 changed files
with
1,528 additions
and
132 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -60,6 +60,7 @@ | |
"metamaskbot", | ||
"metamaskrc", | ||
"metametrics", | ||
"Minipass", | ||
"mocharc", | ||
"MULTICHAIN", | ||
"MULTIPROVIDER", | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,7 +9,8 @@ | |
"scripts": { | ||
"webpack": "tsx ./development/webpack/launch.ts", | ||
"webpack:clearcache": "./development/clear-webpack-cache.js", | ||
"postinstall": "yarn webpack:clearcache", | ||
"foundryup": "tsx ./test/helpers/foundry/foundryup.ts", | ||
"postinstall": "yarn webpack:clearcache && yarn foundryup", | ||
"env:e2e": "SEGMENT_HOST='https://api.segment.io' SEGMENT_WRITE_KEY='FAKE' yarn", | ||
"start": "yarn build:dev dev --apply-lavamoat=false --snow=false", | ||
"start:with-state": "node ./app/scripts/start-with-wallet-state.mjs", | ||
|
@@ -44,6 +45,7 @@ | |
"forwarder": "node ./development/static-server.js ./node_modules/@metamask/forwarder/dist/ --port 9010", | ||
"dapp-forwarder": "concurrently -k -n forwarder,dapp -p '[{time}][{name}]' 'yarn forwarder' 'yarn dapp'", | ||
"test:unit": "jest", | ||
"anvil": "node_modules/.bin/anvil", | ||
"test:unit:watch": "jest --watch", | ||
"test:unit:coverage": "jest --coverage", | ||
"test:unit:webpack": "tsx --test development/webpack/test/*.test.ts", | ||
|
@@ -533,6 +535,7 @@ | |
"@types/serve-handler": "^6.1.4", | ||
"@types/sinon": "^10.0.13", | ||
"@types/sprintf-js": "^1", | ||
"@types/unzipper": "^0.10.10", | ||
"@types/w3c-web-hid": "^1.0.3", | ||
"@types/watchify": "^3.11.1", | ||
"@types/webextension-polyfill": "^0.10.4", | ||
|
@@ -616,6 +619,7 @@ | |
"lockfile-lint": "^4.10.6", | ||
"loose-envify": "^1.4.0", | ||
"mini-css-extract-plugin": "^2.9.1", | ||
"minipass": "^7.1.2", | ||
"mocha": "^10.2.0", | ||
"mocha-junit-reporter": "^2.2.1", | ||
"mockttp": "^3.10.1", | ||
|
@@ -658,13 +662,15 @@ | |
"style-loader": "^0.21.0", | ||
"stylelint": "^13.6.1", | ||
"superstruct": "^1.0.3", | ||
"tar": "^7.4.3", | ||
"terser": "^5.7.0", | ||
"terser-webpack-plugin": "^5.3.10", | ||
"through2": "^4.0.2", | ||
"ts-node": "^10.9.2", | ||
"tsx": "^4.7.1", | ||
"tsx": "^4.19.2", | ||
"ttest": "^2.1.1", | ||
"typescript": "~5.4.5", | ||
"unzipper": "^0.12.3", | ||
"vinyl": "^2.2.1", | ||
"vinyl-buffer": "^1.0.1", | ||
"vinyl-source-stream": "^2.0.0", | ||
|
@@ -681,7 +687,7 @@ | |
"yargs-parser": "^21.1.1" | ||
}, | ||
"engines": { | ||
"node": ">= 20", | ||
"node": ">=20.12.0 <20.15.0 || >=20.17.0", | ||
"yarn": "^4.4.1" | ||
}, | ||
"lavamoat": { | ||
|
@@ -764,5 +770,23 @@ | |
"@lavamoat/allow-scripts>@lavamoat/preinstall-always-fail": false | ||
} | ||
}, | ||
"packageManager": "[email protected]" | ||
"packageManager": "[email protected]", | ||
"foundryup": { | ||
"binaries": [ | ||
"anvil" | ||
], | ||
"checksums": { | ||
"algorithm": "sha256", | ||
"binaries": { | ||
"anvil": { | ||
"darwin-amd64": "8404e555223fe884557d5e22de494baf8b5f0b82c6f87a4c790c5150e546c9d0", | ||
"darwin-arm64": "888500bc210752e71a355ed4d492ad6dcb4c0ef54d283c105a29a5ccc73d0dbd", | ||
"linux-amd64": "6104069b183fa0f3cdcb692681da9dbd203a3c1bceb435853bbf7abd991c649e", | ||
"linux-arm64": "d66ed8f848e829882ebb65d28aaac72aeab6a101655bb62147186040655928b5", | ||
"win32-amd64": "6c71d9a7be39ed32b53c89bdbc83aa748f41587517212ffe2a8b955c3e9c2e9b" | ||
} | ||
} | ||
}, | ||
"version": "v0.3.0" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
import { request as httpRequest, type IncomingMessage } from 'node:http'; | ||
import { request as httpsRequest } from 'node:https'; | ||
import { Stream } from 'node:stream'; | ||
import { pipeline } from 'node:stream/promises'; | ||
import { DownloadOptions } from './types'; | ||
|
||
class DownloadStream extends Stream.PassThrough { | ||
async response(): Promise<IncomingMessage> { | ||
return new Promise((resolve, reject) => { | ||
this.once('response', resolve); | ||
this.once('error', reject); | ||
}); | ||
} | ||
} | ||
|
||
/** | ||
* Starts a download from the given URL. | ||
* | ||
* @param url - The URL to download from | ||
* @param options - The download options | ||
* @param redirects - The number of redirects that have occurred | ||
* @returns A stream of the download | ||
*/ | ||
|
||
export function startDownload( | ||
url: URL, | ||
options: DownloadOptions = {}, | ||
redirects: number = 0, | ||
) { | ||
const MAX_REDIRECTS = options.maxRedirects ?? 5; | ||
const request = url.protocol === 'http:' ? httpRequest : httpsRequest; | ||
const stream = new DownloadStream(); | ||
request(url, options, async (response) => { | ||
stream.once('close', () => { | ||
response.destroy(); | ||
}); | ||
|
||
const { statusCode, statusMessage, headers } = response; | ||
// handle redirects | ||
if ( | ||
statusCode && | ||
statusCode >= 300 && | ||
statusCode < 400 && | ||
headers.location | ||
) { | ||
if (redirects >= MAX_REDIRECTS) { | ||
stream.emit('error', new Error('Too many redirects')); | ||
response.destroy(); | ||
} else { | ||
// note: we don't emit a response until we're done redirecting, because | ||
// handlers only expect it to be emitted once. | ||
await pipeline( | ||
startDownload(new URL(headers.location, url), options, redirects + 1) | ||
// emit the response event to the stream | ||
.once('response', stream.emit.bind(stream, 'response')), | ||
stream, | ||
).catch(stream.emit.bind(stream, 'error')); | ||
response.destroy(); | ||
} | ||
} | ||
|
||
// check for HTTP errors | ||
else if (!statusCode || statusCode < 200 || statusCode >= 300) { | ||
stream.emit( | ||
'error', | ||
new Error( | ||
`Request to ${url} failed. Status Code: ${statusCode} - ${statusMessage}`, | ||
), | ||
); | ||
response.destroy(); | ||
} else { | ||
// resolve with response stream | ||
stream.emit('response', response); | ||
|
||
response.once('error', stream.emit.bind(stream, 'error')); | ||
await pipeline(response, stream).catch(stream.emit.bind(stream, 'error')); | ||
} | ||
}) | ||
.once('error', stream.emit.bind(stream, 'error')) | ||
.end(); | ||
return stream; | ||
} |
Oops, something went wrong.