Skip to content

Commit efecb68

Browse files
committed
Ensure error message for failed slices stay within the slice
1 parent 686963b commit efecb68

File tree

3 files changed

+32
-17
lines changed

3 files changed

+32
-17
lines changed

.werft/build.ts

+7-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as fs from "fs";
22
import { SpanStatusCode } from "@opentelemetry/api";
3-
import { Werft } from "./util/werft";
3+
import { FailedSliceError, Werft } from "./util/werft";
44
import { reportBuildFailureInSlack } from "./util/slack";
55
import * as Tracing from "./observability/tracing";
66
import * as VM from "./vm/vm";
@@ -27,7 +27,12 @@ Tracing.initialize()
2727
message: err,
2828
});
2929

30-
console.log("Error", err);
30+
if (err instanceof FailedSliceError) {
31+
// This error was produced using werft.fail which means that we
32+
// already handled it "gracefully"
33+
} else {
34+
console.log("Error", err);
35+
}
3136

3237
if (context.Repository.ref === "refs/heads/main") {
3338
reportBuildFailureInSlack(context, err).catch((error: Error) => {

.werft/jobs/build/validate-changes.ts

+6-11
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,12 @@ import { JobConfig } from "./job-config";
44

55
export async function validateChanges(werft: Werft, config: JobConfig) {
66
werft.phase("validate-changes", "validating changes");
7-
try {
8-
await Promise.all([
9-
branchNameCheck(werft, config),
10-
preCommitCheck(werft),
11-
typecheckWerftJobs(werft),
12-
leewayVet(werft),
13-
]);
14-
} catch (err) {
15-
werft.fail("validate-changes", err);
16-
}
17-
werft.done("validate-changes");
7+
await Promise.all([
8+
branchNameCheck(werft, config),
9+
preCommitCheck(werft),
10+
typecheckWerftJobs(werft),
11+
leewayVet(werft),
12+
]);
1813
}
1914

2015
// Branch names cannot be longer than 45 characters.

.werft/util/werft.ts

+19-4
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,14 @@ import { exec } from "./shell";
33

44
let werft: Werft;
55

6+
export class FailedSliceError extends Error {
7+
constructor(message: string) {
8+
super(message);
9+
this.name = "FailedSliceError";
10+
Object.setPrototypeOf(this, FailedSliceError.prototype);
11+
}
12+
}
13+
614
/**
715
* For backwards compatibility with existing code we expose a global Werft instance
816
*/
@@ -75,7 +83,7 @@ export class Werft {
7583
/**
7684
* Use this when you intend to fail the werft job
7785
*/
78-
public fail(slice, err) {
86+
public fail(slice: string, err: string | Error) {
7987
const span = this.sliceSpans[slice];
8088

8189
if (span) {
@@ -84,6 +92,8 @@ export class Werft {
8492
console.log(`[${slice}] tracing warning: No slice span by name ${slice}`);
8593
}
8694

95+
const errorMessage = err instanceof Error ? err.toString() : err;
96+
8797
// Set the status on the span for the slice and also propagate the status to the phase and root span
8898
// as well so we can query on all phases that had an error regardless of which slice produced the error.
8999
[span, this.rootSpan, this.currentPhaseSpan].forEach((span: Span) => {
@@ -92,12 +102,17 @@ export class Werft {
92102
}
93103
span.setStatus({
94104
code: SpanStatusCode.ERROR,
95-
message: err,
105+
message: errorMessage,
96106
});
97107
});
98108

99-
console.log(`[${slice}|FAIL] ${err}`);
100-
throw err;
109+
// In case the error message is a multi-line string we want to ensure that we contain
110+
// the error message within the slice (otherwise they'll be moved to the "default" slice of the phase)
111+
errorMessage.split("\n").forEach((line: string) => console.log(`[${slice}] ${line}`));
112+
113+
console.log(`[${slice}] Failed. Expand to see why`);
114+
console.log(`[${slice}|FAIL]`);
115+
throw new FailedSliceError(slice);
101116
}
102117

103118
/**

0 commit comments

Comments
 (0)