mirror of https://github.com/harness/drone.git
258 lines
8.7 KiB
Go
258 lines
8.7 KiB
Go
// Copyright 2023 Harness, Inc.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package webhook
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
gitnesswebhook "github.com/harness/gitness/app/services/webhook"
|
|
"github.com/harness/gitness/events"
|
|
"github.com/harness/gitness/registry/app/api/openapi/contracts/artifact"
|
|
registryevents "github.com/harness/gitness/registry/app/events"
|
|
registrytypes "github.com/harness/gitness/registry/types"
|
|
"github.com/harness/gitness/types"
|
|
"github.com/harness/gitness/types/enum"
|
|
)
|
|
|
|
// ArtifactEventPayload describes the payload of Artifact related webhook triggers.
|
|
type ArtifactEventPayload struct {
|
|
Trigger enum.WebhookTrigger `json:"trigger"`
|
|
Registry RegistryInfo `json:"registry"`
|
|
Principal gitnesswebhook.PrincipalInfo `json:"principal"`
|
|
ArtifactInfo *registryevents.ArtifactInfo `json:"artifact_info"`
|
|
ArtifactChangeInfo *registryevents.ArtifactChangeInfo `json:"artifact_change_info"`
|
|
}
|
|
|
|
type RegistryInfo struct {
|
|
ID int64 `json:"id"`
|
|
Name string `json:"name"`
|
|
Description string `json:"description"`
|
|
URL string `json:"url"`
|
|
}
|
|
|
|
// handleEventArtifactCreated handles branch created events
|
|
// and triggers branch created webhooks for the source repo.
|
|
func (s *Service) handleEventArtifactCreated(
|
|
ctx context.Context,
|
|
event *events.Event[*registryevents.ArtifactCreatedPayload],
|
|
) error {
|
|
return s.triggerForEventWithArtifact(ctx, enum.WebhookTriggerArtifactCreated,
|
|
event.ID, event.Payload.PrincipalID, event.Payload.RegistryID,
|
|
func(
|
|
principal *types.Principal,
|
|
registry *registrytypes.Registry,
|
|
) (any, error) {
|
|
space, err := s.spaceStore.Find(ctx, registry.ParentID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &ArtifactEventPayload{
|
|
Trigger: enum.WebhookTriggerArtifactCreated,
|
|
Registry: RegistryInfo{
|
|
ID: registry.ID,
|
|
Name: registry.Name,
|
|
Description: registry.Description,
|
|
URL: s.urlProvider.GenerateUIRegistryURL(ctx, space.Path, registry.Name),
|
|
},
|
|
Principal: gitnesswebhook.PrincipalInfo{
|
|
ID: principal.ID,
|
|
UID: principal.UID,
|
|
DisplayName: principal.DisplayName,
|
|
Email: principal.Email,
|
|
Type: principal.Type,
|
|
Created: principal.Created,
|
|
Updated: principal.Updated,
|
|
},
|
|
ArtifactInfo: getArtifactInfo(event.Payload.Artifact),
|
|
}, nil
|
|
})
|
|
}
|
|
|
|
// handleEventArtifactUpdated handles branch updated events
|
|
// and triggers branch updated webhooks for the source repo.
|
|
func (s *Service) handleEventArtifactUpdated(
|
|
ctx context.Context,
|
|
event *events.Event[*registryevents.ArtifactUpdatedPayload],
|
|
) error {
|
|
return s.triggerForEventWithArtifact(ctx, enum.WebhookTriggerArtifactUpdated,
|
|
event.ID, event.Payload.PrincipalID, event.Payload.RegistryID,
|
|
func(
|
|
principal *types.Principal,
|
|
registry *registrytypes.Registry,
|
|
) (any, error) {
|
|
space, err := s.spaceStore.Find(ctx, registry.ParentID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &ArtifactEventPayload{
|
|
Trigger: enum.WebhookTriggerArtifactUpdated,
|
|
Registry: RegistryInfo{
|
|
ID: registry.ID,
|
|
Name: registry.Name,
|
|
Description: registry.Description,
|
|
URL: s.urlProvider.GenerateUIRegistryURL(ctx, space.Path, registry.Name),
|
|
},
|
|
Principal: gitnesswebhook.PrincipalInfo{
|
|
ID: principal.ID,
|
|
UID: principal.UID,
|
|
DisplayName: principal.DisplayName,
|
|
Email: principal.Email,
|
|
Type: principal.Type,
|
|
Created: principal.Created,
|
|
Updated: principal.Updated,
|
|
},
|
|
ArtifactInfo: getArtifactInfo(event.Payload.ArtifactChange.New),
|
|
ArtifactChangeInfo: getArtifactInfoForArtifactUpdated(*event.Payload),
|
|
}, nil
|
|
})
|
|
}
|
|
|
|
// handleEventArtifactDeleted handles branch deleted events
|
|
// and triggers branch deleted webhooks for the source repo.
|
|
func (s *Service) handleEventArtifactDeleted(
|
|
ctx context.Context,
|
|
event *events.Event[*registryevents.ArtifactDeletedPayload],
|
|
) error {
|
|
return s.triggerForEventWithArtifact(ctx, enum.WebhookTriggerArtifactDeleted,
|
|
event.ID, event.Payload.PrincipalID, event.Payload.RegistryID,
|
|
func(
|
|
principal *types.Principal,
|
|
registry *registrytypes.Registry,
|
|
) (any, error) {
|
|
space, err := s.spaceStore.Find(ctx, registry.ParentID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &ArtifactEventPayload{
|
|
Trigger: enum.WebhookTriggerArtifactDeleted,
|
|
Registry: RegistryInfo{
|
|
ID: registry.ID,
|
|
Name: registry.Name,
|
|
Description: registry.Description,
|
|
URL: s.urlProvider.GenerateUIRegistryURL(ctx, space.Path, registry.Name),
|
|
},
|
|
Principal: gitnesswebhook.PrincipalInfo{
|
|
ID: principal.ID,
|
|
UID: principal.UID,
|
|
DisplayName: principal.DisplayName,
|
|
Email: principal.Email,
|
|
Type: principal.Type,
|
|
Created: principal.Created,
|
|
Updated: principal.Updated,
|
|
},
|
|
ArtifactInfo: getArtifactInfo(event.Payload.Artifact),
|
|
}, nil
|
|
})
|
|
}
|
|
|
|
func getArtifactInfo(eventArtifact registryevents.Artifact) *registryevents.ArtifactInfo {
|
|
artifactInfo := registryevents.ArtifactInfo{}
|
|
if dockerArtifact, ok := eventArtifact.(*registryevents.DockerArtifact); ok {
|
|
artifactInfo.Type = artifact.PackageTypeDOCKER
|
|
artifactInfo.Name = dockerArtifact.Name
|
|
artifactInfo.Version = dockerArtifact.Tag
|
|
artifactInfo.Artifact = &dockerArtifact
|
|
} else if helmArtifact, ok := eventArtifact.(*registryevents.HelmArtifact); ok {
|
|
artifactInfo.Type = artifact.PackageTypeHELM
|
|
artifactInfo.Name = helmArtifact.Name
|
|
artifactInfo.Version = helmArtifact.Tag
|
|
artifactInfo.Artifact = &helmArtifact
|
|
}
|
|
return &artifactInfo
|
|
}
|
|
|
|
func getArtifactInfoForArtifactUpdated(
|
|
payload registryevents.ArtifactUpdatedPayload,
|
|
) *registryevents.ArtifactChangeInfo {
|
|
artifactInfo := registryevents.ArtifactChangeInfo{
|
|
Type: payload.ArtifactType,
|
|
}
|
|
if dockerArtifact, ok := payload.ArtifactChange.New.(*registryevents.DockerArtifact); ok {
|
|
artifactInfo.Name = dockerArtifact.Name
|
|
} else if helmArtifact, ok := payload.ArtifactChange.New.(*registryevents.HelmArtifact); ok {
|
|
artifactInfo.Name = helmArtifact.Name
|
|
}
|
|
artifactInfo.ArtifactChange = &payload.ArtifactChange
|
|
return &artifactInfo
|
|
}
|
|
|
|
// triggerForEventWithArtifact triggers all webhooks for the given registry and triggerType
|
|
// using the eventID to generate a deterministic triggerID and using the output of bodyFn as payload.
|
|
// The method tries to find the registry and principal and provides both to the bodyFn to generate the body.
|
|
// NOTE: technically we could avoid this call if we send the data via the event (though then events will get big).
|
|
func (s *Service) triggerForEventWithArtifact(
|
|
ctx context.Context,
|
|
triggerType enum.WebhookTrigger,
|
|
eventID string,
|
|
principalID int64,
|
|
registryID int64,
|
|
createBodyFn func(*types.Principal, *registrytypes.Registry) (any, error),
|
|
) error {
|
|
principal, err := s.WebhookExecutor.FindPrincipalForEvent(ctx, principalID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
registry, err := s.registryRepository.Get(ctx, registryID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
body, err := createBodyFn(principal, registry)
|
|
if err != nil {
|
|
return fmt.Errorf("body creation function failed: %w", err)
|
|
}
|
|
|
|
parents, err := s.getParentInfoRegistry(ctx, registry.ID, true)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to get webhook parent info: %w", err)
|
|
}
|
|
|
|
return s.WebhookExecutor.TriggerForEvent(ctx, eventID, parents, triggerType, body)
|
|
}
|
|
|
|
func (s *Service) getParentInfoRegistry(
|
|
ctx context.Context,
|
|
registryID int64,
|
|
inherited bool,
|
|
) ([]types.WebhookParentInfo, error) {
|
|
var parents []types.WebhookParentInfo
|
|
|
|
parents = append(parents, types.WebhookParentInfo{
|
|
ID: registryID,
|
|
Type: enum.WebhookParentRegistry,
|
|
})
|
|
|
|
if inherited {
|
|
registry, err := s.registryRepository.Get(ctx, registryID)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to get registry: %w", err)
|
|
}
|
|
|
|
ids, err := s.spaceStore.GetAncestorIDs(ctx, registry.ParentID)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to get parent space ids: %w", err)
|
|
}
|
|
|
|
for _, id := range ids {
|
|
parents = append(parents, types.WebhookParentInfo{
|
|
Type: enum.WebhookParentSpace,
|
|
ID: id,
|
|
})
|
|
}
|
|
}
|
|
|
|
return parents, nil
|
|
}
|