Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
c36137b
fix(5955): ensure getEnvironment() function to return the correct env…
DDDDDanica Dec 8, 2025
ec732ff
Merge remote-tracking branch 'origin/main' into fix/5955-env-logic
DDDDDanica Dec 10, 2025
b1516e9
chore(5956): lint fix
DDDDDanica Dec 10, 2025
6d9fdfb
chore(5956): fix Empty string GITHUB_HEAD_REF breaks branch detection
DDDDDanica Dec 10, 2025
16cdd36
chore(5956): fix Falsy empty string causes incorrect environment fall…
DDDDDanica Dec 10, 2025
da8f9d0
chore(5956): throw error when getBuildTargetFromTask has no match
DDDDDanica Dec 11, 2025
01644ef
chore(5956): guard type and remove undefine param
DDDDDanica Dec 11, 2025
b48d5c6
chore(5956): fix unit test
DDDDDanica Dec 11, 2025
ac66e77
Merge branch 'main' into fix/5955-env-logic
DDDDDanica Dec 11, 2025
70b4725
Merge branch 'main' into fix/5955-env-logic
DDDDDanica Dec 12, 2025
4f10319
chore(5956): fix remove the type assertion
DDDDDanica Dec 15, 2025
3fadd50
Merge remote-tracking branch 'origin/main' into fix/5955-env-logic
DDDDDanica Dec 15, 2025
ba57673
chore(5956): fix Build fails for low-level tasks passed as entry
DDDDDanica Dec 15, 2025
6c8e6d7
fix: rename metamaskEnvironment to targetEnvironment
DDDDDanica Dec 19, 2025
29f6262
fix: make resolvedEnvironment mandatory
DDDDDanica Dec 20, 2025
569936c
fix: Dry-run message shows incorrect auto-detection status
DDDDDanica Dec 21, 2025
1fcca68
fix: expand SPECIAL_TASK_MAPPINGS for remaining standalone tasks
DDDDDanica Jan 5, 2026
3dddcb9
chore(5956): add all task mappings to SPECIAL_TASK_MAPPINGS
DDDDDanica Jan 5, 2026
05e582b
Merge branch 'main' into fix/5955-env-logic
DDDDDanica Jan 6, 2026
b0f9784
Merge branch 'main' into fix/5955-env-logic
DDDDDanica Jan 6, 2026
2d31221
Merge branch 'main' into fix/5955-env-logic
DDDDDanica Jan 7, 2026
86ad1cc
Merge branch 'main' into fix/5955-env-logic
DDDDDanica Jan 7, 2026
60fb0ed
fix: remove incorrect changes, fix fragile getIgnoredFiles() logic
DDDDDanica Jan 7, 2026
0ac4bd5
fix: fix lint and ts type
DDDDDanica Jan 7, 2026
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
8 changes: 4 additions & 4 deletions development/build/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ const createStaticAssetTasks = require('./static');
const createEtcTasks = require('./etc');
const {
getBrowserVersionMap,
getBuildTargetFromTask,
getEnvironment,
isDevBuild,
isTestBuild,
Expand Down Expand Up @@ -503,10 +504,9 @@ function getIgnoredFiles(target) {
Please fix builds.yml or specify a compatible set of features.`);
}

if (
target.includes(BUILD_TARGETS.DEV) ||
target.includes(BUILD_TARGETS.TEST)
) {
const buildTarget = getBuildTargetFromTask(target);

if (isDevBuild(buildTarget) || isTestBuild(buildTarget)) {
return ignoredPaths;
}

Expand Down
44 changes: 44 additions & 0 deletions development/build/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,49 @@ function isTestBuild(buildTarget) {
);
}

/**
* Task prefix to build target mapping.
* Used to extract the build target from task names like 'scripts:core:test:standardEntryPoints'.
* Sorted by prefix length (longest first) to ensure 'test-live' matches before 'test'.
*/
const TASK_PREFIX_TO_BUILD_TARGET = [
['scripts:core:test-live', BUILD_TARGETS.TEST_DEV],
['scripts:core:dist', BUILD_TARGETS.DIST],
['scripts:core:prod', BUILD_TARGETS.PROD],
['scripts:core:test', BUILD_TARGETS.TEST],
['scripts:core:dev', BUILD_TARGETS.DEV],
];

/**
* Extract the build target from a task name.
*
* Task names follow patterns like:
* - 'dev' -> 'dev' (already a build target)
* - 'scripts:core:test:standardEntryPoints' -> 'test'
* - 'scripts:core:test-live:sentry' -> 'testDev'
*
* @param {string} taskName - The task name or build target.
* @returns {BUILD_TARGETS} The extracted build target, or the original
* taskName if it couldn't be mapped (for backwards compatibility).
*/
function getBuildTargetFromTask(taskName) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Child processes receive task names (e.g., scripts:core:test:standardEntryPoints) instead of build targets (test). This function extracts the correct build target from task names so getEnvironment() works correctly in child processes.

// If it's already a valid build target, return it
const validTargets = Object.values(BUILD_TARGETS);
if (validTargets.includes(taskName)) {
return taskName;
}

// Check task prefixes to extract the build target
for (const [prefix, buildTarget] of TASK_PREFIX_TO_BUILD_TARGET) {
if (taskName.startsWith(prefix)) {
return buildTarget;
}
}

// Return original for backwards compatibility with unknown task names
return taskName;
}

/**
* Map the current version to a format that is compatible with each browser.
*
Expand Down Expand Up @@ -299,6 +342,7 @@ function makeSelfInjecting(filePath) {
module.exports = {
getBrowserVersionMap,
getBuildName,
getBuildTargetFromTask,
getEnvironment,
isDevBuild,
isTestBuild,
Expand Down
96 changes: 96 additions & 0 deletions development/build/utils.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import { getBuildTargetFromTask, getEnvironment } from './utils';

describe('getBuildTargetFromTask', () => {
it('passes through valid build targets unchanged', () => {
expect(getBuildTargetFromTask('dev')).toBe('dev');
expect(getBuildTargetFromTask('test')).toBe('test');
expect(getBuildTargetFromTask('testDev')).toBe('testDev');
expect(getBuildTargetFromTask('prod')).toBe('prod');
expect(getBuildTargetFromTask('dist')).toBe('dist');
});

it('extracts build target from script task names', () => {
expect(getBuildTargetFromTask('scripts:core:dev:standardEntryPoints')).toBe(
'dev',
);
expect(getBuildTargetFromTask('scripts:core:dev:contentscript')).toBe(
'dev',
);
expect(
getBuildTargetFromTask('scripts:core:test:standardEntryPoints'),
).toBe('test');
expect(getBuildTargetFromTask('scripts:core:test:sentry')).toBe('test');
expect(
getBuildTargetFromTask('scripts:core:test-live:standardEntryPoints'),
).toBe('testDev');
expect(
getBuildTargetFromTask('scripts:core:prod:standardEntryPoints'),
).toBe('prod');
expect(
getBuildTargetFromTask('scripts:core:dist:standardEntryPoints'),
).toBe('dist');
});

it('returns original taskName for unknown patterns (backwards compatibility)', () => {
expect(getBuildTargetFromTask('unknown:task')).toBe('unknown:task');
expect(getBuildTargetFromTask('manifest:dev')).toBe('manifest:dev');
});
});

describe('getEnvironment', () => {
const { env } = process;

beforeEach(() => {
process.env = { ...env };
// Clear GitHub env vars that CI sets
delete process.env.GITHUB_HEAD_REF;
delete process.env.GITHUB_REF_NAME;
delete process.env.GITHUB_EVENT_NAME;
});

afterAll(() => {
process.env = env;
});

it('returns correct environment for build targets', () => {
expect(getEnvironment({ buildTarget: 'prod' as never })).toBe('production');
expect(getEnvironment({ buildTarget: 'dev' as never })).toBe('development');
expect(getEnvironment({ buildTarget: 'test' as never })).toBe('testing');
expect(getEnvironment({ buildTarget: 'testDev' as never })).toBe(
'development',
);
expect(getEnvironment({ buildTarget: 'dist' as never })).toBe('other');
});

it('returns RELEASE_CANDIDATE for dist on release branch', () => {
process.env.GITHUB_REF_NAME = 'release/13.12.0';
expect(getEnvironment({ buildTarget: 'dist' as never })).toBe(
'release-candidate',
);
});

it('returns STAGING for dist on main branch', () => {
process.env.GITHUB_REF_NAME = 'main';
expect(getEnvironment({ buildTarget: 'dist' as never })).toBe('staging');
});

it('returns PULL_REQUEST for dist on pull_request event', () => {
process.env.GITHUB_EVENT_NAME = 'pull_request';
expect(getEnvironment({ buildTarget: 'dist' as never })).toBe(
'pull-request',
);
});

it('returns TESTING for test even with pull_request event', () => {
process.env.GITHUB_EVENT_NAME = 'pull_request';
expect(getEnvironment({ buildTarget: 'test' as never })).toBe('testing');
});

it('prefers GITHUB_HEAD_REF over GITHUB_REF_NAME', () => {
process.env.GITHUB_HEAD_REF = 'release/15.0.0';
process.env.GITHUB_REF_NAME = 'main';
expect(getEnvironment({ buildTarget: 'dist' as never })).toBe(
'release-candidate',
);
});
});
29 changes: 29 additions & 0 deletions development/webpack/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,35 @@ Run `yarn webpack --help` for the list of options.

Note: multiple array options cannot be set this way, due to this bug in yargs: https://github.com/yargs/yargs/issues/821

## CLI Arguments

### `--targetEnvironment`

Explicitly sets the build environment for Sentry reporting and feature flags. If not specified, it is auto-detected from git.

| Value | When Used |
| ------------------- | -------------------------------------------- |
| `production` | Must be explicitly set (never auto-detected) |
| `development` | `--env development` |
| `testing` | `--test` flag |
| `staging` | `main` branch on CI |
| `release-candidate` | `release/*` branch on CI |
| `pull-request` | `pull_request` GitHub event |
| `other` | Local builds or any other context (default) |

**Examples:**

```bash
# Local development (auto-detects as 'other')
yarn webpack --env production

# Explicit production (for actual releases only)
yarn webpack --env production --targetEnvironment production

# Check what environment will be used
yarn webpack --env production --dry-run
```

You can also combine environment variables with `--config` and CLI options:

```bash
Expand Down
2 changes: 1 addition & 1 deletion development/webpack/test/cli.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ describe('./utils/cli.ts', () => {

it('getDryRunMessage', () => {
const { args, features } = parseArgv([], loadBuildTypesConfig());
const message = getDryRunMessage(args, features);
const message = getDryRunMessage(args, features, 'development');
// testing the exact message could be nice, but verbose and maybe a bit
// brittle, so we just check that it returns a string
assert.strictEqual(
Expand Down
29 changes: 25 additions & 4 deletions development/webpack/utils/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import type { Options as YargsOptions } from 'yargs';
import yargs from 'yargs/yargs';
import parser from 'yargs-parser';
import type { BuildTypesConfig } from '../../lib/build-type';
import { ENVIRONMENT } from '../../build/constants';
import {
Browsers,
type Manifest,
Expand All @@ -16,6 +17,7 @@ import {
toOrange,
} from './helpers';

const environmentOptions = Object.values(ENVIRONMENT);
const ENV_PREFIX = 'BUNDLE';
const addFeat = 'addFeature' as const;
const omitFeat = 'omitFeature' as const;
Expand Down Expand Up @@ -374,6 +376,19 @@ function getOptions(
type: 'boolean',
},

targetEnvironment: {
array: false,
choices: environmentOptions,
defaultDescription:
'Auto-detected from git context (branch name, CI environment)',
description:
'The build environment (production, staging, release-candidate, pull-request, other). ' +
'Controls Sentry project targeting and feature flag detection. ' +
'If not specified, auto-detected from git context.',
group: toOrange('Build options:'),
type: 'string',
},

dryRun: {
array: false,
default: false,
Expand All @@ -394,13 +409,19 @@ function getOptions(
/**
* Returns a string representation of the given arguments and features.
*
* @param args
* @param features
* @param args - The parsed CLI arguments
* @param features - The active and available features
* @param resolvedEnvironment - The resolved MetaMask environment
*/
export function getDryRunMessage(args: Args, features: Features) {
export function getDryRunMessage(
args: Args,
features: Features,
resolvedEnvironment: string,
) {
return `🦊 Build Config 🦊

Environment: ${args.env}
Environment (--env): ${args.env}
Target Environment: ${resolvedEnvironment}${resolvedEnvironment === args.targetEnvironment ? '' : ' (auto-detected)'}
Minify: ${args.minify}
Watch: ${args.watch}
Cache: ${args.cache}
Expand Down
Loading
Loading