Compare commits

...
7 changed files with 71 additions and 14 deletions

No files matched your search

@@ -1,4 +1,4 @@
import { BuildTrigger, Job, Metadata } from '@expo/eas-build-job';
import { BuildPhase, BuildTrigger, Job, Metadata } from '@expo/eas-build-job';
import { randomUUID } from 'crypto';
import { vol } from 'memfs';
@@ -116,4 +116,30 @@ describe('BuildContext', () => {
foo: 'bar',
});
});
it('should use a custom phase display name for logger metadata', async () => {
const logger = createMockLogger();
const ctx = new BuildContext(
{
triggeredBy: BuildTrigger.EAS_CLI,
} as Job,
{
env: {
__API_SERVER_URL: 'http://api.expo.test',
},
workingdir: '/workingdir',
logger,
logBuffer: { getLogs: () => [], getPhaseLogs: () => [] },
uploadArtifact: jest.fn(),
}
);
(jest.spyOn(ctx as any, 'collectAndUpdateEnvVariablesAsync') as any).mockResolvedValue(
undefined
);
await ctx.runBuildPhase('Configure Android version', async () => undefined);
expect(logger.child).toHaveBeenCalledWith({ phase: 'Configure Android version' });
});
});
@@ -12,6 +12,23 @@ afterEach(() => {
});
describe(resolveBuildPhaseErrorAsync, () => {
it('omits non-enum buildPhase on the returned build error', async () => {
const fakeError = new Error();
const err = await resolveBuildPhaseErrorAsync(
fakeError,
['some log line'],
{
job: { platform: Platform.ANDROID } as Job,
phase: 'Configure Android version',
env: {},
},
'/fake/path'
);
expect(err.errorCode).toBe(errors.ErrorCode.UNKNOWN_ERROR);
expect(err.buildPhase).toBeUndefined();
});
it('detects log for corrupted npm package', async () => {
const fakeError = new Error();
const err = await resolveBuildPhaseErrorAsync(
@@ -1,4 +1,4 @@
import { BuildPhase, errors } from '@expo/eas-build-job';
import { BuildPhase, errors, isBuildPhase } from '@expo/eas-build-job';
import fs from 'fs-extra';
import { buildErrorHandlers } from './buildErrorHandlers';
@@ -7,7 +7,7 @@ import { userErrorHandlers } from './userErrorHandlers';
import { findXcodeBuildLogsPathAsync } from '../ios/xcodeBuildLogs';
async function maybeReadXcodeBuildLogs(
phase: BuildPhase,
phase: BuildPhase | string | undefined,
buildLogsDirectory: string
): Promise<string | undefined> {
if (phase !== BuildPhase.RUN_FASTLANE) {
@@ -77,7 +77,7 @@ export async function resolveBuildPhaseErrorAsync(
error instanceof errors.UserFacingError
? error
: (resolveError(userErrorHandlers, logLines, errorContext, xcodeBuildLogs) ??
new errors.UnknownError(errorContext.phase));
new errors.UnknownError(phase));
const buildError = resolveError(buildErrorHandlers, logLines, errorContext, xcodeBuildLogs);
const trackingCode =
@@ -90,7 +90,7 @@ export async function resolveBuildPhaseErrorAsync(
trackingCode,
docsUrl: userFacingError.docsUrl,
cause: error,
buildPhase: phase,
...(phase && isBuildPhase(phase) ? { buildPhase: phase } : {}),
metadata: buildError?.metadata,
});
}
@@ -1,7 +1,7 @@
import { BuildMode, BuildPhase, Env, Job, Platform } from '@expo/eas-build-job';
export interface ErrorContext<TJob extends Job = Job> {
phase: BuildPhase;
phase: BuildPhase | string;
job: TJob;
env: Env;
}
+13 -5
View File
@@ -11,6 +11,7 @@ import {
ManagedArtifactType,
Metadata,
errors,
isBuildPhase,
isGenericArtifact,
} from '@expo/eas-build-job';
import { BuildTrigger } from '@expo/eas-build-job/dist/common';
@@ -91,7 +92,7 @@ export class BuildContext<TJob extends Job = Job> {
private _metadata?: Metadata;
private readonly defaultLogger: bunyan;
private readonly _uploadArtifact: BuildContextOptions['uploadArtifact'];
private buildPhase?: BuildPhase;
private buildPhase?: BuildPhase | string;
private buildPhaseSkipped = false;
private buildPhaseHasWarnings = false;
private _appConfig?: ExpoConfig;
@@ -185,7 +186,7 @@ export class BuildContext<TJob extends Job = Job> {
}
public async runBuildPhase<T>(
buildPhase: BuildPhase,
buildPhase: BuildPhase | string,
phase: () => Promise<T>,
{
doNotMarkStart = false,
@@ -283,7 +284,7 @@ export class BuildContext<TJob extends Job = Job> {
private async handleBuildPhaseErrorAsync(
err: any,
buildPhase: BuildPhase
buildPhase: BuildPhase | string
): Promise<errors.BuildError> {
const buildError = await resolveBuildPhaseErrorAsync(
err,
@@ -316,7 +317,7 @@ export class BuildContext<TJob extends Job = Job> {
return path.join(baseDirectory, this.job.projectRootDirectory ?? '.');
}
private setBuildPhase(buildPhase: BuildPhase, { doNotMarkStart = false } = {}): void {
private setBuildPhase(buildPhase: BuildPhase | string, { doNotMarkStart = false } = {}): void {
if (this.buildPhase) {
if (this.buildPhase === buildPhase) {
return;
@@ -349,7 +350,14 @@ export class BuildContext<TJob extends Job = Job> {
}
await this.collectAndUpdateEnvVariablesAsync();
this.reportBuildPhaseStats?.({ buildPhase: this.buildPhase, result, durationMs });
const buildPhase = this.buildPhase;
if (isBuildPhase(buildPhase)) {
this.reportBuildPhaseStats?.({
buildPhase,
result,
durationMs,
});
}
if (!doNotMarkEnd) {
this.logger.info(
+3 -3
View File
@@ -1,4 +1,4 @@
import { BuildPhase, buildPhaseDisplayName } from './logs';
import { BuildPhase, buildPhaseDisplayName, isBuildPhase } from './logs';
export enum ErrorCode {
UNKNOWN_ERROR = 'UNKNOWN_ERROR',
@@ -94,11 +94,11 @@ export class UserFacingError<
}
export class UnknownError extends UserFacingError {
constructor(buildPhase?: BuildPhase) {
constructor(buildPhase?: BuildPhase | string) {
super(
ErrorCode.UNKNOWN_ERROR,
buildPhase
? `Unknown error. See logs of the ${buildPhaseDisplayName[buildPhase]} build phase for more information.`
? `Unknown error. See logs of the ${isBuildPhase(buildPhase) ? buildPhaseDisplayName[buildPhase] : buildPhase} build phase for more information.`
: 'Unknown error. See logs for more information.'
);
}
+6
View File
@@ -59,6 +59,12 @@ export enum BuildPhase {
COMPLETE_JOB = 'COMPLETE_JOB',
}
const buildPhaseValues = new Set<string>(Object.values(BuildPhase));
export function isBuildPhase(value: string): value is BuildPhase {
return buildPhaseValues.has(value);
}
export enum SubmissionPhase {
SPIN_UP_SUBMISSION_WORKER = 'SPIN_UP_SUBMISSION_WORKER',
SUBMIT_TO_PLAY_STORE = 'SUBMIT_TO_PLAY_STORE',