Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
231 changes: 231 additions & 0 deletions packages/worker/src/__unit__/env.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,34 @@ import os from 'os';

import config from '../config';
import { getBuildEnv, getGradleMemoryOptions } from '../env';
import {
DEFAULT_RUNTIME_SETTINGS,
applyRuntimeSettings,
resetRuntimeSettings,
} from '../runtimeSettings';

describe(getBuildEnv.name, () => {
const originalSentryDsn = config.sentry.dsn;
const originalPlatform = process.platform;
const originalCacheUrls = {
EAS_BUILD_NPM_CACHE_URL: process.env.EAS_BUILD_NPM_CACHE_URL,
NVM_NODEJS_ORG_MIRROR: process.env.NVM_NODEJS_ORG_MIRROR,
EAS_BUILD_MAVEN_CACHE_URL: process.env.EAS_BUILD_MAVEN_CACHE_URL,
EAS_BUILD_COCOAPODS_CACHE_URL: process.env.EAS_BUILD_COCOAPODS_CACHE_URL,
};

beforeEach(() => {
applyRuntimeSettings(DEFAULT_RUNTIME_SETTINGS);
});

afterEach(() => {
config.sentry.dsn = originalSentryDsn;
restoreEnv('EAS_BUILD_NPM_CACHE_URL', originalCacheUrls.EAS_BUILD_NPM_CACHE_URL);
restoreEnv('NVM_NODEJS_ORG_MIRROR', originalCacheUrls.NVM_NODEJS_ORG_MIRROR);
restoreEnv('EAS_BUILD_MAVEN_CACHE_URL', originalCacheUrls.EAS_BUILD_MAVEN_CACHE_URL);
restoreEnv('EAS_BUILD_COCOAPODS_CACHE_URL', originalCacheUrls.EAS_BUILD_COCOAPODS_CACHE_URL);
mockProcessPlatform(originalPlatform);
resetRuntimeSettings();
jest.restoreAllMocks();
});

Expand Down Expand Up @@ -62,6 +84,200 @@ describe(getBuildEnv.name, () => {
expect(env.EXPO_PRECOMPILED_MODULES_PATH).toBeUndefined();
});

it('adds precompiled modules env vars for iOS jobs when enabled', () => {
applyRuntimeSettings({
caches: {
linux: { npm: true, nodejs: true, maven: true },
darwin: { npm: true, nodejs: true, cocoapods: true },
},
iosPrecompiledModules: true,
});

const env = getBuildEnv({
job: {
platform: Platform.IOS,
type: Workflow.GENERIC,
builderEnvironment: {
env: {},
},
} as any,
projectId: 'project-id',
metadata: {
buildProfile: 'production',
gitCommitHash: 'abc123',
username: 'expo-user',
} as any,
buildId: 'build-id',
});

expect(env.EAS_USE_PRECOMPILED_MODULES).toBe('1');
});

it('does not add precompiled modules env vars for Android jobs when enabled', () => {
applyRuntimeSettings({
caches: {
linux: { npm: true, nodejs: true, maven: true },
darwin: { npm: true, nodejs: true, cocoapods: true },
},
iosPrecompiledModules: true,
});

const env = getBuildEnv({
job: {
platform: Platform.ANDROID,
type: Workflow.MANAGED,
builderEnvironment: {
env: {},
},
username: 'expo-user',
} as any,
projectId: 'project-id',
metadata: {
buildProfile: 'production',
gitCommitHash: 'abc123',
username: 'expo-user',
} as any,
buildId: 'build-id',
});

expect(env.EAS_USE_PRECOMPILED_MODULES).toBeUndefined();
});

it('leaves job-provided precompiled modules env vars in override position', () => {
applyRuntimeSettings({
caches: {
linux: { npm: true, nodejs: true, maven: true },
darwin: { npm: true, nodejs: true, cocoapods: true },
},
iosPrecompiledModules: true,
});

const job = {
platform: Platform.IOS,
type: Workflow.GENERIC,
builderEnvironment: {
env: {
EAS_USE_PRECOMPILED_MODULES: '0',
},
},
} as any;
const baseEnv = getBuildEnv({
job,
projectId: 'project-id',
metadata: {
buildProfile: 'production',
gitCommitHash: 'abc123',
username: 'expo-user',
} as any,
buildId: 'build-id',
});

expect({ ...baseEnv, ...job.builderEnvironment.env }.EAS_USE_PRECOMPILED_MODULES).toBe('0');
});

it('does not expose disabled Linux cache URLs in build env', () => {
mockProcessPlatform('linux');
process.env.EAS_BUILD_NPM_CACHE_URL = 'https://npm.example';
process.env.NVM_NODEJS_ORG_MIRROR = 'https://node.example';
process.env.EAS_BUILD_MAVEN_CACHE_URL = 'https://maven.example';
applyRuntimeSettings({
caches: {
linux: { npm: false, nodejs: false, maven: false },
darwin: { npm: true, nodejs: true, cocoapods: true },
},
iosPrecompiledModules: false,
});

const env = getBuildEnv({
job: {
platform: Platform.ANDROID,
type: Workflow.MANAGED,
builderEnvironment: {
env: {},
},
username: 'expo-user',
} as any,
projectId: 'project-id',
metadata: {
buildProfile: 'production',
gitCommitHash: 'abc123',
username: 'expo-user',
} as any,
buildId: 'build-id',
});

expect(env.NPM_CACHE_URL).toBeUndefined();
expect(env.NVM_NODEJS_ORG_MIRROR).toBeUndefined();
expect(env.EAS_BUILD_NPM_CACHE_URL).toBeUndefined();
expect(env.EAS_BUILD_MAVEN_CACHE_URL).toBeUndefined();
});

it('does not expose disabled Darwin cache URLs in build env', () => {
mockProcessPlatform('darwin');
process.env.EAS_BUILD_NPM_CACHE_URL = 'https://npm.example';
process.env.NVM_NODEJS_ORG_MIRROR = 'https://node.example';
process.env.EAS_BUILD_COCOAPODS_CACHE_URL = 'https://pods.example';
applyRuntimeSettings({
caches: {
linux: { npm: true, nodejs: true, maven: true },
darwin: { npm: false, nodejs: false, cocoapods: false },
},
iosPrecompiledModules: false,
});

const env = getBuildEnv({
job: {
platform: Platform.IOS,
type: Workflow.GENERIC,
builderEnvironment: {
env: {},
},
} as any,
projectId: 'project-id',
metadata: {
buildProfile: 'production',
gitCommitHash: 'abc123',
username: 'expo-user',
} as any,
buildId: 'build-id',
});

expect(env.NPM_CACHE_URL).toBeUndefined();
expect(env.NVM_NODEJS_ORG_MIRROR).toBeUndefined();
expect(env.EAS_BUILD_NPM_CACHE_URL).toBeUndefined();
expect(env.EAS_BUILD_COCOAPODS_CACHE_URL).toBeUndefined();
});

it('exposes enabled cache URLs inferred from worker environment variables', () => {
mockProcessPlatform('linux');
process.env.EAS_BUILD_NPM_CACHE_URL = 'https://npm.example';
process.env.NVM_NODEJS_ORG_MIRROR = 'https://node.example';
process.env.EAS_BUILD_MAVEN_CACHE_URL = 'https://maven.example';

const env = getBuildEnv({
job: {
platform: Platform.ANDROID,
type: Workflow.MANAGED,
builderEnvironment: {
env: {},
},
username: 'expo-user',
} as any,
projectId: 'project-id',
metadata: {
buildProfile: 'production',
gitCommitHash: 'abc123',
username: 'expo-user',
} as any,
buildId: 'build-id',
});

expect(env.NPM_CACHE_URL).toBe('https://npm.example');
expect(env.EAS_BUILD_NPM_CACHE_URL).toBe('https://npm.example');
expect(env.NVM_NODEJS_ORG_MIRROR).toBe('https://node.example');
expect(env.EAS_BUILD_MAVEN_CACHE_URL).toBe('https://maven.example');
});

it('sizes Gradle memory options from total memory', () => {
const totalMemory = jest.spyOn(os, 'totalmem');

Expand All @@ -84,3 +300,18 @@ describe(getBuildEnv.name, () => {
});
});
});

function mockProcessPlatform(platform: NodeJS.Platform): void {
Object.defineProperty(process, 'platform', {
configurable: true,
value: platform,
});
}

function restoreEnv(key: string, value: string | undefined): void {
if (value === undefined) {
delete process.env[key];
} else {
process.env[key] = value;
}
}
103 changes: 101 additions & 2 deletions packages/worker/src/__unit__/runtimeEnvironment.test.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
// @ts-nocheck
import { Android, Ios, Job } from '@expo/eas-build-job';
import templateFile from '@expo/template-file';
import spawn, { SpawnResult } from '@expo/turtle-spawn';
import { pathExists } from 'fs-extra';
import { prepareRuntimeEnvironment } from '../runtimeEnvironment';
import { mkdirp, pathExists } from 'fs-extra';

import config from '../config';
import {
prepareRuntimeEnvironment,
prepareRuntimeEnvironmentConfigFiles,
} from '../runtimeEnvironment';
import { applyRuntimeSettings, resetRuntimeSettings } from '../runtimeSettings';

jest.mock('fs-extra');
jest.mock('@expo/template-file');
jest.mock('@expo/turtle-spawn');

const spawnResult: SpawnResult = {
Expand All @@ -31,10 +39,86 @@ const ctx = {
const builderConfig: Ios.BuilderEnvironment | Android.BuilderEnvironment = {};

describe('prepareRuntimeEnvironment', () => {
const originalEnvironment = config.env;
const originalPlatform = process.platform;
const originalCacheUrls = {
EAS_BUILD_NPM_CACHE_URL: process.env.EAS_BUILD_NPM_CACHE_URL,
EAS_BUILD_MAVEN_CACHE_URL: process.env.EAS_BUILD_MAVEN_CACHE_URL,
};

beforeEach(() => {
jest.mocked(spawn).mockReset();
});

afterEach(() => {
config.env = originalEnvironment;
restoreEnv('EAS_BUILD_NPM_CACHE_URL', originalCacheUrls.EAS_BUILD_NPM_CACHE_URL);
restoreEnv('EAS_BUILD_MAVEN_CACHE_URL', originalCacheUrls.EAS_BUILD_MAVEN_CACHE_URL);
mockProcessPlatform(originalPlatform);
resetRuntimeSettings();
jest.restoreAllMocks();
});

describe(prepareRuntimeEnvironmentConfigFiles.name, () => {
beforeEach(() => {
config.env = 'production';
process.env.EAS_BUILD_NPM_CACHE_URL = 'https://npm.example';
process.env.EAS_BUILD_MAVEN_CACHE_URL = 'https://maven.example';
});

it('does not prepare disabled Linux cache config files', async () => {
mockProcessPlatform('linux');
applyRuntimeSettings({
caches: {
linux: { npm: false, nodejs: true, maven: false },
darwin: { npm: true, nodejs: true, cocoapods: true },
},
iosPrecompiledModules: false,
});

await prepareRuntimeEnvironmentConfigFiles();

expect(spawn).not.toHaveBeenCalledWith('npm', [
'config',
'set',
'registry',
'https://npm.example',
]);
expect(templateFile).not.toHaveBeenCalled();
expect(mkdirp).not.toHaveBeenCalled();
});

it('prepares enabled Linux cache config files', async () => {
mockProcessPlatform('linux');
applyRuntimeSettings({
caches: {
linux: { npm: true, nodejs: true, maven: true },
darwin: { npm: true, nodejs: true, cocoapods: true },
},
iosPrecompiledModules: false,
});

await prepareRuntimeEnvironmentConfigFiles();

expect(spawn).toHaveBeenCalledWith('npm', [
'config',
'set',
'registry',
'https://npm.example',
]);
expect(templateFile).toHaveBeenCalledWith(
expect.stringContaining('yarnrc.yml'),
{ URL: 'https://npm.example' },
expect.stringContaining('.yarnrc.yml')
);
expect(templateFile).toHaveBeenCalledWith(
expect.stringContaining('init.gradle'),
{ URL: 'https://maven.example' },
expect.stringContaining('init.gradle')
);
});
});

describe('installNode', () => {
describe('prepareRuntimeEnvironment', () => {
beforeEach(() => {
Expand Down Expand Up @@ -188,3 +272,18 @@ describe('prepareRuntimeEnvironment', () => {
});
});
});

function mockProcessPlatform(platform: NodeJS.Platform): void {
Object.defineProperty(process, 'platform', {
configurable: true,
value: platform,
});
}

function restoreEnv(key: string, value: string | undefined): void {
if (value === undefined) {
delete process.env[key];
} else {
process.env[key] = value;
}
}
Loading
Loading