Compare commits

...
Author SHA1 Message Date
Vojtech NovakandKadi Kraman 8ab71f6380 Update CHANGELOG.md
Co-authored-by: Kadi Kraman <[email protected]>
2025-08-13 18:05:43 +02:00
Vojtech Novak 640cbb5283 throw when overriding platform-specific base values 2025-08-13 16:39:43 +02:00
Vojtech Novak be8d777598 [eas-cli] fix disabling cache when extending eas config 2025-08-13 16:11:33 +02:00
3 changed files with 182 additions and 32 deletions

No files matched your search

+2 -1
View File
@@ -12,7 +12,8 @@ This is the log of notable changes to EAS CLI and related packages.
### 🐛 Bug fixes
- Make EXPO_PUBLIC_ env vars plain text, rest sensitive ([#3121](https://github.com/expo/eas-cli/pull/3121) by [@kadikraman](https://github.com/kadikraman))
- Make `EXPO_PUBLIC_` env vars plain text, rest sensitive ([#3121](https://github.com/expo/eas-cli/pull/3121) by [@kadikraman](https://github.com/kadikraman))
- improve `eas.json` config extension handling ([#3143](https://github.com/expo/eas-cli/pull/3143) by [@vonovak](https://github.com/vonovak))
### 🧹 Chores
@@ -5,10 +5,17 @@ import { vol } from 'memfs';
import { EasJsonAccessor } from '../accessor';
import { InvalidEasJsonError } from '../errors';
import { EasJson } from '../types';
import { EasJsonUtils } from '../utils';
jest.mock('fs');
type DeepPartial<T> = T extends object
? {
[P in keyof T]?: DeepPartial<T[P]>;
}
: T;
beforeEach(async () => {
vol.reset();
await fs.mkdirp('/project');
@@ -830,21 +837,15 @@ test('valid build profile with caching without paths', async () => {
'production'
);
expect(androidProfile).toEqual({
const expected = {
distribution: 'store',
credentialsSource: 'remote',
cache: {
disabled: false,
},
});
expect(iosProfile).toEqual({
distribution: 'store',
credentialsSource: 'remote',
cache: {
disabled: false,
},
});
};
expect(androidProfile).toEqual(expected);
expect(iosProfile).toEqual(expected);
});
test('valid build profile with caching with paths', async () => {
@@ -867,23 +868,17 @@ test('valid build profile with caching with paths', async () => {
'production'
);
expect(androidProfile).toEqual({
const expected = {
distribution: 'store',
credentialsSource: 'remote',
cache: {
disabled: false,
paths: ['index.ts'],
},
});
};
expect(androidProfile).toEqual(expected);
expect(iosProfile).toEqual({
distribution: 'store',
credentialsSource: 'remote',
cache: {
disabled: false,
paths: ['index.ts'],
},
});
expect(iosProfile).toEqual(expected);
});
test('valid build profile with caching with customPaths - moved into paths and customPaths removed', async () => {
@@ -906,23 +901,17 @@ test('valid build profile with caching with customPaths - moved into paths and c
'production'
);
expect(androidProfile).toEqual({
const expected = {
distribution: 'store',
credentialsSource: 'remote',
cache: {
disabled: false,
paths: ['index.ts'],
},
});
};
expect(iosProfile).toEqual({
distribution: 'store',
credentialsSource: 'remote',
cache: {
disabled: false,
paths: ['index.ts'],
},
});
expect(androidProfile).toEqual(expected);
expect(iosProfile).toEqual(expected);
});
test('invalid build profile with caching with both paths and customPaths - error thrown', async () => {
@@ -952,3 +941,137 @@ test('invalid build profile with caching with both paths and customPaths - error
await EasJsonUtils.getBuildProfileAsync(accessor, Platform.ANDROID, 'production');
}).rejects.toThrow(expectedError);
});
test('platform-specific setting from base can _not_ be overridden by a setting on the common level', async () => {
const baseConfig = {
ios: {
prebuildCommand: 'ios prebuild',
},
android: {
prebuildCommand: 'android prebuild',
},
};
await fs.writeJson('/project/eas.json', {
build: {
base: baseConfig,
extension1: {
extends: 'base',
prebuildCommand: 'new great prebuild',
},
},
} satisfies DeepPartial<EasJson>);
const accessor = EasJsonAccessor.fromProjectPath('/project');
await expect(() =>
EasJsonUtils.getBuildProfileAsync(accessor, Platform.ANDROID, 'extension1')
).rejects.toThrow(
'Cannot override platform-specific base value "android prebuild" by value "new great prebuild" for key "prebuildCommand". Move the entry out of the "android" object, into the common properties, if you want to override it.'
);
});
describe('extensions can disable cache which is present in base', () => {
test.each([
{
testName: 'platform-specific setting can be disabled',
baseConfig: {
ios: {
cache: {
paths: ['ios-path'],
},
},
android: {
cache: {
paths: ['android-path'],
},
},
},
},
{
testName: 'platform-common setting can be disabled',
baseConfig: {
cache: {
paths: ['common-path'],
},
},
},
])('$testName', async ({ baseConfig }) => {
await fs.writeJson('/project/eas.json', {
build: {
base: baseConfig,
extension1: {
extends: 'base',
cache: {
disabled: true,
},
},
},
} satisfies DeepPartial<EasJson>);
const accessor = EasJsonAccessor.fromProjectPath('/project');
const extendedProfileIos1 = await EasJsonUtils.getBuildProfileAsync(
accessor,
Platform.IOS,
'extension1'
);
const extendedProfileAndroid1 = await EasJsonUtils.getBuildProfileAsync(
accessor,
Platform.ANDROID,
'extension1'
);
const expected = {
cache: {
disabled: true,
},
credentialsSource: 'remote',
distribution: 'store',
};
expect(extendedProfileIos1).toEqual(expected);
expect(extendedProfileAndroid1).toEqual(expected);
});
test('common setting can be disabled per platform', async () => {
await fs.writeJson('/project/eas.json', {
build: {
base: {
cache: {
paths: ['common-path'],
},
},
extension1: {
extends: 'base',
ios: {
cache: {
disabled: true,
},
},
},
},
} satisfies DeepPartial<EasJson>);
const accessor = EasJsonAccessor.fromProjectPath('/project');
const extendedProfileIos1 = await EasJsonUtils.getBuildProfileAsync(
accessor,
Platform.IOS,
'extension1'
);
const extendedProfileAndroid1 = await EasJsonUtils.getBuildProfileAsync(
accessor,
Platform.ANDROID,
'extension1'
);
expect(extendedProfileIos1).toMatchObject({
cache: {
disabled: true,
},
});
expect(extendedProfileAndroid1).toMatchObject({
cache: {
paths: ['common-path'],
},
});
});
});
+27 -1
View File
@@ -3,7 +3,7 @@ import { Platform } from '@expo/eas-build-job';
import { MissingParentProfileError, MissingProfileError } from '../errors';
import { EasJson } from '../types';
import { BuildProfileSchema } from './schema';
import { BuildProfile, EasJsonBuildProfile } from './types';
import { BuildProfile, CommonBuildProfile, EasJsonBuildProfile } from './types';
type EasJsonBuildProfileResolved = Omit<EasJsonBuildProfile, 'extends'>;
@@ -87,6 +87,32 @@ function mergeProfiles(
...update.env,
};
}
if (update?.cache?.disabled) {
delete result.ios?.cache;
delete result.android?.cache;
result.cache = {
disabled: true,
} as CommonBuildProfile['cache'];
}
for (const [key, newValue] of Object.entries(update ?? [])) {
for (const platform of [Platform.ANDROID, Platform.IOS]) {
const platformConfig = base?.[platform];
// @ts-expect-error 'string' can't be used to index type...
const existingValue = platformConfig?.[key];
if (existingValue !== undefined) {
throw new Error(
`Cannot override platform-specific base value ${JSON.stringify(
existingValue
)} by value ${JSON.stringify(
newValue
)} for key "${key}". Move the entry out of the "${platform}" object, into the common properties, if you want to override it.`
);
}
}
}
if (base.android && update.android) {
result.android = mergeProfiles(
base.android as EasJsonBuildProfileResolved,