Skip to content

Commit ae5f557

Browse files
authored
Merge pull request #83 from vercel/fabio/add-cheks-api-example
add example to run the checks api
2 parents 42c22bc + 1addeb8 commit ae5f557

File tree

2 files changed

+102
-20
lines changed

2 files changed

+102
-20
lines changed

app/webhook/route.ts

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ import {
55
type WebhookEvent,
66
webhookEventSchema,
77
} from "@/lib/vercel/schemas";
8-
import { storeWebhookEvent, uninstallInstallation } from "@/lib/partner";
8+
import { listInstallations, storeWebhookEvent, uninstallInstallation } from "@/lib/partner";
9+
import { fetchVercelApi } from "@/lib/vercel/api";
910

1011
export const dynamic = "force-dynamic";
1112

@@ -53,6 +54,63 @@ export async function POST(req: Request): Promise<Response> {
5354
switch (type) {
5455
case "integration-configuration.removed": {
5556
await uninstallInstallation(payload.configuration.id);
57+
break;
58+
}
59+
case "deployment.created": {
60+
const deploymentId = payload.deployment.id
61+
const installationId = await getInstallationId(payload.installationIds)
62+
if (!installationId) {
63+
console.error(`No installations found for deployment ${deploymentId}`, payload)
64+
break;
65+
}
66+
await fetchVercelApi(
67+
`/v1/deployments/${deploymentId}/checks`,
68+
{
69+
data: {
70+
blocking: true,
71+
rerequestable: true,
72+
name: "Test Check",
73+
},
74+
method: "POST",
75+
installationId
76+
},
77+
);
78+
break;
79+
}
80+
case "deployment.ready": {
81+
const deploymentId = payload.deployment.id
82+
const installationId = await getInstallationId(payload.installationIds)
83+
if (!installationId) {
84+
console.error(`No installations found for deployment ${deploymentId}`, payload)
85+
break;
86+
}
87+
88+
const data = (await fetchVercelApi(
89+
`/v1/deployments/${deploymentId}/checks`,
90+
{
91+
method: "get",
92+
installationId
93+
},
94+
)) as { checks: { id: string }[] };
95+
96+
const checkId = data.checks[0]?.id;
97+
98+
if (!checkId) {
99+
console.error(`No Check found for deployment ${deploymentId}`, data)
100+
}
101+
102+
await fetchVercelApi(
103+
`/v1/deployments/${deploymentId}/checks/${data.checks[0]?.id}`,
104+
{
105+
data: {
106+
conclusion: "succeeded",
107+
status: "completed",
108+
},
109+
method: "PATCH",
110+
installationId
111+
},
112+
)
113+
break;
56114
}
57115
}
58116

@@ -65,3 +123,9 @@ function sha1(data: Buffer, secret: string): string {
65123
.update(new Uint8Array(data))
66124
.digest("hex");
67125
}
126+
127+
async function getInstallationId(installationIds: string[] | undefined) {
128+
const installations = await listInstallations()
129+
const installationId = installationIds?.find((id) => installations.includes(id))
130+
return installationId
131+
}

lib/vercel/schemas.ts

Lines changed: 37 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -620,33 +620,44 @@ const integrationConfigurationRemovedWebhookEventSchema =
620620
export type DeploymentIntegrationActionStartEvent = z.infer<
621621
typeof deploymentIntegrationActionStartEventSchema
622622
>;
623+
624+
const deploymentWebhookPayloadEventSchema = z.object({
625+
user: z
626+
.object({
627+
id: z.string(),
628+
})
629+
.passthrough(),
630+
team: z
631+
.object({
632+
id: z.string(),
633+
})
634+
.passthrough(),
635+
installationIds: z.string().array().optional(),
636+
deployment: z
637+
.object({
638+
id: z.string(),
639+
})
640+
.passthrough(),
641+
});
642+
623643
const deploymentIntegrationActionStartEventSchema =
624644
webhookEventBaseSchema.extend({
625645
type: z.literal("deployment.integration.action.start"),
626-
payload: z.object({
627-
user: z
628-
.object({
629-
id: z.string(),
630-
})
631-
.passthrough(),
632-
team: z
633-
.object({
634-
id: z.string(),
635-
})
636-
.passthrough(),
646+
payload: deploymentWebhookPayloadEventSchema.extend({
637647
installationId: z.string(),
638648
action: z.string(),
639-
resourceId: z.string(),
640-
deployment: z
641-
.object({
642-
id: z.string(),
643-
})
644-
.passthrough(),
645-
configuration: z.object({
649+
resourceId: z.string(), configuration: z.object({
646650
id: z.string(),
647651
}),
648-
}),
652+
})
653+
});
654+
655+
const deploymentEvent = <T extends string>(eventType: T) => {
656+
return webhookEventBaseSchema.extend({
657+
type: z.literal(eventType),
658+
payload: deploymentWebhookPayloadEventSchema,
649659
});
660+
}
650661

651662
export type WebhookEvent = z.infer<typeof webhookEventSchema>;
652663
export const webhookEventSchema = z.discriminatedUnion("type", [
@@ -655,6 +666,13 @@ export const webhookEventSchema = z.discriminatedUnion("type", [
655666
invoiceNotPaidWebhookEventSchema,
656667
integrationConfigurationRemovedWebhookEventSchema,
657668
deploymentIntegrationActionStartEventSchema,
669+
deploymentEvent("deployment.created"),
670+
deploymentEvent("deployment.ready"),
671+
deploymentEvent("deployment.promoted"),
672+
deploymentEvent("deployment.succeeded"),
673+
deploymentEvent("deployment.error"),
674+
deploymentEvent("deployment.cancelled"),
675+
deploymentEvent("deployment.check-rerequested"),
658676
]);
659677

660678
export type UnknownWebhookEvent = z.infer<typeof unknownWebhookEventSchema>;

0 commit comments

Comments
 (0)