mirror of
https://github.com/harness/drone.git
synced 2025-05-06 05:40:32 +08:00

This change includes: - webhook event processor (includes actual webhook execution) - webhook retrigger API allowing to retrigger previous webhook executions
89 lines
3.1 KiB
Go
89 lines
3.1 KiB
Go
// Copyright 2022 Harness Inc. All rights reserved.
|
|
// Use of this source code is governed by the Polyform Free Trial License
|
|
// that can be found in the LICENSE.md file for this repository.
|
|
|
|
package webhook
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
|
|
"github.com/harness/gitness/internal/store"
|
|
"github.com/harness/gitness/types"
|
|
"github.com/harness/gitness/types/enum"
|
|
|
|
"github.com/rs/zerolog/log"
|
|
"go.uber.org/multierr"
|
|
)
|
|
|
|
func generateTriggerIDFromEventID(eventID string) string {
|
|
return fmt.Sprintf("event-%s", eventID)
|
|
}
|
|
|
|
func triggerForEventWithGitUID(ctx context.Context, server *Server, repoStore store.RepoStore, eventID string,
|
|
repoGitUID string, triggerType enum.WebhookTrigger, createBody func(*types.Repository) interface{}) error {
|
|
// TODO: can we avoid this DB call? would need the gitrpc to know the repo id though ...
|
|
repo, err := repoStore.FindByGitUID(ctx, repoGitUID)
|
|
|
|
// not found error is unrecoverable - most likely a racing condition of repo being deleted by now
|
|
if err != nil && errors.Is(err, store.ErrResourceNotFound) {
|
|
log.Ctx(ctx).Warn().Err(err).
|
|
Msgf("discard event since repo with gitUID '%s' doesn't exist anymore", repoGitUID)
|
|
return nil
|
|
}
|
|
|
|
// all other errors we return and force the event to be reprocessed
|
|
if err != nil {
|
|
return fmt.Errorf("failed to get repo for gitUID '%s': %w", repoGitUID, err)
|
|
}
|
|
|
|
body := createBody(repo)
|
|
return triggerForEvent(ctx, server, eventID, enum.WebhookParentRepo, repo.ID, triggerType, body)
|
|
}
|
|
|
|
func triggerForEvent(ctx context.Context, server *Server, eventID string,
|
|
parentType enum.WebhookParent, parentID int64, triggerType enum.WebhookTrigger, body interface{}) error {
|
|
triggerID := generateTriggerIDFromEventID(eventID)
|
|
|
|
results, err := server.triggerWebhooksFor(ctx, parentType, parentID, triggerID, triggerType, body)
|
|
|
|
// return all errors and force the event to be reprocessed (it's not webhook execution specific!)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to trigger %s (id: '%s') for webhooks of %s %d: %w",
|
|
triggerType, triggerID, parentType, parentID, err)
|
|
}
|
|
|
|
// go through all events and figure out if we need to retry the event.
|
|
// Combine all errors into a single error to log (to reduce number of logs)
|
|
retryRequired := false
|
|
var errs error
|
|
for _, result := range results {
|
|
if result.Skipped() {
|
|
continue
|
|
}
|
|
|
|
// combine errors of non-successful executions
|
|
if result.Execution.Result != enum.WebhookExecutionResultSuccess {
|
|
errs = multierr.Append(errs, fmt.Errorf("execution %d of webhook %d resulted in %s: %w",
|
|
result.Execution.ID, result.Webhook.ID, result.Execution.Result, result.Err))
|
|
}
|
|
|
|
if result.Execution.Result == enum.WebhookExecutionResultRetriableError {
|
|
retryRequired = true
|
|
}
|
|
}
|
|
|
|
// in case there was at least one error, log error details in single log to reduce log flooding
|
|
if errs != nil {
|
|
log.Ctx(ctx).Warn().Err(errs).Msgf("webhook execution for %s %d had errors", parentType, parentID)
|
|
}
|
|
|
|
// in case at least one webhook has to be retried, return an error to the event framework to have it reprocessed
|
|
if retryRequired {
|
|
return fmt.Errorf("at least one webhook execution resulted in a retry for %s %d", parentType, parentID)
|
|
}
|
|
|
|
return nil
|
|
}
|