PR feedback

This commit is contained in:
Frostebite
2025-12-05 18:08:29 +00:00
parent 69731babfc
commit 956b2e4324
8 changed files with 432 additions and 115 deletions

View File

@@ -61,6 +61,7 @@ class KubernetesJobSpecFactory {
backoffLimit: 0,
template: {
spec: {
terminationGracePeriodSeconds: 90, // Give PreStopHook (60s sleep) time to complete
volumes: [
{
name: 'build-mount',

View File

@@ -32,6 +32,9 @@ class KubernetesPods {
);
}
let containerExitCode: number | undefined;
let containerSucceeded = false;
if (containerStatuses.length > 0) {
containerStatuses.forEach((cs, idx) => {
if (cs.state?.waiting) {
@@ -40,10 +43,15 @@ class KubernetesPods {
);
}
if (cs.state?.terminated) {
const exitCode = cs.state.terminated.exitCode;
containerExitCode = exitCode;
if (exitCode === 0) {
containerSucceeded = true;
}
errorDetails.push(
`Container ${idx} (${cs.name}) terminated: ${cs.state.terminated.reason} - ${
cs.state.terminated.message || ''
} (exit code: ${cs.state.terminated.exitCode})`,
} (exit code: ${exitCode})`,
);
}
});
@@ -53,6 +61,25 @@ class KubernetesPods {
errorDetails.push(`Recent events: ${JSON.stringify(events.slice(-5), undefined, 2)}`);
}
// Check if only PreStopHook failed but container succeeded
const hasPreStopHookFailure = events.some((e) => e.reason === 'FailedPreStopHook');
if (containerSucceeded && containerExitCode === 0) {
// Container succeeded - PreStopHook failure is non-critical
if (hasPreStopHookFailure) {
CloudRunnerLogger.logWarning(
`Pod ${podName} marked as Failed due to PreStopHook failure, but container exited successfully (exit code 0). This is non-fatal.`,
);
} else {
CloudRunnerLogger.log(
`Pod ${podName} container succeeded (exit code 0), but pod phase is Failed. Checking details...`,
);
}
CloudRunnerLogger.log(`Pod details: ${errorDetails.join('\n')}`);
// Don't throw error - container succeeded, PreStopHook failure is non-critical
return false; // Pod is not running, but we don't treat it as a failure
}
const errorMessage = `K8s pod failed\n${errorDetails.join('\n')}`;
CloudRunnerLogger.log(errorMessage);
throw new Error(errorMessage);

View File

@@ -334,6 +334,10 @@ export class ContainerHookService {
if (step.image === undefined) {
step.image = `ubuntu`;
}
// Ensure allowFailure defaults to false if not explicitly set
if (step.allowFailure === undefined) {
step.allowFailure = false;
}
}
if (object === undefined) {
throw new Error(`Failed to parse ${steps}`);

View File

@@ -6,4 +6,5 @@ export class ContainerHook {
public name!: string;
public image: string = `ubuntu`;
public hook!: string;
public allowFailure: boolean = false; // If true, hook failures won't stop the build
}

View File

@@ -32,15 +32,33 @@ export class CustomWorkflow {
// }
for (const step of steps) {
CloudRunnerLogger.log(`Cloud Runner is running in custom job mode`);
output += await CloudRunner.Provider.runTaskInWorkflow(
CloudRunner.buildParameters.buildGuid,
step.image,
step.commands,
`/${CloudRunnerFolders.buildVolumeFolder}`,
`/${CloudRunnerFolders.projectPathAbsolute}/`,
environmentVariables,
[...secrets, ...step.secrets],
);
try {
const stepOutput = await CloudRunner.Provider.runTaskInWorkflow(
CloudRunner.buildParameters.buildGuid,
step.image,
step.commands,
`/${CloudRunnerFolders.buildVolumeFolder}`,
`/${CloudRunnerFolders.projectPathAbsolute}/`,
environmentVariables,
[...secrets, ...step.secrets],
);
output += stepOutput;
} catch (error: any) {
const allowFailure = step.allowFailure === true;
const stepName = step.name || step.image || 'unknown';
if (allowFailure) {
CloudRunnerLogger.logWarning(
`Hook container "${stepName}" failed but allowFailure is true. Continuing build. Error: ${error?.message || error}`,
);
// Continue to next step
} else {
CloudRunnerLogger.log(
`Hook container "${stepName}" failed and allowFailure is false (default). Stopping build.`,
);
throw error;
}
}
}
return output;