Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
13 changes: 13 additions & 0 deletions development/build/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,18 @@ const ENVIRONMENT = {
TESTING: 'testing',
};

/**
* Task prefixes for each build target.
* Used to create task names like 'scripts:core:dev:standardEntryPoints'.
*/
const TASK_PREFIXES = {
[BUILD_TARGETS.DEV]: 'scripts:core:dev',
[BUILD_TARGETS.DIST]: 'scripts:core:dist',
[BUILD_TARGETS.PROD]: 'scripts:core:prod',
[BUILD_TARGETS.TEST]: 'scripts:core:test',
[BUILD_TARGETS.TEST_DEV]: 'scripts:core:test-live',
};

const TASKS = {
...BUILD_TARGETS,
CLEAN: 'clean',
Expand Down Expand Up @@ -87,6 +99,7 @@ const MANIFEST_RELEASE_CANDIDATE_KEY =
module.exports = {
BUILD_TARGETS,
ENVIRONMENT,
TASK_PREFIXES,
TASKS,
MANIFEST_DEV_KEY,
MANIFEST_RELEASE_CANDIDATE_KEY,
Expand Down
9 changes: 7 additions & 2 deletions development/build/manifest.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,11 @@ const {
MANIFEST_RELEASE_CANDIDATE_KEY,
} = require('./constants');
const { createTask, composeSeries } = require('./task');
const { getEnvironment, getBuildName } = require('./utils');
const {
getEnvironment,
getBuildName,
getBuildTargetFromTask,
} = require('./utils');
const { fromIniFile } = require('./config');

module.exports = createManifestTasks;
Expand Down Expand Up @@ -55,7 +59,8 @@ function createManifestTasks({
shouldIncludeOcapKernel = false,
shouldIncludeSnow,
}) {
const environment = getEnvironment({ buildTarget: entryTask });
const buildTarget = getBuildTargetFromTask(entryTask);
const environment = getEnvironment({ buildTarget });

// merge base manifest with per-platform manifests
const prepPlatforms = async () => {
Expand Down
12 changes: 6 additions & 6 deletions development/build/scripts.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ const bifyModuleGroups = require('bify-module-groups');
const { streamFlatMap } = require('../stream-flat-map');
const { isManifestV3 } = require('../../shared/modules/mv3.utils');
const { setEnvironmentVariables } = require('./set-environment-variables');
const { BUILD_TARGETS } = require('./constants');
const { BUILD_TARGETS, TASK_PREFIXES } = require('./constants');
const { getConfig, getActiveFeatures } = require('./config');
const {
isDevBuild,
Expand Down Expand Up @@ -155,27 +155,27 @@ function createScriptTasks({
// dev tasks (live reload)
dev: createTasksForScriptBundles({
buildTarget: BUILD_TARGETS.DEV,
taskPrefix: 'scripts:core:dev',
taskPrefix: TASK_PREFIXES[BUILD_TARGETS.DEV],
}),
// production-like distributable build
dist: createTasksForScriptBundles({
buildTarget: BUILD_TARGETS.DIST,
taskPrefix: 'scripts:core:dist',
taskPrefix: TASK_PREFIXES[BUILD_TARGETS.DIST],
}),
// production
prod: createTasksForScriptBundles({
buildTarget: BUILD_TARGETS.PROD,
taskPrefix: 'scripts:core:prod',
taskPrefix: TASK_PREFIXES[BUILD_TARGETS.PROD],
}),
// built for CI tests
test: createTasksForScriptBundles({
buildTarget: BUILD_TARGETS.TEST,
taskPrefix: 'scripts:core:test',
taskPrefix: TASK_PREFIXES[BUILD_TARGETS.TEST],
}),
// built for CI test debugging
testDev: createTasksForScriptBundles({
buildTarget: BUILD_TARGETS.TEST_DEV,
taskPrefix: 'scripts:core:test-live',
taskPrefix: TASK_PREFIXES[BUILD_TARGETS.TEST_DEV],
}),
};

Expand Down
58 changes: 54 additions & 4 deletions development/build/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ const { readFileSync, writeFileSync } = require('fs');
const semver = require('semver');
const { capitalize } = require('lodash');
const { loadBuildTypesConfig } = require('../lib/build-type');
const { BUILD_TARGETS, ENVIRONMENT } = require('./constants');
const { BUILD_TARGETS, ENVIRONMENT, TASK_PREFIXES } = require('./constants');

/**
* Returns whether the current build is a development build or not.
Expand All @@ -29,6 +29,43 @@ function isTestBuild(buildTarget) {
);
}

/**
* Extract the actual build target from a task name.
*
* Task names follow patterns like:
* - 'scripts:core:dev:standardEntryPoints' -> 'dev'
* - 'scripts:core:test:contentscript' -> 'test'
* - 'scripts:core:test-live:sentry' -> 'testDev'
* - 'test' -> 'test' (already a build target)
*
* @param {string} taskName - The task name or build target.
* @returns {BUILD_TARGETS | string} The extracted build target.
*/
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;
}

// Create reverse mapping from prefix to build target
// Sort by prefix length descending to ensure longer prefixes match first
// (e.g., 'scripts:core:test-live' before 'scripts:core:test')
const prefixEntries = Object.entries(TASK_PREFIXES).sort(
([, prefixA], [, prefixB]) => prefixB.length - prefixA.length,
);

for (const [buildTarget, prefix] of prefixEntries) {
if (taskName.startsWith(prefix)) {
return buildTarget;
}
}

// If no match found, return the original task name
// (getEnvironment will handle it appropriately)
return taskName;
}

/**
* Map the current version to a format that is compatible with each browser.
*
Expand Down Expand Up @@ -114,12 +151,24 @@ Good luck on your endeavors.`,
/**
* Get the environment of the current build.
*
* This is a pure function that determines the build environment based on the
* build target and optional git context. When git context is not provided,
* it falls back to reading from process.env for backwards compatibility.
*
* @param {object} options - Build options.
* @param {BUILD_TARGETS} options.buildTarget - The target of the current build.
* @param {{ branch?: string, eventName?: string }} [options.git] - Optional git context for pure function usage.
* @returns {ENVIRONMENT} The current build environment.
*/
function getEnvironment({ buildTarget }) {
const branch = process.env.GITHUB_HEAD_REF || process.env.GITHUB_REF_NAME;
function getEnvironment({ buildTarget, git }) {
// Use provided git context or fall back to process.env for backwards compatibility
const branch =
git?.branch ||
process.env.GITHUB_HEAD_REF ||
process.env.GITHUB_REF_NAME ||
'';
const eventName = git?.eventName || process.env.GITHUB_EVENT_NAME || '';

// get environment slug
if (buildTarget === BUILD_TARGETS.PROD) {
return ENVIRONMENT.PRODUCTION;
Expand All @@ -131,7 +180,7 @@ function getEnvironment({ buildTarget }) {
return ENVIRONMENT.RELEASE_CANDIDATE;
} else if (branch === 'main') {
return ENVIRONMENT.STAGING;
} else if (process.env.GITHUB_EVENT_NAME === 'pull_request') {
} else if (eventName === 'pull_request') {
return ENVIRONMENT.PULL_REQUEST;
}
return ENVIRONMENT.OTHER;
Expand Down Expand Up @@ -299,6 +348,7 @@ function makeSelfInjecting(filePath) {
module.exports = {
getBrowserVersionMap,
getBuildName,
getBuildTargetFromTask,
getEnvironment,
isDevBuild,
isTestBuild,
Expand Down
157 changes: 157 additions & 0 deletions development/build/utils.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
import { getEnvironment, getBuildTargetFromTask } from './utils';
import { TASKS } from './constants';

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

it('extracts build target from task names', () => {
expect(
getBuildTargetFromTask(TASKS.SCRIPTS_CORE_DEV_STANDARD_ENTRY_POINTS),
).toBe('dev');
expect(
getBuildTargetFromTask(TASKS.SCRIPTS_CORE_TEST_STANDARD_ENTRY_POINTS),
).toBe('test');
expect(
getBuildTargetFromTask(TASKS.SCRIPTS_CORE_PROD_STANDARD_ENTRY_POINTS),
).toBe('prod');
expect(
getBuildTargetFromTask(TASKS.SCRIPTS_CORE_DIST_STANDARD_ENTRY_POINTS),
).toBe('dist');
expect(
getBuildTargetFromTask(
TASKS.SCRIPTS_CORE_TEST_LIVE_STANDARD_ENTRY_POINTS,
),
).toBe('testDev');
});

it('returns unknown patterns unchanged', () => {
expect(getBuildTargetFromTask('unknown:task')).toBe('unknown:task');
expect(getBuildTargetFromTask(TASKS.MANIFEST_DEV)).toBe(TASKS.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;
});

describe('with explicit git context (pure function usage)', () => {
it('returns correct environment for build targets', () => {
const git = { branch: '', eventName: '' };
expect(getEnvironment({ buildTarget: 'prod' as never, git })).toBe(
'production',
);
expect(getEnvironment({ buildTarget: 'dev' as never, git })).toBe(
'development',
);
expect(getEnvironment({ buildTarget: 'test' as never, git })).toBe(
'testing',
);
expect(getEnvironment({ buildTarget: 'testDev' as never, git })).toBe(
'development',
);
expect(getEnvironment({ buildTarget: 'dist' as never, git })).toBe(
'other',
);
});

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

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

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

it('returns TESTING for test even with pull_request event', () => {
const git = { branch: '', eventName: 'pull_request' };
expect(getEnvironment({ buildTarget: 'test' as never, git })).toBe(
'testing',
);
});

it('prioritizes release branch over pull_request event', () => {
const git = { branch: 'release/14.0.0', eventName: 'pull_request' };
expect(getEnvironment({ buildTarget: 'dist' as never, git })).toBe(
'release-candidate',
);
});
});

describe('with process.env fallback (backwards compatibility)', () => {
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

### `--metamaskEnvironment`

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

| Value | When Used |
| ------------------- | -------------------------------------------- |
| `production` | Must be explicitly set (never auto-detected) |
| `development` | `--env development` |
| `testing` | `--test` flag |
| `staging` | `main` branch |
| `release-candidate` | `release/*` branch |
| `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 --metamaskEnvironment 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
1 change: 1 addition & 0 deletions development/webpack/test/cli.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ describe('./utils/cli.ts', () => {
snow: false,
dryRun: false,
stats: false,
metamaskEnvironment: undefined,
};

it('should return defaults', () => {
Expand Down
Loading
Loading