@@ -4,13 +4,22 @@ import {
44 githubWebhookPullRequestPayloadSchema ,
55 githubWebhookPushPayloadSchema ,
66} from "@verge/contracts" ;
7- import { createEventIngestion , getRepositoryBySlug } from "@verge/db" ;
7+ import {
8+ createEventIngestion ,
9+ getRepositoryBySlug ,
10+ getRepositoryDefinitionBySlug ,
11+ } from "@verge/db" ;
812
913import type { ApiContext } from "../context.js" ;
1014import { createPlannedRun } from "../planning.js" ;
1115import { collectChangedFilesFromPushPayload , validateGitHubSignature } from "../utils.js" ;
1216
1317export const registerWebhookRoutes = ( app : FastifyInstance , context : ApiContext ) : void => {
18+ const deriveRepositorySlug = ( fullName : string ) : string => {
19+ const segments = fullName . split ( "/" ) ;
20+ return segments [ segments . length - 1 ] ?? fullName ;
21+ } ;
22+
1423 app . post ( "/webhooks/github" , { config : { rawBody : true } } , async ( request , reply ) => {
1524 const deliveryId = String ( request . headers [ "x-github-delivery" ] ?? "" ) ;
1625 const eventName = String ( request . headers [ "x-github-event" ] ?? "" ) ;
@@ -34,38 +43,75 @@ export const registerWebhookRoutes = (app: FastifyInstance, context: ApiContext)
3443 return reply . code ( 401 ) . send ( { message : "Invalid webhook signature" } ) ;
3544 }
3645
37- const repository = await getRepositoryBySlug ( context . connection . db , context . repositorySlug ) ;
38- if ( ! repository ) {
39- return reply . code ( 404 ) . send ( { message : "Repository not found" } ) ;
40- }
41-
42- const result = await context . connection . db . transaction ( ) . execute ( async ( trx ) => {
43- const { eventIngestion, inserted } = await createEventIngestion ( trx , {
44- repositoryId : repository . id ,
45- source : "github" ,
46- deliveryId,
47- eventName,
48- payload : request . body ,
49- } ) ;
46+ if ( eventName === "push" ) {
47+ const payload = githubWebhookPushPayloadSchema . parse ( request . body ) ;
48+ const repositorySlug = deriveRepositorySlug ( payload . repository . full_name ) ;
49+ const repository = await getRepositoryBySlug ( context . connection . db , repositorySlug ) ;
50+ const repositoryDefinition = await getRepositoryDefinitionBySlug (
51+ context . connection . db ,
52+ repositorySlug ,
53+ ) ;
5054
51- if ( ! inserted ) {
52- return { duplicate : true } as const ;
55+ if ( ! repository || ! repositoryDefinition ) {
56+ return reply . code ( 404 ) . send ( { message : "Repository not found" } ) ;
5357 }
5458
55- if ( eventName === "push" ) {
56- const payload = githubWebhookPushPayloadSchema . parse ( request . body ) ;
57- await createPlannedRun ( trx , repository , context . repositoryDefinition , {
59+ const result = await context . connection . db . transaction ( ) . execute ( async ( trx ) => {
60+ const { eventIngestion, inserted } = await createEventIngestion ( trx , {
61+ repositoryId : repository . id ,
62+ source : "github" ,
63+ deliveryId,
64+ eventName,
65+ payload : request . body ,
66+ } ) ;
67+
68+ if ( ! inserted ) {
69+ return { duplicate : true } as const ;
70+ }
71+
72+ await createPlannedRun ( trx , repository , repositoryDefinition , {
5873 trigger : "push" ,
5974 commitSha : payload . after ,
6075 branch : payload . ref . replace ( "refs/heads/" , "" ) ,
6176 changedFiles : collectChangedFilesFromPushPayload ( payload ) ,
6277 eventIngestionId : eventIngestion . id ,
6378 } ) ;
6479 return { duplicate : false , trigger : "push" } as const ;
80+ } ) ;
81+
82+ if ( result . duplicate ) {
83+ return reply . code ( 202 ) . send ( { ok : true , duplicate : true } ) ;
6584 }
6685
67- if ( eventName === "pull_request" ) {
68- const payload = githubWebhookPullRequestPayloadSchema . parse ( request . body ) ;
86+ return reply . code ( 202 ) . send ( { ok : true , ...result } ) ;
87+ }
88+
89+ if ( eventName === "pull_request" ) {
90+ const payload = githubWebhookPullRequestPayloadSchema . parse ( request . body ) ;
91+ const repositorySlug = deriveRepositorySlug ( payload . repository . full_name ) ;
92+ const repository = await getRepositoryBySlug ( context . connection . db , repositorySlug ) ;
93+ const repositoryDefinition = await getRepositoryDefinitionBySlug (
94+ context . connection . db ,
95+ repositorySlug ,
96+ ) ;
97+
98+ if ( ! repository || ! repositoryDefinition ) {
99+ return reply . code ( 404 ) . send ( { message : "Repository not found" } ) ;
100+ }
101+
102+ const result = await context . connection . db . transaction ( ) . execute ( async ( trx ) => {
103+ const { eventIngestion, inserted } = await createEventIngestion ( trx , {
104+ repositoryId : repository . id ,
105+ source : "github" ,
106+ deliveryId,
107+ eventName,
108+ payload : request . body ,
109+ } ) ;
110+
111+ if ( ! inserted ) {
112+ return { duplicate : true } as const ;
113+ }
114+
69115 if ( ! [ "opened" , "reopened" , "synchronize" ] . includes ( payload . action ) ) {
70116 return {
71117 duplicate : false ,
@@ -74,7 +120,7 @@ export const registerWebhookRoutes = (app: FastifyInstance, context: ApiContext)
74120 } as const ;
75121 }
76122
77- await createPlannedRun ( trx , repository , context . repositoryDefinition , {
123+ await createPlannedRun ( trx , repository , repositoryDefinition , {
78124 trigger : "pull_request" ,
79125 commitSha : payload . pull_request . head . sha ,
80126 branch : payload . pull_request . head . ref ,
@@ -83,15 +129,15 @@ export const registerWebhookRoutes = (app: FastifyInstance, context: ApiContext)
83129 eventIngestionId : eventIngestion . id ,
84130 } ) ;
85131 return { duplicate : false , trigger : "pull_request" } as const ;
86- }
132+ } ) ;
87133
88- return { duplicate : false , ignored : true , eventName } as const ;
89- } ) ;
134+ if ( result . duplicate ) {
135+ return reply . code ( 202 ) . send ( { ok : true , duplicate : true } ) ;
136+ }
90137
91- if ( result . duplicate ) {
92- return reply . code ( 202 ) . send ( { ok : true , duplicate : true } ) ;
138+ return reply . code ( 202 ) . send ( { ok : true , ...result } ) ;
93139 }
94140
95- return reply . code ( 202 ) . send ( { ok : true , ... result } ) ;
141+ return reply . code ( 202 ) . send ( { ok : true , ignored : true , eventName } ) ;
96142 } ) ;
97143} ;
0 commit comments