mirror of
https://github.com/expo/eas-cli.git
synced 2026-11-13 20:28:08 -10:00
Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1222104094 | ||
|
|
0f1fe92a46 | ||
|
|
245942348d | ||
|
|
ae6b38b925 |
No files matched your search
@@ -309,4 +309,217 @@ Refer to "Xcode Logs" below for additional, more detailed logs.`);
|
||||
`Gradle build failed with unknown error. See logs for the "Run gradlew" phase for more information.`
|
||||
);
|
||||
});
|
||||
|
||||
it('detects NPM_ERESOLVE tracking code', async () => {
|
||||
const err = await resolveBuildPhaseErrorAsync(
|
||||
new Error(),
|
||||
[
|
||||
'npm ERR! code ERESOLVE',
|
||||
'npm ERR! ERESOLVE could not resolve',
|
||||
'npm ERR! While resolving: [email protected]',
|
||||
],
|
||||
{
|
||||
job: { platform: Platform.ANDROID } as Job,
|
||||
phase: BuildPhase.INSTALL_DEPENDENCIES,
|
||||
env: {},
|
||||
},
|
||||
'/fake/path'
|
||||
);
|
||||
expect(err.errorCode).toBe(errors.ErrorCode.UNKNOWN_ERROR);
|
||||
expect(err.trackingCode).toBe('NPM_ERESOLVE');
|
||||
});
|
||||
|
||||
it('detects METRO_UNABLE_TO_RESOLVE tracking code', async () => {
|
||||
const err = await resolveBuildPhaseErrorAsync(
|
||||
new Error(),
|
||||
[
|
||||
'error: Unable to resolve module ./src/missing from /home/expo/workingdir/build/index.js: ',
|
||||
'None of these files exist:',
|
||||
],
|
||||
{
|
||||
job: { platform: Platform.ANDROID } as Job,
|
||||
phase: BuildPhase.PREBUILD,
|
||||
env: {},
|
||||
},
|
||||
'/fake/path'
|
||||
);
|
||||
expect(err.errorCode).toBe(errors.ErrorCode.UNKNOWN_ERROR);
|
||||
expect(err.trackingCode).toBe('METRO_UNABLE_TO_RESOLVE');
|
||||
});
|
||||
|
||||
it('detects METRO_UNABLE_TO_RESOLVE without phase restriction', async () => {
|
||||
const err = await resolveBuildPhaseErrorAsync(
|
||||
new Error(),
|
||||
[
|
||||
'error: Unable to resolve module @react-native/assets from /home/expo/workingdir/build/App.js',
|
||||
],
|
||||
{
|
||||
job: { platform: Platform.ANDROID } as Job,
|
||||
phase: BuildPhase.EAGER_BUNDLE,
|
||||
env: {},
|
||||
},
|
||||
'/fake/path'
|
||||
);
|
||||
expect(err.errorCode).toBe(errors.ErrorCode.UNKNOWN_ERROR);
|
||||
expect(err.trackingCode).toBe('METRO_UNABLE_TO_RESOLVE');
|
||||
});
|
||||
|
||||
it('detects PNPM_ERROR tracking code', async () => {
|
||||
const err = await resolveBuildPhaseErrorAsync(
|
||||
new Error(),
|
||||
[
|
||||
' ERR_PNPM_PEER_DEP_ISSUES Unmet peer dependencies',
|
||||
'hint: If you want peer dependencies to be automatically installed, add "auto-install-peers=true" to an .npmrc file.',
|
||||
],
|
||||
{
|
||||
job: { platform: Platform.ANDROID } as Job,
|
||||
phase: BuildPhase.INSTALL_DEPENDENCIES,
|
||||
env: {},
|
||||
},
|
||||
'/fake/path'
|
||||
);
|
||||
expect(err.errorCode).toBe(errors.ErrorCode.UNKNOWN_ERROR);
|
||||
expect(err.trackingCode).toBe('PNPM_ERROR');
|
||||
});
|
||||
|
||||
it('does not detect PNPM_ERROR outside INSTALL_DEPENDENCIES phase', async () => {
|
||||
const err = await resolveBuildPhaseErrorAsync(
|
||||
new Error(),
|
||||
[' ERR_PNPM_PEER_DEP_ISSUES Unmet peer dependencies'],
|
||||
{
|
||||
job: { platform: Platform.ANDROID } as Job,
|
||||
phase: BuildPhase.PREBUILD,
|
||||
env: {},
|
||||
},
|
||||
'/fake/path'
|
||||
);
|
||||
expect(err.errorCode).toBe(errors.ErrorCode.UNKNOWN_ERROR);
|
||||
expect(err.trackingCode).toBeUndefined();
|
||||
});
|
||||
|
||||
it('detects PREBUILD_DANGEROUS_MOD_ENOENT tracking code', async () => {
|
||||
const err = await resolveBuildPhaseErrorAsync(
|
||||
new Error(),
|
||||
[
|
||||
"Error: [android.dangerous]: withAndroidDangerousBaseMod: ENOENT: no such file or directory, open './assets/splash.png'",
|
||||
],
|
||||
{
|
||||
job: { platform: Platform.ANDROID } as Job,
|
||||
phase: BuildPhase.PREBUILD,
|
||||
env: {},
|
||||
},
|
||||
'/fake/path'
|
||||
);
|
||||
expect(err.errorCode).toBe(errors.ErrorCode.UNKNOWN_ERROR);
|
||||
expect(err.trackingCode).toBe('PREBUILD_DANGEROUS_MOD_ENOENT');
|
||||
});
|
||||
|
||||
it('detects PREBUILD_DANGEROUS_MOD_ENOENT for iOS', async () => {
|
||||
const err = await resolveBuildPhaseErrorAsync(
|
||||
new Error(),
|
||||
[
|
||||
"Error: [ios.dangerous]: withIosDangerousBaseMod: ENOENT: no such file or directory, open './assets/fonts/CustomFont.ttf'",
|
||||
],
|
||||
{
|
||||
job: { platform: Platform.IOS } as Job,
|
||||
phase: BuildPhase.PREBUILD,
|
||||
env: {},
|
||||
},
|
||||
'/fake/path'
|
||||
);
|
||||
expect(err.errorCode).toBe(errors.ErrorCode.UNKNOWN_ERROR);
|
||||
expect(err.trackingCode).toBe('PREBUILD_DANGEROUS_MOD_ENOENT');
|
||||
});
|
||||
|
||||
it('detects SYNTAX_ERROR tracking code', async () => {
|
||||
const err = await resolveBuildPhaseErrorAsync(
|
||||
new Error(),
|
||||
['SyntaxError: Unexpected token } in JSON at position 1234'],
|
||||
{
|
||||
job: { platform: Platform.ANDROID } as Job,
|
||||
phase: BuildPhase.PREBUILD,
|
||||
env: {},
|
||||
},
|
||||
'/fake/path'
|
||||
);
|
||||
expect(err.errorCode).toBe(errors.ErrorCode.UNKNOWN_ERROR);
|
||||
expect(err.trackingCode).toBe('SYNTAX_ERROR');
|
||||
});
|
||||
|
||||
it('detects MONOREPO_PACKAGE_JSON_NOT_FOUND tracking code', async () => {
|
||||
const err = await resolveBuildPhaseErrorAsync(
|
||||
new Error(),
|
||||
['Error: package.json does not exist at /home/expo/workingdir/build/packages/app'],
|
||||
{
|
||||
job: { platform: Platform.ANDROID } as Job,
|
||||
phase: BuildPhase.INSTALL_DEPENDENCIES,
|
||||
env: {},
|
||||
},
|
||||
'/fake/path'
|
||||
);
|
||||
expect(err.errorCode).toBe(errors.ErrorCode.UNKNOWN_ERROR);
|
||||
expect(err.trackingCode).toBe('MONOREPO_PACKAGE_JSON_NOT_FOUND');
|
||||
});
|
||||
|
||||
it('detects EXPO_CONFIG_ERROR tracking code', async () => {
|
||||
const err = await resolveBuildPhaseErrorAsync(
|
||||
new Error(),
|
||||
['ConfigError: Property "expo.ios.bundleIdentifier" in app.json is invalid.'],
|
||||
{
|
||||
job: { platform: Platform.IOS } as Job,
|
||||
phase: BuildPhase.PREBUILD,
|
||||
env: {},
|
||||
},
|
||||
'/fake/path'
|
||||
);
|
||||
expect(err.errorCode).toBe(errors.ErrorCode.UNKNOWN_ERROR);
|
||||
expect(err.trackingCode).toBe('EXPO_CONFIG_ERROR');
|
||||
});
|
||||
|
||||
it('detects RUNTIME_VERSION_MISMATCH tracking code', async () => {
|
||||
const err = await resolveBuildPhaseErrorAsync(
|
||||
new Error(),
|
||||
['Error: runtimeVersion in Expo.plist policies must be set to a valid value.'],
|
||||
{
|
||||
job: { platform: Platform.IOS } as Job,
|
||||
phase: BuildPhase.CONFIGURE_EXPO_UPDATES,
|
||||
env: {},
|
||||
},
|
||||
'/fake/path'
|
||||
);
|
||||
expect(err.errorCode).toBe(errors.ErrorCode.UNKNOWN_ERROR);
|
||||
expect(err.trackingCode).toBe('RUNTIME_VERSION_MISMATCH');
|
||||
});
|
||||
|
||||
it('does not detect RUNTIME_VERSION_MISMATCH outside CONFIGURE_EXPO_UPDATES phase', async () => {
|
||||
const err = await resolveBuildPhaseErrorAsync(
|
||||
new Error(),
|
||||
['Error: runtimeVersion in Expo.plist policies must be set to a valid value.'],
|
||||
{
|
||||
job: { platform: Platform.IOS } as Job,
|
||||
phase: BuildPhase.PREBUILD,
|
||||
env: {},
|
||||
},
|
||||
'/fake/path'
|
||||
);
|
||||
expect(err.errorCode).toBe(errors.ErrorCode.UNKNOWN_ERROR);
|
||||
expect(err.trackingCode).toBeUndefined();
|
||||
});
|
||||
|
||||
it('detects CONFIG_PLUGIN_RESOLVE_ERROR tracking code', async () => {
|
||||
const err = await resolveBuildPhaseErrorAsync(
|
||||
new Error(),
|
||||
[
|
||||
'Error: Failed to resolve plugin for module "expo-camera" relative to "/home/expo/workingdir/build"',
|
||||
],
|
||||
{
|
||||
job: { platform: Platform.ANDROID } as Job,
|
||||
phase: BuildPhase.PREBUILD,
|
||||
env: {},
|
||||
},
|
||||
'/fake/path'
|
||||
);
|
||||
expect(err.errorCode).toBe(errors.ErrorCode.UNKNOWN_ERROR);
|
||||
expect(err.trackingCode).toBe('CONFIG_PLUGIN_RESOLVE_ERROR');
|
||||
});
|
||||
});
|
||||
@@ -361,4 +361,69 @@ export const buildErrorHandlers: ErrorHandler<TrackedBuildError>[] = [
|
||||
'fastlane: Bundle React Native code and images failed.'
|
||||
),
|
||||
},
|
||||
// --- Specific patterns for reducing unknown_error bucket ---
|
||||
{
|
||||
phase: BuildPhase.INSTALL_DEPENDENCIES,
|
||||
// npm ERR! ERESOLVE could not resolve
|
||||
regexp: /npm ERR!.*ERESOLVE|ERESOLVE could not resolve/,
|
||||
createError: () => new TrackedBuildError('NPM_ERESOLVE', 'npm: ERESOLVE could not resolve.'),
|
||||
},
|
||||
{
|
||||
phase: BuildPhase.INSTALL_DEPENDENCIES,
|
||||
// ERR_PNPM_PEER_DEP_ISSUES or other pnpm errors
|
||||
regexp: /ERR_PNPM_/,
|
||||
createError: () => new TrackedBuildError('PNPM_ERROR', 'pnpm: error during install.'),
|
||||
},
|
||||
{
|
||||
// Can occur in PREBUILD, EAGER_BUNDLE, or other phases
|
||||
// Unable to resolve module `./src/missing` from `index.js`
|
||||
regexp: /Unable to resolve module/,
|
||||
createError: () =>
|
||||
new TrackedBuildError('METRO_UNABLE_TO_RESOLVE', 'metro: Unable to resolve module.'),
|
||||
},
|
||||
{
|
||||
phase: BuildPhase.PREBUILD,
|
||||
// Error: [android.dangerous]: withAndroidDangerousBaseMod: ENOENT: no such file or directory, open './assets/splash.png'
|
||||
// Must come AFTER EXPO_CLI_MISSING_ICON which matches the icon-specific subset
|
||||
regexp: /with(?:Android|Ios)DangerousBaseMod:.*ENOENT/,
|
||||
createError: () =>
|
||||
new TrackedBuildError(
|
||||
'PREBUILD_DANGEROUS_MOD_ENOENT',
|
||||
'prebuild: ENOENT in dangerous base mod.'
|
||||
),
|
||||
},
|
||||
{
|
||||
// SyntaxError: Unexpected token ...
|
||||
regexp: /SyntaxError:/,
|
||||
createError: () => new TrackedBuildError('SYNTAX_ERROR', 'SyntaxError encountered.'),
|
||||
},
|
||||
{
|
||||
// package.json does not exist (common in monorepos with wrong working directory)
|
||||
regexp: /package\.json does not exist/,
|
||||
createError: () =>
|
||||
new TrackedBuildError('MONOREPO_PACKAGE_JSON_NOT_FOUND', 'package.json does not exist.'),
|
||||
},
|
||||
{
|
||||
// ConfigError: Property ... in app.json is invalid
|
||||
regexp: /ConfigError:/,
|
||||
createError: () => new TrackedBuildError('EXPO_CONFIG_ERROR', 'expo: ConfigError encountered.'),
|
||||
},
|
||||
{
|
||||
phase: BuildPhase.CONFIGURE_EXPO_UPDATES,
|
||||
// runtimeVersion policies must be set ...
|
||||
// runtime version is not equal ...
|
||||
regexp: /runtimeVersion.*policies.*must.*set|runtime version.*not.*equal/i,
|
||||
createError: () =>
|
||||
new TrackedBuildError('RUNTIME_VERSION_MISMATCH', 'expo-updates: runtime version mismatch.'),
|
||||
},
|
||||
{
|
||||
phase: BuildPhase.PREBUILD,
|
||||
// Failed to resolve plugin for module "expo-camera" ...
|
||||
regexp: /Failed to resolve plugin/,
|
||||
createError: () =>
|
||||
new TrackedBuildError(
|
||||
'CONFIG_PLUGIN_RESOLVE_ERROR',
|
||||
'prebuild: Failed to resolve config plugin.'
|
||||
),
|
||||
},
|
||||
];
|
||||
Reference in new issue
Block a user