// handleEvent is essentially a router: it dispatches based on the event type
// to perform whatever changeset action is appropriate for that event.
handleEvent is essentially a router: it dispatches based on the event type
to perform whatever changeset action is appropriate for that event.
// handleEvent is essentially a router : it dispatches based on the event type // to perform whatever changeset action is appropriate for that event .
func (h *GitLabWebhook) handleEvent(ctx context.Context, extSvc *types.ExternalService, event interface{}) *httpError {
	log15.Debug("GitLab webhook received", "type", fmt.Sprintf("%T", event))
	esID, err := extractExternalServiceID(extSvc)
	if err != nil {
		return &httpError{
			code: http.StatusInternalServerError,
			err:  err,
		}
	}
	switch e := event.(type) {
	 For example, approvals and unapprovals manifest in normal syncs as
	 system notes, but we _don't_ get them as note events in webhooks.
	 Instead, we get a merge request webhook with an "approved" or
	 "unapproved" action field that magically appears in the object (merge
	 request) attributes and no further details on who changed the approval
	 status, the note ID, or anything else we can use to deduplicate later.
	 Similarly, for update events, we don't get the full set of fields that
	 we get when we sync using the REST API (presumably because this reflects
	 the data types at the point webhooks were added to GitLab several years
	 ago, and not today): labels come in a different format outside of the
	 merge request, and we'd still have to go query for notes and pipelines.
	 Therefore, the only realistic action we can take here is to re-sync the
	 changeset as a whole. The problem is that — since we only have the merge
	 request — this requires three requests to the REST API, and GitLab's
	 documentation is quite clear that webhooks should run as fast as possible
	 to avoid unexpected retries.
	 To meet this goal, rather than synchronously synchronizing here, we'll
	 instead ask repo-updater to prioritize the sync of this changeset and let
	 the normal sync process take care of pulling the notes and pipelines and
	 putting things in the right places. The downside is that the updated
	 changeset state won't appear _quite_ as instantaneously to the user, but
	 this is the best compromise given the limited payload we get in the
	 webhook.
	case *webhooks.MergeRequestApprovedEvent,
		*webhooks.MergeRequestUnapprovedEvent,
		*webhooks.MergeRequestUpdateEvent:
		if err := h.enqueueChangesetSyncFromEvent(ctx, esID, e.(webhooks.MergeRequestEventCommonContainer).ToEventCommon()); err != nil {
			return &httpError{
				code: http.StatusInternalServerError,
				err:  err,
			}
		}
		return nil
	case webhooks.UpsertableWebhookEvent:
		eventCommon := e.ToEventCommon()
		event := e.ToEvent()
		pr := gitlabToPR(&eventCommon.Project, eventCommon.MergeRequest)
		if err := h.upsertChangesetEvent(ctx, esID, pr, event); err != nil {
			return &httpError{
				code: http.StatusInternalServerError,
				err:  errors.Wrap(err, "upserting changeset event"),
			}
		}
		return nil
	case *webhooks.PipelineEvent:
		if err := h.handlePipelineEvent(ctx, esID, e); err != nil && err != errPipelineMissingMergeRequest {
			return &httpError{
				code: http.StatusInternalServerError,
				err:  err,
			}
		}
		return nil
	}
	 We don't want to return a non-2XX status code and have GitLab retry the
	 webhook, so we'll log that we don't know what to do and return 204.
	log15.Debug("cannot handle GitLab webhook event of unknown type", "event", event, "type", fmt.Sprintf("%T", event))
	return nil
}
func ( h * GitLabWebhook ) handleEvent ( ctx context . Context , extSvc * types . ExternalService , event interface { } ) * httpError { log15 . Debug ( " " , " " , fmt . Sprintf ( " " , event ) ) esID , err := extractExternalServiceID ( extSvc ) if err != nil { return & httpError { code : http . StatusInternalServerError , err : err , } } switch e := event . ( type ) { case * webhooks . MergeRequestApprovedEvent , * webhooks . MergeRequestUnapprovedEvent , * webhooks . MergeRequestUpdateEvent : if err := h . enqueueChangesetSyncFromEvent ( ctx , esID , e . ( webhooks . MergeRequestEventCommonContainer ) . ToEventCommon ( ) ) ; err != nil { return & httpError { code : http . StatusInternalServerError , err : err , } } return nil case webhooks . UpsertableWebhookEvent : eventCommon := e . ToEventCommon ( ) event := e . ToEvent ( ) pr := gitlabToPR ( & eventCommon . Project , eventCommon . MergeRequest ) if err := h . upsertChangesetEvent ( ctx , esID , pr , event ) ; err != nil { return & httpError { code : http . StatusInternalServerError , err : errors . Wrap ( err , " " ) , } } return nil case * webhooks . PipelineEvent : if err := h . handlePipelineEvent ( ctx , esID , e ) ; err != nil && err != errPipelineMissingMergeRequest { return & httpError { code : http . StatusInternalServerError , err : err , } } return nil } log15 . Debug ( " " , " " , event , " " , fmt . Sprintf ( " " , event ) ) return nil }
handleEvent is essentially a router: it dispatches based on the event type
to perform whatever changeset action is appropriate for that event.
handleEvent is essentially a router : it dispatches based on the event type to perform whatever changeset action is appropriate for that event .
// Some merge request event types require us to do a full resync. // // For example, approvals and unapprovals manifest in normal syncs as // system notes, but we _don't_ get them as note events in webhooks. // Instead, we get a merge request webhook with an "approved" or // "unapproved" action field that magically appears in the object (merge // request) attributes and no further details on who changed the approval // status, the note ID, or anything else we can use to deduplicate later. // // Similarly, for update events, we don't get the full set of fields that // we get when we sync using the REST API (presumably because this reflects // the data types at the point webhooks were added to GitLab several years // ago, and not today): labels come in a different format outside of the // merge request, and we'd still have to go query for notes and pipelines. // // Therefore, the only realistic action we can take here is to re-sync the // changeset as a whole. The problem is that — since we only have the merge // request — this requires three requests to the REST API, and GitLab's // documentation is quite clear that webhooks should run as fast as possible // to avoid unexpected retries. // // To meet this goal, rather than synchronously synchronizing here, we'll // instead ask repo-updater to prioritize the sync of this changeset and let // the normal sync process take care of pulling the notes and pipelines and // putting things in the right places. The downside is that the updated // changeset state won't appear _quite_ as instantaneously to the user, but // this is the best compromise given the limited payload we get in the // webhook. // We don't want to return a non-2XX status code and have GitLab retry the // webhook, so we'll log that we don't know what to do and return 204.