1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-11-22 18:00:18 +01:00
metamask-extension/development/build/index.js
Mark Stacey 75a8aedc32
Derive version suffix from build type and version (#13895)
The version of a build is now derived from both the `version` field in
`package.json` and the requested build type and version. The build type
and version are added onto the manifest version as a suffix, according
to the SemVer prerelease format.

We already have support in the extension for versions of this format,
but to apply a Flask or Beta version required manual updates to
`package.json`. Now it can be done just with build arguments.

A `get-version` module was created to make it easier to generate the
version in the various places we do that during the build. It was
created in the `development/lib` directory because it will be used by
other non-build development scripts in a future PR.

The `BuildType` constant was extracted to its own module as well, and
moved to the `development/lib` directory. This was to make it clear
that it's used by various different development scripts, not just the
build.
2022-03-10 12:31:50 -03:30

273 lines
7.2 KiB
JavaScript
Executable File

//
// build task definitions
//
// run any task with "yarn build ${taskName}"
//
const path = require('path');
const livereload = require('gulp-livereload');
const minimist = require('minimist');
const { sync: globby } = require('globby');
const { getVersion } = require('../lib/get-version');
const { BuildType } = require('../lib/build-type');
const {
createTask,
composeSeries,
composeParallel,
runTask,
} = require('./task');
const createManifestTasks = require('./manifest');
const createScriptTasks = require('./scripts');
const createStyleTasks = require('./styles');
const createStaticAssetTasks = require('./static');
const createEtcTasks = require('./etc');
const { getBrowserVersionMap } = require('./utils');
// Packages required dynamically via browserify configuration in dependencies
// Required for LavaMoat policy generation
require('loose-envify');
require('globalthis');
require('@babel/plugin-proposal-object-rest-spread');
require('@babel/plugin-transform-runtime');
require('@babel/plugin-proposal-class-properties');
require('@babel/plugin-proposal-optional-chaining');
require('@babel/plugin-proposal-nullish-coalescing-operator');
require('@babel/preset-env');
require('@babel/preset-react');
require('@babel/core');
// ESLint-related
require('@babel/eslint-parser');
require('@babel/eslint-plugin');
require('@metamask/eslint-config');
require('@metamask/eslint-config-nodejs');
require('eslint');
require('eslint-config-prettier');
require('eslint-import-resolver-node');
require('eslint-plugin-import');
require('eslint-plugin-jsdoc');
require('eslint-plugin-node');
require('eslint-plugin-prettier');
require('eslint-plugin-react');
require('eslint-plugin-react-hooks');
defineAndRunBuildTasks();
function defineAndRunBuildTasks() {
const {
buildType,
entryTask,
isLavaMoat,
policyOnly,
shouldIncludeLockdown,
shouldLintFenceFiles,
skipStats,
version,
} = parseArgv();
const browserPlatforms = ['firefox', 'chrome', 'brave', 'opera'];
const browserVersionMap = getBrowserVersionMap(browserPlatforms, version);
const ignoredFiles = getIgnoredFiles(buildType);
const staticTasks = createStaticAssetTasks({
livereload,
browserPlatforms,
shouldIncludeLockdown,
buildType,
});
const manifestTasks = createManifestTasks({
browserPlatforms,
browserVersionMap,
buildType,
});
const styleTasks = createStyleTasks({ livereload });
const scriptTasks = createScriptTasks({
browserPlatforms,
buildType,
ignoredFiles,
isLavaMoat,
livereload,
policyOnly,
shouldLintFenceFiles,
version,
});
const { clean, reload, zip } = createEtcTasks({
livereload,
browserPlatforms,
buildType,
version,
});
// build for development (livereload)
createTask(
'dev',
composeSeries(
clean,
styleTasks.dev,
composeParallel(
scriptTasks.dev,
staticTasks.dev,
manifestTasks.dev,
reload,
),
),
);
// build for test development (livereload)
createTask(
'testDev',
composeSeries(
clean,
styleTasks.dev,
composeParallel(
scriptTasks.testDev,
staticTasks.dev,
manifestTasks.testDev,
reload,
),
),
);
// build for prod release
createTask(
'prod',
composeSeries(
clean,
styleTasks.prod,
composeParallel(scriptTasks.prod, staticTasks.prod, manifestTasks.prod),
zip,
),
);
// build just production scripts, for LavaMoat policy generation purposes
createTask('scripts:prod', scriptTasks.prod);
// build for CI testing
createTask(
'test',
composeSeries(
clean,
styleTasks.prod,
composeParallel(scriptTasks.test, staticTasks.prod, manifestTasks.test),
zip,
),
);
// special build for minimal CI testing
createTask('styles', styleTasks.prod);
// Finally, start the build process by running the entry task.
runTask(entryTask, { skipStats });
}
function parseArgv() {
const NamedArgs = {
BuildType: 'build-type',
BuildVersion: 'build-version',
LintFenceFiles: 'lint-fence-files',
Lockdown: 'lockdown',
PolicyOnly: 'policy-only',
SkipStats: 'skip-stats',
};
const argv = minimist(process.argv.slice(2), {
boolean: [
NamedArgs.LintFenceFiles,
NamedArgs.Lockdown,
NamedArgs.PolicyOnly,
NamedArgs.SkipStats,
],
string: [NamedArgs.BuildType, NamedArgs.BuildVersion],
default: {
[NamedArgs.BuildType]: BuildType.main,
[NamedArgs.BuildVersion]: '0',
[NamedArgs.LintFenceFiles]: true,
[NamedArgs.Lockdown]: true,
[NamedArgs.PolicyOnly]: false,
[NamedArgs.SkipStats]: false,
},
});
if (argv._.length !== 1) {
throw new Error(
`Metamask build: Expected a single positional argument, but received "${argv._.length}" arguments.`,
);
}
const entryTask = argv._[0];
if (!entryTask) {
throw new Error('MetaMask build: No entry task specified.');
}
const buildType = argv[NamedArgs.BuildType];
if (!(buildType in BuildType)) {
throw new Error(`MetaMask build: Invalid build type: "${buildType}"`);
}
const rawBuildVersion = argv[NamedArgs.BuildVersion];
const buildVersion = Number.parseInt(rawBuildVersion, 10);
if (rawBuildVersion.match(/^\d+$/u) === null || Number.isNaN(buildVersion)) {
throw new Error(
`MetaMask build: Invalid build version: "${rawBuildVersion}"`,
);
}
// Manually default this to `false` for dev builds only.
const shouldLintFenceFiles = process.argv.includes(
`--${NamedArgs.LintFenceFiles}`,
)
? argv[NamedArgs.LintFenceFiles]
: !/dev/iu.test(entryTask);
const policyOnly = argv[NamedArgs.PolicyOnly];
const version = getVersion(buildType, buildVersion);
return {
buildType,
entryTask,
isLavaMoat: process.argv[0].includes('lavamoat'),
policyOnly,
shouldIncludeLockdown: argv[NamedArgs.Lockdown],
shouldLintFenceFiles,
skipStats: argv[NamedArgs.SkipStats],
version,
};
}
/**
* Gets the files to be ignored by the current build, if any.
*
* @param {string} currentBuildType - The type of the current build.
* @returns {string[] | null} The array of files to be ignored by the current
* build, or `null` if no files are to be ignored.
*/
function getIgnoredFiles(currentBuildType) {
const excludedFiles = Object.values(BuildType)
// This filter removes "main" and the current build type. The files of any
// build types that remain in the array will be excluded. "main" is the
// default build type, and has no files that are excluded from other builds.
.filter(
(buildType) =>
buildType !== BuildType.main && buildType !== currentBuildType,
)
// Compute globs targeting files for exclusion for each excluded build
// type.
.reduce((excludedGlobs, excludedBuildType) => {
return excludedGlobs.concat([
`../../app/**/${excludedBuildType}/**`,
`../../shared/**/${excludedBuildType}/**`,
`../../ui/**/${excludedBuildType}/**`,
]);
}, [])
// This creates absolute paths of the form:
// PATH_TO_REPOSITORY_ROOT/app/**/${excludedBuildType}/**
.map((pathGlob) => path.resolve(__dirname, pathGlob));
return globby(excludedFiles);
}