Skip to content

Commit a087060

Browse files
authored
feat(core): emit deploy run results to Garden Cloud (#7781)
With this change we include the results with the ACTION_RUN_COMPLETED event if the action kind is Deploy. This enables us display links to ingresses in the Garden Cloud UI. The plan was also to include kind specific state such as whether a Test action was cached in team or local cache but that's a bigger lift and will need be handled in a separate PR. The protobuf schema already accounts for those fields as well though.
1 parent 3076baf commit a087060

File tree

6 files changed

+114
-7
lines changed

6 files changed

+114
-7
lines changed

core/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
"types": "build/src/index.d.ts",
2727
"dependencies": {
2828
"@bufbuild/protobuf": "2.8.0",
29-
"@buf/garden_grow-platform.bufbuild_es": "2.8.0-20250916142245-2420a337ce6a.1",
29+
"@buf/garden_grow-platform.bufbuild_es": "2.8.0-20251027135652-778164cdd988.1",
3030
"@codenamize/codenamize": "^1.1.1",
3131
"@connectrpc/connect": "2.1.0",
3232
"@connectrpc/connect-node": "2.0.4",
@@ -279,4 +279,4 @@
279279
"fsevents": "^2.3.3"
280280
},
281281
"gitHead": "b0647221a4d2ff06952bae58000b104215aed922"
282-
}
282+
}

core/src/cloud/api/grpc-event-converter.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import {
3434
GardenCommandExecutionStartedSchema,
3535
} from "@buf/garden_grow-platform.bufbuild_es/garden/public/events/v1/garden_command_pb.js"
3636
import { timestampFromDate } from "@bufbuild/protobuf/wkt"
37+
import type { DeployRunResult } from "@buf/garden_grow-platform.bufbuild_es/garden/public/events/v1/garden_action_pb.js"
3738
import {
3839
GardenActionGetStatusCompletedSchema,
3940
GardenActionGetStatusStartedSchema,
@@ -43,7 +44,10 @@ import {
4344
GardenActionRunCompletedSchema,
4445
GardenActionRunStartedSchema,
4546
GardenActionScannedSchema,
47+
ServiceIngressSchema,
48+
DeployRunResultSchema,
4649
} from "@buf/garden_grow-platform.bufbuild_es/garden/public/events/v1/garden_action_pb.js"
50+
import type { DeployStatusForEventPayload } from "../../types/service.js"
4751

4852
const nextEventUlid = monotonicFactory()
4953

@@ -233,13 +237,44 @@ export class GrpcEventConverter {
233237
}),
234238
]
235239
} else if (payload.operation === "process") {
240+
const actionKind = payload.actionKind
241+
242+
let deployRunResult: DeployRunResult | undefined = undefined
243+
244+
if (actionKind === "deploy" && "status" in payload && payload.status) {
245+
const deployStatus = payload.status as DeployStatusForEventPayload
246+
247+
deployRunResult = create(DeployRunResultSchema, {
248+
createdAt: deployStatus.createdAt,
249+
mode: deployStatus.mode,
250+
externalId: deployStatus.externalId,
251+
externalVersion: deployStatus.externalVersion,
252+
ingresses:
253+
deployStatus.ingresses?.map((ingress) =>
254+
create(ServiceIngressSchema, {
255+
hostname: ingress.hostname,
256+
linkUrl: ingress.linkUrl,
257+
path: ingress.path || "/",
258+
port: ingress.port,
259+
protocol: ingress.protocol,
260+
})
261+
) || [],
262+
lastMessage: deployStatus.lastMessage,
263+
lastError: deployStatus.lastError,
264+
runningReplicas: deployStatus.runningReplicas,
265+
updatedAt: deployStatus.updatedAt,
266+
})
267+
}
268+
236269
return [
237270
createGardenCliEvent(context, GardenCliEventType.ACTION_RUN_COMPLETED, {
238271
case: "actionRunCompleted",
239272
value: create(GardenActionRunCompletedSchema, {
240273
actionUlid: this.mapToUlid(payload.actionUid, "actionUid", "actionUlid"),
241274
completedAt: timestampFromDate(new Date()),
242275
success: !["not-ready", "failed", "unknown"].includes(payload.state),
276+
// This is undefined for non-Deploy actions
277+
deployRunResult,
243278
}),
244279
}),
245280
]

core/src/events/action-status-events.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
77
*/
88

9+
import type { ActionKind } from "../actions/types.js"
910
import { actionStates } from "../actions/types.js"
1011
import type { BuildState } from "../plugin/handlers/Build/get-status.js"
1112
import type { ActionRuntime, RunState } from "../plugin/plugin.js"
@@ -94,7 +95,7 @@ interface ActionStatusPayloadBase {
9495
* should've been actionKind.
9596
*/
9697
actionType: string
97-
actionKind: string
98+
actionKind: Lowercase<ActionKind>
9899
actionVersion: string
99100
actionUid: string
100101
/**

core/src/events/util.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ export function makeActionStatusPayloadBase({
7878
actionName: action.name,
7979
actionVersion: action.versionString(log),
8080
// NOTE: The type/kind needs to be lower case in the event payload
81-
actionKind: action.kind.toLowerCase(),
81+
actionKind: action.kind.toLowerCase() as Lowercase<ActionKind>,
8282
actionType: action.type,
8383
actionUid: action.uid,
8484
moduleName: action.moduleName(),

core/test/unit/src/cloud/grpc-event-stream.ts

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import type { Log } from "../../../../src/logger/log-entry.js"
2020
import { getRootLogger } from "../../../../src/logger/logger.js"
2121
import { makeTestGardenA } from "../../../helpers.js"
2222
import { sleep } from "../../../../src/util/util.js"
23+
import type { GardenActionRunCompleted } from "@buf/garden_grow-platform.bufbuild_es/garden/public/events/v1/garden_action_pb.js"
2324

2425
const receivedEvents = new Array<Event>()
2526
// if this is true, the mock backend will simulate failures.
@@ -187,6 +188,76 @@ describe("GrpcEventStream", () => {
187188
expect(event.eventData.value).to.be.an("object")
188189
})
189190

191+
it("should include Deploy process result when applicable", async () => {
192+
garden.events.emit("deployStatus", {
193+
startedAt: new Date().toISOString(),
194+
completedAt: new Date().toISOString(),
195+
state: "ready",
196+
status: {
197+
createdAt: new Date().toISOString(),
198+
mode: "sync",
199+
externalId: "fake-external-id",
200+
externalVersion: "fake-external-version",
201+
forwardablePorts: [],
202+
ingresses: [
203+
{
204+
hostname: "fake-hostname",
205+
linkUrl: "fake-link-url",
206+
path: "/",
207+
port: 443,
208+
protocol: "https",
209+
},
210+
],
211+
lastMessage: "hello",
212+
lastError: "goodbye",
213+
outputs: {},
214+
runningReplicas: 3,
215+
state: "ready",
216+
updatedAt: new Date().toISOString(),
217+
},
218+
actionName: "api",
219+
actionKind: "deploy",
220+
actionType: "kubernetes",
221+
actionUid: "fake-action-uid",
222+
sessionId: "fake-session-id",
223+
operation: "process",
224+
force: false,
225+
actionVersion: "foobar",
226+
moduleName: null,
227+
runtime: undefined,
228+
})
229+
await bufferedEventStream.close()
230+
expect(receivedEvents.length).to.equal(1)
231+
const event = receivedEvents[0]
232+
233+
const eventPayload = event.eventData.value?.eventData.value as GardenActionRunCompleted
234+
235+
expect(event.eventUlid).to.be.a("string")
236+
expect(event.eventData).to.be.an("object")
237+
expect(eventPayload.deployRunResult).to.be.an("object")
238+
expect(eventPayload.deployRunResult).to.eql({
239+
$typeName: eventPayload.deployRunResult?.$typeName,
240+
ingresses: [
241+
{
242+
$typeName: eventPayload.deployRunResult?.ingresses[0].$typeName,
243+
hostname: "fake-hostname",
244+
linkUrl: "fake-link-url",
245+
path: "/",
246+
port: 443,
247+
protocol: "https",
248+
},
249+
],
250+
createdAt: eventPayload.deployRunResult?.createdAt,
251+
mode: "sync",
252+
externalId: "fake-external-id",
253+
externalVersion: "fake-external-version",
254+
lastMessage: "hello",
255+
lastError: "goodbye",
256+
runningReplicas: 3,
257+
updatedAt: eventPayload.deployRunResult?.updatedAt,
258+
})
259+
})
260+
190261
it("should send events in the correct order even when facing transient failures", async () => {
191262
// Simulate unreliable backend
192263
simulateUnreliableBackend = true

package-lock.json

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)