From 79e2bcb711ba4685cc625fee2d35fb1c44be0ac3 Mon Sep 17 00:00:00 2001 From: Arjun Komath Date: Sat, 29 Aug 2026 08:55:14 +1000 Subject: [PATCH] fix: keep failure notifications concise --- web/lib/notifications/index.ts | 7 +++++-- web/tests/notifications.test.ts | 33 ++++++++++++++++++++++++++++++--- 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/web/lib/notifications/index.ts b/web/lib/notifications/index.ts index f978fc46..70cf50f5 100644 --- a/web/lib/notifications/index.ts +++ b/web/lib/notifications/index.ts @@ -79,14 +79,17 @@ export async function renderInAppNotification(event: NotificationEvent) { if (event.kind === "build.failed") { return { title: `Build failed: ${context.serviceName}`, - body: event.error ?? `A build for ${context.serviceName} failed.`, + body: `A build for ${context.serviceName} failed.`, href: `${serviceHref}/builds/${event.buildId}`, }; } if (event.kind === "cron.failed") { return { title: `Cron failed: ${context.serviceName}`, - body: `${event.path}: ${event.error ?? "Cron request failed"}`, + body: + event.statusCode === null + ? `${event.path} failed.` + : `${event.path} failed with HTTP status ${event.statusCode}.`, href: serviceHref, }; } diff --git a/web/tests/notifications.test.ts b/web/tests/notifications.test.ts index 8450deb6..c09983c5 100644 --- a/web/tests/notifications.test.ts +++ b/web/tests/notifications.test.ts @@ -99,8 +99,8 @@ describe("notification pipeline", () => { ).resolves.toBeNull(); }); - it("renders cron failures with the service deep link", async () => { - mocks.select.mockReturnValueOnce({ + it("omits raw build and cron errors from in-app notifications", async () => { + mocks.select.mockReturnValue({ from: vi.fn(() => ({ innerJoin: vi.fn(() => ({ innerJoin: vi.fn(() => ({ @@ -119,6 +119,19 @@ describe("notification pipeline", () => { })), }); + await expect( + renderInAppNotification({ + kind: "build.failed", + occurrenceId: "build-1", + serviceId: "service-1", + buildId: "build-1", + error: "buildctl failed\n".repeat(1_000), + }), + ).resolves.toEqual({ + title: "Build failed: API", + body: "A build for API failed.", + href: "/dashboard/projects/cloud/production/services/service-1/builds/build-1", + }); await expect( renderInAppNotification({ kind: "cron.failed", @@ -130,7 +143,21 @@ describe("notification pipeline", () => { }), ).resolves.toEqual({ title: "Cron failed: API", - body: "/jobs/nightly: HTTP status 500", + body: "/jobs/nightly failed with HTTP status 500.", + href: "/dashboard/projects/cloud/production/services/service-1", + }); + await expect( + renderInAppNotification({ + kind: "cron.failed", + occurrenceId: "cron-2", + serviceId: "service-1", + path: "/jobs/nightly", + statusCode: null, + error: "Connection refused", + }), + ).resolves.toEqual({ + title: "Cron failed: API", + body: "/jobs/nightly failed.", href: "/dashboard/projects/cloud/production/services/service-1", }); });