diff --git a/.circleci/config.yml b/.circleci/config.yml index 9318c26de..183808490 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -246,9 +246,25 @@ jobs: - checkout - attach_workspace: at: . - - run: - name: build:dist - command: yarn dist + - when: + condition: + not: + matches: + pattern: /^master$/ + value: << pipeline.git.branch >> + steps: + - run: + name: build:dist + command: yarn build dist + - when: + condition: + matches: + pattern: /^master$/ + value: << pipeline.git.branch >> + steps: + - run: + name: build:prod + command: yarn build prod - run: name: build:debug command: find dist/ -type f -exec md5sum {} \; | sort -k 2 @@ -266,7 +282,7 @@ jobs: at: . - run: name: build:dist - command: yarn build --build-type beta prod + command: yarn build --build-type beta dist - run: name: build:debug command: find dist/ -type f -exec md5sum {} \; | sort -k 2 @@ -290,7 +306,7 @@ jobs: at: . - run: name: build:dist - command: yarn build --build-type flask prod + command: yarn build --build-type flask dist - run: name: build:debug command: find dist/ -type f -exec md5sum {} \; | sort -k 2 diff --git a/.gitignore b/.gitignore index cca1fefab..c86fb82db 100644 --- a/.gitignore +++ b/.gitignore @@ -47,7 +47,9 @@ notes.txt .nyc_output +# MetaMask configuration .metamaskrc +.metamaskprodrc # TypeScript tsout/ diff --git a/.metamaskrc.dist b/.metamaskrc.dist index 7a7ab0da7..353e63118 100644 --- a/.metamaskrc.dist +++ b/.metamaskrc.dist @@ -5,6 +5,8 @@ SEGMENT_WRITE_KEY= ONBOARDING_V2= SWAPS_USE_DEV_APIS= COLLECTIBLES_V1= +PUBNUB_PUB_KEY= +PUBNUB_SUB_KEY= ; Set this to '1' to enable support for Sign-In with Ethereum [EIP-4361](https://eips.ethereum.org/EIPS/eip-4361) SIWE_V1= diff --git a/development/build/config.js b/development/build/config.js new file mode 100644 index 000000000..a907b64f5 --- /dev/null +++ b/development/build/config.js @@ -0,0 +1,101 @@ +const path = require('path'); +const { readFile } = require('fs/promises'); +const ini = require('ini'); +const { BuildType } = require('../lib/build-type'); + +/** + * Get configuration for non-production builds. + * + * @returns {object} The production configuration. + */ +async function getConfig() { + const configPath = path.resolve(__dirname, '..', '..', '.metamaskrc'); + let configContents = ''; + try { + configContents = await readFile(configPath, { + encoding: 'utf8', + }); + } catch (error) { + if (error.code !== 'ENOENT') { + throw error; + } + } + return { + COLLECTIBLES_V1: process.env.COLLECTIBLES_V1, + INFURA_PROJECT_ID: process.env.INFURA_PROJECT_ID, + ONBOARDING_V2: process.env.ONBOARDING_V2, + PHISHING_WARNING_PAGE_URL: process.env.PHISHING_WARNING_PAGE_URL, + PUBNUB_PUB_KEY: process.env.PUBNUB_PUB_KEY, + PUBNUB_SUB_KEY: process.env.PUBNUB_SUB_KEY, + SEGMENT_HOST: process.env.SEGMENT_HOST, + SEGMENT_WRITE_KEY: process.env.SEGMENT_WRITE_KEY, + SENTRY_DSN_DEV: + process.env.SENTRY_DSN_DEV ?? + 'https://f59f3dd640d2429d9d0e2445a87ea8e1@sentry.io/273496', + SIWE_V1: process.env.SIWE_V1, + SWAPS_USE_DEV_APIS: process.env.SWAPS_USE_DEV_APIS, + ...ini.parse(configContents), + }; +} + +/** + * Get configuration for production builds and perform validation. + * + * This function validates that all required variables are present, and that + * the production configuration file doesn't include any extraneous entries. + * + * @param {BuildType} buildType - The current build type (e.g. "main", "flask", + * etc.). + * @returns {object} The production configuration. + */ +async function getProductionConfig(buildType) { + const prodConfigPath = path.resolve(__dirname, '..', '..', '.metamaskprodrc'); + let prodConfigContents = ''; + try { + prodConfigContents = await readFile(prodConfigPath, { + encoding: 'utf8', + }); + } catch (error) { + if (error.code !== 'ENOENT') { + throw error; + } + } + const prodConfig = { + INFURA_BETA_PROJECT_ID: process.env.INFURA_BETA_PROJECT_ID, + INFURA_FLASK_PROJECT_ID: process.env.INFURA_FLASK_PROJECT_ID, + INFURA_PROD_PROJECT_ID: process.env.INFURA_PROD_PROJECT_ID, + PUBNUB_PUB_KEY: process.env.PUBNUB_PUB_KEY, + PUBNUB_SUB_KEY: process.env.PUBNUB_SUB_KEY, + SEGMENT_BETA_WRITE_KEY: process.env.SEGMENT_BETA_WRITE_KEY, + SEGMENT_FLASK_WRITE_KEY: process.env.SEGMENT_FLASK_WRITE_KEY, + SEGMENT_PROD_WRITE_KEY: process.env.SEGMENT_PROD_WRITE_KEY, + SENTRY_DSN: process.env.SENTRY_DSN, + ...ini.parse(prodConfigContents), + }; + + const requiredEnvironmentVariables = { + all: ['PUBNUB_PUB_KEY', 'PUBNUB_SUB_KEY', 'SENTRY_DSN'], + [BuildType.beta]: ['INFURA_BETA_PROJECT_ID', 'SEGMENT_BETA_WRITE_KEY'], + [BuildType.flask]: ['INFURA_FLASK_PROJECT_ID', 'SEGMENT_FLASK_WRITE_KEY'], + [BuildType.main]: ['INFURA_PROD_PROJECT_ID', 'SEGMENT_PROD_WRITE_KEY'], + }; + + for (const required of [ + ...requiredEnvironmentVariables.all, + ...requiredEnvironmentVariables[buildType], + ]) { + if (!prodConfig[required]) { + throw new Error(`Missing '${required}' environment variable`); + } + } + + const allValid = Object.values(requiredEnvironmentVariables).flat(); + for (const environmentVariable of Object.keys(prodConfig)) { + if (!allValid.includes(environmentVariable)) { + throw new Error(`Invalid environment variable: '${environmentVariable}'`); + } + } + return prodConfig; +} + +module.exports = { getConfig, getProductionConfig }; diff --git a/development/build/constants.js b/development/build/constants.js index 722fa1451..c91ce0a93 100644 --- a/development/build/constants.js +++ b/development/build/constants.js @@ -1,27 +1,51 @@ +/** + * The build target. This descrbes the overall purpose of the build. + * + * These constants also act as the high-level tasks for the build system (i.e. + * the usual tasks invoked directly via the CLI rather than internally). + */ const BUILD_TARGETS = { - DEVELOPMENT: 'dev', - PRODUCTION: 'prod', - E2E_TEST: 'test', - E2E_TEST_DEV: 'testDev', + DEV: 'dev', + DIST: 'dist', + PROD: 'prod', + TEST: 'test', + TEST_DEV: 'testDev', +}; + +/** + * The build environment. This describes the environment this build was produced in. + */ +const ENVIRONMENT = { + DEVELOPMENT: 'development', + PRODUCTION: 'production', + OTHER: 'other', + PULL_REQUEST: 'pull-request', + RELEASE_CANDIDATE: 'release-candidate', + STAGING: 'staging', + TESTING: 'testing', }; const TASKS = { + ...BUILD_TARGETS, CLEAN: 'clean', - DEV: 'dev', LINT_SCSS: 'lint-scss', MANIFEST_DEV: 'manifest:dev', MANIFEST_PROD: 'manifest:prod', MANIFEST_TEST: 'manifest:test', MANIFEST_TEST_DEV: 'manifest:testDev', - PROD: 'prod', RELOAD: 'reload', - SCRIPTS_PROD: 'scripts:prod', SCRIPTS_CORE_DEV_STANDARD_ENTRY_POINTS: 'scripts:core:dev:standardEntryPoints', SCRIPTS_CORE_DEV_CONTENTSCRIPT: 'scripts:core:dev:contentscript', SCRIPTS_CORE_DEV_DISABLE_CONSOLE: 'scripts:core:dev:disable-console', SCRIPTS_CORE_DEV_SENTRY: 'scripts:core:dev:sentry', SCRIPTS_CORE_DEV_PHISHING_DETECT: 'scripts:core:dev:phishing-detect', + SCRIPTS_CORE_DIST_STANDARD_ENTRY_POINTS: + 'scripts:core:dist:standardEntryPoints', + SCRIPTS_CORE_DIST_CONTENTSCRIPT: 'scripts:core:dist:contentscript', + SCRIPTS_CORE_DIST_DISABLE_CONSOLE: 'scripts:core:dist:disable-console', + SCRIPTS_CORE_DIST_SENTRY: 'scripts:core:dist:sentry', + SCRIPTS_CORE_DIST_PHISHING_DETECT: 'scripts:core:dist:phishing-detect', SCRIPTS_CORE_PROD_STANDARD_ENTRY_POINTS: 'scripts:core:prod:standardEntryPoints', SCRIPTS_CORE_PROD_CONTENTSCRIPT: 'scripts:core:prod:contentscript', @@ -42,14 +66,13 @@ const TASKS = { SCRIPTS_CORE_TEST_DISABLE_CONSOLE: 'scripts:core:test:disable-console', SCRIPTS_CORE_TEST_SENTRY: 'scripts:core:test:sentry', SCRIPTS_CORE_TEST_PHISHING_DETECT: 'scripts:core:test:phishing-detect', + SCRIPTS_DIST: 'scripts:dist', STATIC_DEV: 'static:dev', STATIC_PROD: 'static:prod', STYLES: 'styles', STYLES_DEV: 'styles:dev', STYLES_PROD: 'styles:prod', - TEST: 'test', - TEST_DEV: 'testDev', ZIP: 'zip', }; -module.exports = { BUILD_TARGETS, TASKS }; +module.exports = { BUILD_TARGETS, ENVIRONMENT, TASKS }; diff --git a/development/build/index.js b/development/build/index.js index 06cd53f41..308495017 100755 --- a/development/build/index.js +++ b/development/build/index.js @@ -10,7 +10,7 @@ const { hideBin } = require('yargs/helpers'); const { sync: globby } = require('globby'); const { getVersion } = require('../lib/get-version'); const { BuildType } = require('../lib/build-type'); -const { TASKS } = require('./constants'); +const { TASKS, ENVIRONMENT } = require('./constants'); const { createTask, composeSeries, @@ -22,7 +22,9 @@ const createScriptTasks = require('./scripts'); const createStyleTasks = require('./styles'); const createStaticAssetTasks = require('./static'); const createEtcTasks = require('./etc'); -const { getBrowserVersionMap } = require('./utils'); +const { getBrowserVersionMap, getEnvironment } = require('./utils'); +const { getConfig, getProductionConfig } = require('./config'); +const { BUILD_TARGETS } = require('./constants'); // Packages required dynamically via browserify configuration in dependencies // Required for LavaMoat policy generation @@ -50,9 +52,12 @@ require('eslint-plugin-react'); require('eslint-plugin-react-hooks'); require('eslint-plugin-jest'); -defineAndRunBuildTasks(); +defineAndRunBuildTasks().catch((error) => { + console.error(error.stack || error); + process.exitCode = 1; +}); -function defineAndRunBuildTasks() { +async function defineAndRunBuildTasks() { const { applyLavaMoat, buildType, @@ -63,7 +68,7 @@ function defineAndRunBuildTasks() { shouldLintFenceFiles, skipStats, version, - } = parseArgv(); + } = await parseArgv(); const browserPlatforms = ['firefox', 'chrome', 'brave', 'opera']; @@ -135,6 +140,17 @@ function defineAndRunBuildTasks() { ), ); + // build production-like distributable build + createTask( + TASKS.DIST, + composeSeries( + clean, + styleTasks.prod, + composeParallel(scriptTasks.dist, staticTasks.prod, manifestTasks.prod), + zip, + ), + ); + // build for prod release createTask( TASKS.PROD, @@ -147,7 +163,7 @@ function defineAndRunBuildTasks() { ); // build just production scripts, for LavaMoat policy generation purposes - createTask(TASKS.SCRIPTS_PROD, scriptTasks.prod); + createTask(TASKS.SCRIPTS_DIST, scriptTasks.dist); // build for CI testing createTask( @@ -164,20 +180,22 @@ function defineAndRunBuildTasks() { createTask(TASKS.styles, styleTasks.prod); // Finally, start the build process by running the entry task. - runTask(entryTask, { skipStats }); + await runTask(entryTask, { skipStats }); } -function parseArgv() { +async function parseArgv() { const { argv } = yargs(hideBin(process.argv)) .usage('$0 [options]', 'Build the MetaMask extension.', (_yargs) => _yargs .positional('task', { description: `The task to run. There are a number of main tasks, each of which calls other tasks internally. The main tasks are: -prod: Create an optimized build for a production environment. - dev: Create an unoptimized, live-reloading build for local development. +dist: Create an optimized production-like for a non-production environment. + +prod: Create an optimized build for a production environment. + test: Create an optimized build for running e2e tests. testDev: Create an unoptimized, live-reloading build for debugging e2e tests.`, @@ -254,6 +272,18 @@ testDev: Create an unoptimized, live-reloading build for debugging e2e tests.`, const version = getVersion(buildType, buildVersion); + const highLevelTasks = Object.values(BUILD_TARGETS); + if (highLevelTasks.includes(task)) { + const environment = getEnvironment({ buildTarget: task }); + if (environment === ENVIRONMENT.PRODUCTION) { + // Output ignored, this is only called to ensure config is validated + await getProductionConfig(buildType); + } else { + // Output ignored, this is only called to ensure config is validated + await getConfig(); + } + } + return { applyLavaMoat, buildType, diff --git a/development/build/scripts.js b/development/build/scripts.js index 098c6af47..1afd9c4f6 100644 --- a/development/build/scripts.js +++ b/development/build/scripts.js @@ -24,45 +24,19 @@ const Sqrl = require('squirrelly'); const lavapack = require('@lavamoat/lavapack'); const lavamoatBrowserify = require('lavamoat-browserify'); const terser = require('terser'); -const ini = require('ini'); const bifyModuleGroups = require('bify-module-groups'); -const configPath = path.resolve(__dirname, '..', '..', '.metamaskrc'); -let configContents = ''; -try { - configContents = readFileSync(configPath, { - encoding: 'utf8', - }); -} catch (error) { - if (error.code !== 'ENOENT') { - throw error; - } -} -const metamaskrc = { - INFURA_PROJECT_ID: process.env.INFURA_PROJECT_ID, - INFURA_BETA_PROJECT_ID: process.env.INFURA_BETA_PROJECT_ID, - INFURA_FLASK_PROJECT_ID: process.env.INFURA_FLASK_PROJECT_ID, - INFURA_PROD_PROJECT_ID: process.env.INFURA_PROD_PROJECT_ID, - ONBOARDING_V2: process.env.ONBOARDING_V2, - COLLECTIBLES_V1: process.env.COLLECTIBLES_V1, - PHISHING_WARNING_PAGE_URL: process.env.PHISHING_WARNING_PAGE_URL, - SEGMENT_HOST: process.env.SEGMENT_HOST, - SEGMENT_WRITE_KEY: process.env.SEGMENT_WRITE_KEY, - SEGMENT_BETA_WRITE_KEY: process.env.SEGMENT_BETA_WRITE_KEY, - SEGMENT_FLASK_WRITE_KEY: process.env.SEGMENT_FLASK_WRITE_KEY, - SEGMENT_PROD_WRITE_KEY: process.env.SEGMENT_PROD_WRITE_KEY, - SENTRY_DSN_DEV: - process.env.SENTRY_DSN_DEV || - 'https://f59f3dd640d2429d9d0e2445a87ea8e1@sentry.io/273496', - SIWE_V1: process.env.SIWE_V1, - ...ini.parse(configContents), -}; - const { streamFlatMap } = require('../stream-flat-map'); const { BuildType } = require('../lib/build-type'); -const { BUILD_TARGETS } = require('./constants'); -const { logError } = require('./utils'); +const { BUILD_TARGETS, ENVIRONMENT } = require('./constants'); +const { getConfig, getProductionConfig } = require('./config'); +const { + isDevBuild, + isTestBuild, + getEnvironment, + logError, +} = require('./utils'); const { createTask, @@ -74,81 +48,28 @@ const { createRemoveFencedCodeTransform, } = require('./transforms/remove-fenced-code'); -/** - * The build environment. This describes the environment this build was produced in. - */ -const ENVIRONMENT = { - DEVELOPMENT: 'development', - PRODUCTION: 'production', - OTHER: 'other', - PULL_REQUEST: 'pull-request', - RELEASE_CANDIDATE: 'release-candidate', - STAGING: 'staging', - TESTING: 'testing', -}; - -/** - * Returns whether the current build is a development build or not. - * - * @param {BUILD_TARGETS} buildTarget - The current build target. - * @returns Whether the current build is a development build. - */ -function isDevBuild(buildTarget) { - return ( - buildTarget === BUILD_TARGETS.DEVELOPMENT || - buildTarget === BUILD_TARGETS.E2E_TEST_DEV - ); -} - -/** - * Returns whether the current build is an e2e test build or not. - * - * @param {BUILD_TARGETS} buildTarget - The current build target. - * @returns Whether the current build is an e2e test build. - */ -function isTestBuild(buildTarget) { - return ( - buildTarget === BUILD_TARGETS.E2E_TEST || - buildTarget === BUILD_TARGETS.E2E_TEST_DEV - ); -} - -/** - * Get a value from the configuration, and confirm that it is set. - * - * @param {string} key - The configuration key to retrieve. - * @returns {string} The config entry requested. - * @throws {Error} Throws if the requested key is missing. - */ -function getConfigValue(key) { - const value = metamaskrc[key]; - if (!value) { - throw new Error(`Missing config entry for '${key}'`); - } - return value; -} - /** * Get the appropriate Infura project ID. * * @param {object} options - The Infura project ID options. * @param {BuildType} options.buildType - The current build type. + * @param {object} options.config - The environment variable configuration. * @param {ENVIRONMENT[keyof ENVIRONMENT]} options.environment - The build environment. * @param {boolean} options.testing - Whether this is a test build or not. * @returns {string} The Infura project ID. */ -function getInfuraProjectId({ buildType, environment, testing }) { +function getInfuraProjectId({ buildType, config, environment, testing }) { if (testing) { return '00000000000000000000000000000000'; } else if (environment !== ENVIRONMENT.PRODUCTION) { // Skip validation because this is unset on PRs from forks. - return metamaskrc.INFURA_PROJECT_ID; + return config.INFURA_PROJECT_ID; } else if (buildType === BuildType.main) { - return getConfigValue('INFURA_PROD_PROJECT_ID'); + return config.INFURA_PROD_PROJECT_ID; } else if (buildType === BuildType.beta) { - return getConfigValue('INFURA_BETA_PROJECT_ID'); + return config.INFURA_BETA_PROJECT_ID; } else if (buildType === BuildType.flask) { - return getConfigValue('INFURA_FLASK_PROJECT_ID'); + return config.INFURA_FLASK_PROJECT_ID; } throw new Error(`Invalid build type: '${buildType}'`); } @@ -158,19 +79,20 @@ function getInfuraProjectId({ buildType, environment, testing }) { * * @param {object} options - The Segment write key options. * @param {BuildType} options.buildType - The current build type. + * @param {object} options.config - The environment variable configuration. * @param {keyof ENVIRONMENT} options.environment - The current build environment. * @returns {string} The Segment write key. */ -function getSegmentWriteKey({ buildType, environment }) { +function getSegmentWriteKey({ buildType, config, environment }) { if (environment !== ENVIRONMENT.PRODUCTION) { // Skip validation because this is unset on PRs from forks, and isn't necessary for development builds. - return metamaskrc.SEGMENT_WRITE_KEY; + return config.SEGMENT_WRITE_KEY; } else if (buildType === BuildType.main) { - return getConfigValue('SEGMENT_PROD_WRITE_KEY'); + return config.SEGMENT_PROD_WRITE_KEY; } else if (buildType === BuildType.beta) { - return getConfigValue('SEGMENT_BETA_WRITE_KEY'); + return config.SEGMENT_BETA_WRITE_KEY; } else if (buildType === BuildType.flask) { - return getConfigValue('SEGMENT_FLASK_WRITE_KEY'); + return config.SEGMENT_FLASK_WRITE_KEY; } throw new Error(`Invalid build type: '${buildType}'`); } @@ -179,11 +101,12 @@ function getSegmentWriteKey({ buildType, environment }) { * Get the URL for the phishing warning page, if it has been set. * * @param {object} options - The phishing warning page options. + * @param {object} options.config - The environment variable configuration. * @param {boolean} options.testing - Whether this is a test build or not. * @returns {string} The URL for the phishing warning page, or `undefined` if no URL is set. */ -function getPhishingWarningPageUrl({ testing }) { - let phishingWarningPageUrl = metamaskrc.PHISHING_WARNING_PAGE_URL; +function getPhishingWarningPageUrl({ config, testing }) { + let phishingWarningPageUrl = config.PHISHING_WARNING_PAGE_URL; if (!phishingWarningPageUrl) { phishingWarningPageUrl = testing @@ -259,35 +182,35 @@ function createScriptTasks({ shouldLintFenceFiles, version, }) { - // internal tasks - const core = { + // high level tasks + return { // dev tasks (live reload) dev: createTasksForScriptBundles({ - buildTarget: BUILD_TARGETS.DEVELOPMENT, + buildTarget: BUILD_TARGETS.DEV, taskPrefix: 'scripts:core:dev', }), + // production-like distributable build + dist: createTasksForScriptBundles({ + buildTarget: BUILD_TARGETS.DIST, + taskPrefix: 'scripts:core:dist', + }), // production prod: createTasksForScriptBundles({ - buildTarget: BUILD_TARGETS.PRODUCTION, + buildTarget: BUILD_TARGETS.PROD, taskPrefix: 'scripts:core:prod', }), // built for CI tests test: createTasksForScriptBundles({ - buildTarget: BUILD_TARGETS.E2E_TEST, + buildTarget: BUILD_TARGETS.TEST, taskPrefix: 'scripts:core:test', }), // built for CI test debugging testDev: createTasksForScriptBundles({ - buildTarget: BUILD_TARGETS.E2E_TEST_DEV, + buildTarget: BUILD_TARGETS.TEST_DEV, taskPrefix: 'scripts:core:test-live', }), }; - // high level tasks - - const { dev, test, testDev, prod } = core; - return { dev, test, testDev, prod }; - /** * Define tasks for building the JavaScript modules used by the extension. * This function returns a single task that builds JavaScript modules in @@ -595,7 +518,7 @@ function createFactoredBuild({ const reloadOnChange = isDevBuild(buildTarget); const minify = !isDevBuild(buildTarget); - const envVars = getEnvironmentVariables({ + const envVars = await getEnvironmentVariables({ buildTarget, buildType, version, @@ -823,11 +746,11 @@ function createNormalBundle({ const minify = Boolean(devMode) === false; const envVars = { - ...getEnvironmentVariables({ + ...(await getEnvironmentVariables({ buildTarget, buildType, version, - }), + })), ...extraEnvironmentVariables, }; setupBundlerDefaults(buildConfiguration, { @@ -915,7 +838,7 @@ function setupBundlerDefaults( }); // Ensure react-devtools is only included in dev builds - if (buildTarget !== BUILD_TARGETS.DEVELOPMENT) { + if (buildTarget !== BUILD_TARGETS.DEV) { bundlerOpts.manualIgnore.push('react-devtools'); bundlerOpts.manualIgnore.push('remote-redux-devtools'); } @@ -1081,20 +1004,22 @@ async function createBundle(buildConfiguration, { reloadOnChange }) { * @param {string} options.version - The current version of the extension. * @returns {object} A map of environment variables to inject. */ -function getEnvironmentVariables({ buildTarget, buildType, version }) { +async function getEnvironmentVariables({ buildTarget, buildType, version }) { const environment = getEnvironment({ buildTarget }); - if (environment === ENVIRONMENT.PRODUCTION && !process.env.SENTRY_DSN) { - throw new Error('Missing SENTRY_DSN environment variable'); - } + const config = + environment === ENVIRONMENT.PRODUCTION + ? await getProductionConfig(buildType) + : await getConfig(); const devMode = isDevBuild(buildTarget); const testing = isTestBuild(buildTarget); return { - COLLECTIBLES_V1: metamaskrc.COLLECTIBLES_V1 === '1', - CONF: devMode ? metamaskrc : {}, + COLLECTIBLES_V1: config.COLLECTIBLES_V1 === '1', + CONF: devMode ? config : {}, IN_TEST: testing, INFURA_PROJECT_ID: getInfuraProjectId({ buildType, + config, environment, testing, }), @@ -1103,39 +1028,19 @@ function getEnvironmentVariables({ buildTarget, buildType, version }) { METAMASK_VERSION: version, METAMASK_BUILD_TYPE: buildType, NODE_ENV: devMode ? ENVIRONMENT.DEVELOPMENT : ENVIRONMENT.PRODUCTION, - ONBOARDING_V2: metamaskrc.ONBOARDING_V2 === '1', - PHISHING_WARNING_PAGE_URL: getPhishingWarningPageUrl({ testing }), - PUBNUB_PUB_KEY: process.env.PUBNUB_PUB_KEY || '', - PUBNUB_SUB_KEY: process.env.PUBNUB_SUB_KEY || '', - SEGMENT_HOST: metamaskrc.SEGMENT_HOST, - SEGMENT_WRITE_KEY: getSegmentWriteKey({ buildType, environment }), - SENTRY_DSN: process.env.SENTRY_DSN, - SENTRY_DSN_DEV: metamaskrc.SENTRY_DSN_DEV, - SIWE_V1: metamaskrc.SIWE_V1 === '1', - SWAPS_USE_DEV_APIS: process.env.SWAPS_USE_DEV_APIS === '1', + ONBOARDING_V2: config.ONBOARDING_V2 === '1', + PHISHING_WARNING_PAGE_URL: getPhishingWarningPageUrl({ config, testing }), + PUBNUB_PUB_KEY: config.PUBNUB_PUB_KEY || '', + PUBNUB_SUB_KEY: config.PUBNUB_SUB_KEY || '', + SEGMENT_HOST: config.SEGMENT_HOST, + SEGMENT_WRITE_KEY: getSegmentWriteKey({ buildType, config, environment }), + SENTRY_DSN: config.SENTRY_DSN, + SENTRY_DSN_DEV: config.SENTRY_DSN_DEV, + SIWE_V1: config.SIWE_V1 === '1', + SWAPS_USE_DEV_APIS: config.SWAPS_USE_DEV_APIS === '1', }; } -function getEnvironment({ buildTarget }) { - // get environment slug - if (isDevBuild(buildTarget)) { - return ENVIRONMENT.DEVELOPMENT; - } else if (isTestBuild(buildTarget)) { - return ENVIRONMENT.TESTING; - } else if (process.env.CIRCLE_BRANCH === 'master') { - return ENVIRONMENT.PRODUCTION; - } else if ( - /^Version-v(\d+)[.](\d+)[.](\d+)/u.test(process.env.CIRCLE_BRANCH) - ) { - return ENVIRONMENT.RELEASE_CANDIDATE; - } else if (process.env.CIRCLE_BRANCH === 'develop') { - return ENVIRONMENT.STAGING; - } else if (process.env.CIRCLE_PULL_REQUEST) { - return ENVIRONMENT.PULL_REQUEST; - } - return ENVIRONMENT.OTHER; -} - function renderHtmlFile({ htmlName, groupSet, diff --git a/development/build/utils.js b/development/build/utils.js index 4e31f489a..f783c6d40 100644 --- a/development/build/utils.js +++ b/development/build/utils.js @@ -1,5 +1,30 @@ const semver = require('semver'); const { BuildType } = require('../lib/build-type'); +const { BUILD_TARGETS, ENVIRONMENT } = require('./constants'); + +/** + * Returns whether the current build is a development build or not. + * + * @param {BUILD_TARGETS} buildTarget - The current build target. + * @returns Whether the current build is a development build. + */ +function isDevBuild(buildTarget) { + return ( + buildTarget === BUILD_TARGETS.DEV || buildTarget === BUILD_TARGETS.TEST_DEV + ); +} + +/** + * Returns whether the current build is an e2e test build or not. + * + * @param {BUILD_TARGETS} buildTarget - The current build target. + * @returns Whether the current build is an e2e test build. + */ +function isTestBuild(buildTarget) { + return ( + buildTarget === BUILD_TARGETS.TEST || buildTarget === BUILD_TARGETS.TEST_DEV + ); +} /** * Map the current version to a format that is compatible with each browser. @@ -51,6 +76,33 @@ function getBrowserVersionMap(platforms, version) { }, {}); } +/** + * Get the environment of the current build. + * + * @param {object} options - Build options. + * @param {BUILD_TARGETS} options.buildTarget - The target of the current build. + * @returns {ENVIRONMENT} The current build environment. + */ +function getEnvironment({ buildTarget }) { + // get environment slug + if (buildTarget === BUILD_TARGETS.PROD) { + return ENVIRONMENT.PRODUCTION; + } else if (isDevBuild(buildTarget)) { + return ENVIRONMENT.DEVELOPMENT; + } else if (isTestBuild(buildTarget)) { + return ENVIRONMENT.TESTING; + } else if ( + /^Version-v(\d+)[.](\d+)[.](\d+)/u.test(process.env.CIRCLE_BRANCH) + ) { + return ENVIRONMENT.RELEASE_CANDIDATE; + } else if (process.env.CIRCLE_BRANCH === 'develop') { + return ENVIRONMENT.STAGING; + } else if (process.env.CIRCLE_PULL_REQUEST) { + return ENVIRONMENT.PULL_REQUEST; + } + return ENVIRONMENT.OTHER; +} + /** * Log an error to the console. * @@ -67,5 +119,8 @@ function logError(error) { module.exports = { getBrowserVersionMap, + getEnvironment, + isDevBuild, + isTestBuild, logError, }; diff --git a/package.json b/package.json index f7bea6d74..cae0ff143 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "start": "yarn build:dev dev --apply-lavamoat=false", "start:lavamoat": "yarn build:dev dev --apply-lavamoat=true", "start:mv3": "ENABLE_MV3=true yarn build:dev dev --apply-lavamoat=false", - "dist": "yarn build prod", + "dist": "yarn build dist", "build": "yarn lavamoat:build", "build:dev": "node development/build/index.js", "start:test": "SEGMENT_HOST='https://api.segment.io' SEGMENT_WRITE_KEY='FAKE' yarn build testDev",