mirror of
https://github.com/harness/drone.git
synced 2025-05-05 15:32:56 +00:00
feat: [AH-933]: implement webhook execution (#3444)
* feat: [AH-933]: implement webhook execution * feat: [AH-933]: implement webhook execution
This commit is contained in:
parent
3a2428f6b8
commit
6da9821bc7
@ -19,6 +19,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/harness/gitness/app/auth"
|
||||
webhooksservice "github.com/harness/gitness/app/services/webhook"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
@ -35,7 +36,11 @@ func (c *Controller) RetriggerExecutionRepo(
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to acquire access to the repo: %w", err)
|
||||
}
|
||||
|
||||
return c.webhookService.RetriggerExecution(
|
||||
executionCore, err := c.webhookService.RetriggerExecution(
|
||||
ctx, repo.ID, enum.WebhookParentRepo, webhookIdentifier, webhookExecutionID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
execution := webhooksservice.CoreWebhookExecutionToGitnessWebhookExecution(executionCore)
|
||||
return execution, nil
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/harness/gitness/app/auth"
|
||||
webhooksservice "github.com/harness/gitness/app/services/webhook"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
@ -36,6 +37,11 @@ func (c *Controller) RetriggerExecutionSpace(
|
||||
return nil, fmt.Errorf("failed to acquire access to space: %w", err)
|
||||
}
|
||||
|
||||
return c.webhookService.RetriggerExecution(
|
||||
executionCore, err := c.webhookService.RetriggerExecution(
|
||||
ctx, space.ID, enum.WebhookParentSpace, webhookIdentifier, webhookExecutionID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
execution := webhooksservice.CoreWebhookExecutionToGitnessWebhookExecution(executionCore)
|
||||
return execution, nil
|
||||
}
|
||||
|
@ -63,6 +63,11 @@ func InternalError(ctx context.Context, w http.ResponseWriter) {
|
||||
UserError(ctx, w, usererror.ErrInternal)
|
||||
}
|
||||
|
||||
// InternalErrorf writes the json-encoded message with internal server error status code.
|
||||
func InternalErrorf(ctx context.Context, w http.ResponseWriter, format string, args ...interface{}) {
|
||||
UserError(ctx, w, usererror.Newf(http.StatusInternalServerError, format, args...))
|
||||
}
|
||||
|
||||
// UserError writes the json-encoded user error.
|
||||
func UserError(ctx context.Context, w http.ResponseWriter, err *usererror.Error) {
|
||||
log.Ctx(ctx).Debug().Err(err).Msgf("operation resulted in user facing error")
|
||||
|
@ -44,7 +44,7 @@ func (s *Service) triggerForEventWithRepo(
|
||||
repoID int64,
|
||||
createBodyFn func(*types.Principal, *types.Repository) (any, error),
|
||||
) error {
|
||||
principal, err := s.findPrincipalForEvent(ctx, principalID)
|
||||
principal, err := s.WebhookExecutor.FindPrincipalForEvent(ctx, principalID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -65,7 +65,7 @@ func (s *Service) triggerForEventWithRepo(
|
||||
return fmt.Errorf("failed to get webhook parent info for parents: %w", err)
|
||||
}
|
||||
|
||||
return s.triggerForEvent(ctx, eventID, parents, triggerType, body)
|
||||
return s.WebhookExecutor.TriggerForEvent(ctx, eventID, parents, triggerType, body)
|
||||
}
|
||||
|
||||
// triggerForEventWithPullReq triggers all webhooks for the given repo and triggerType
|
||||
@ -73,11 +73,15 @@ func (s *Service) triggerForEventWithRepo(
|
||||
// The method tries to find the pullreq, principal, target repo, and source repo
|
||||
// and provides all 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) triggerForEventWithPullReq(ctx context.Context,
|
||||
func (s *Service) triggerForEventWithPullReq(
|
||||
ctx context.Context,
|
||||
triggerType enum.WebhookTrigger, eventID string, principalID int64, prID int64,
|
||||
createBodyFn func(principal *types.Principal, pr *types.PullReq,
|
||||
targetRepo *types.Repository, sourceRepo *types.Repository) (any, error)) error {
|
||||
principal, err := s.findPrincipalForEvent(ctx, principalID)
|
||||
createBodyFn func(
|
||||
principal *types.Principal, pr *types.PullReq,
|
||||
targetRepo *types.Repository, sourceRepo *types.Repository,
|
||||
) (any, error),
|
||||
) error {
|
||||
principal, err := s.WebhookExecutor.FindPrincipalForEvent(ctx, principalID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -111,7 +115,7 @@ func (s *Service) triggerForEventWithPullReq(ctx context.Context,
|
||||
return fmt.Errorf("failed to get webhook parent info: %w", err)
|
||||
}
|
||||
|
||||
return s.triggerForEvent(ctx, eventID, parents, triggerType, body)
|
||||
return s.WebhookExecutor.TriggerForEvent(ctx, eventID, parents, triggerType, body)
|
||||
}
|
||||
|
||||
// findRepositoryForEvent finds the repository for the provided repoID.
|
||||
@ -146,9 +150,9 @@ func (s *Service) findPullReqForEvent(ctx context.Context, prID int64) (*types.P
|
||||
return pr, nil
|
||||
}
|
||||
|
||||
// findPrincipalForEvent finds the principal for the provided principalID.
|
||||
func (s *Service) findPrincipalForEvent(ctx context.Context, principalID int64) (*types.Principal, error) {
|
||||
principal, err := s.principalStore.Find(ctx, principalID)
|
||||
// FindPrincipalForEvent finds the principal for the provided principalID.
|
||||
func (w *WebhookExecutor) FindPrincipalForEvent(ctx context.Context, principalID int64) (*types.Principal, error) {
|
||||
principal, err := w.principalStore.Find(ctx, principalID)
|
||||
|
||||
if err != nil && errors.Is(err, store.ErrResourceNotFound) {
|
||||
// this should never happen (as we won't delete principals) - discard event
|
||||
@ -162,9 +166,9 @@ func (s *Service) findPrincipalForEvent(ctx context.Context, principalID int64)
|
||||
return principal, nil
|
||||
}
|
||||
|
||||
// triggerForEvent triggers all webhooks for the given parentType/ID and triggerType
|
||||
// TriggerForEvent triggers all webhooks for the given parentType/ID and triggerType
|
||||
// using the eventID to generate a deterministic triggerID and sending the provided body as payload.
|
||||
func (s *Service) triggerForEvent(
|
||||
func (w *WebhookExecutor) TriggerForEvent(
|
||||
ctx context.Context,
|
||||
eventID string,
|
||||
parents []types.WebhookParentInfo,
|
||||
@ -173,7 +177,7 @@ func (s *Service) triggerForEvent(
|
||||
) error {
|
||||
triggerID := generateTriggerIDFromEventID(eventID)
|
||||
|
||||
results, err := s.triggerWebhooksFor(ctx, parents, triggerID, triggerType, body)
|
||||
results, err := w.triggerWebhooksFor(ctx, parents, triggerID, triggerType, body)
|
||||
|
||||
// return all errors and force the event to be reprocessed (it's not webhook execution specific!)
|
||||
if err != nil {
|
||||
|
@ -78,7 +78,7 @@ func (s *Service) RetriggerExecution(
|
||||
parentType enum.WebhookParent,
|
||||
webhookIdentifier string,
|
||||
webhookExecutionID int64,
|
||||
) (*types.WebhookExecution, error) {
|
||||
) (*types.WebhookExecutionCore, error) {
|
||||
webhook, err := s.GetWebhookVerifyOwnership(
|
||||
ctx, parentID, parentType, webhookIdentifier)
|
||||
if err != nil {
|
||||
@ -91,7 +91,7 @@ func (s *Service) RetriggerExecution(
|
||||
return nil, err
|
||||
}
|
||||
|
||||
executionResult, err := s.RetriggerWebhookExecution(ctx, webhookExecution.ID)
|
||||
executionResult, err := s.WebhookExecutor.RetriggerWebhookExecution(ctx, webhookExecution.ID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to retrigger webhook execution: %w", err)
|
||||
}
|
||||
|
@ -41,8 +41,10 @@ type PullReqCreatedPayload struct {
|
||||
|
||||
// handleEventPullReqCreated handles created events for pull requests
|
||||
// and triggers pullreq created webhooks for the source repo.
|
||||
func (s *Service) handleEventPullReqCreated(ctx context.Context,
|
||||
event *events.Event[*pullreqevents.CreatedPayload]) error {
|
||||
func (s *Service) handleEventPullReqCreated(
|
||||
ctx context.Context,
|
||||
event *events.Event[*pullreqevents.CreatedPayload],
|
||||
) error {
|
||||
return s.triggerForEventWithPullReq(ctx, enum.WebhookTriggerPullReqCreated,
|
||||
event.ID, event.Payload.PrincipalID, event.Payload.PullReqID,
|
||||
func(principal *types.Principal, pr *types.PullReq, targetRepo, sourceRepo *types.Repository) (any, error) {
|
||||
@ -89,8 +91,10 @@ type PullReqReopenedPayload PullReqCreatedPayload
|
||||
|
||||
// handleEventPullReqReopened handles reopened events for pull requests
|
||||
// and triggers pullreq reopened webhooks for the source repo.
|
||||
func (s *Service) handleEventPullReqReopened(ctx context.Context,
|
||||
event *events.Event[*pullreqevents.ReopenedPayload]) error {
|
||||
func (s *Service) handleEventPullReqReopened(
|
||||
ctx context.Context,
|
||||
event *events.Event[*pullreqevents.ReopenedPayload],
|
||||
) error {
|
||||
return s.triggerForEventWithPullReq(ctx, enum.WebhookTriggerPullReqReopened,
|
||||
event.ID, event.Payload.PrincipalID, event.Payload.PullReqID,
|
||||
func(principal *types.Principal, pr *types.PullReq, targetRepo, sourceRepo *types.Repository) (any, error) {
|
||||
@ -144,8 +148,10 @@ type PullReqBranchUpdatedPayload struct {
|
||||
|
||||
// handleEventPullReqBranchUpdated handles branch updated events for pull requests
|
||||
// and triggers pullreq branch updated webhooks for the source repo.
|
||||
func (s *Service) handleEventPullReqBranchUpdated(ctx context.Context,
|
||||
event *events.Event[*pullreqevents.BranchUpdatedPayload]) error {
|
||||
func (s *Service) handleEventPullReqBranchUpdated(
|
||||
ctx context.Context,
|
||||
event *events.Event[*pullreqevents.BranchUpdatedPayload],
|
||||
) error {
|
||||
return s.triggerForEventWithPullReq(ctx, enum.WebhookTriggerPullReqBranchUpdated,
|
||||
event.ID, event.Payload.PrincipalID, event.Payload.PullReqID,
|
||||
func(principal *types.Principal, pr *types.PullReq, targetRepo, sourceRepo *types.Repository) (any, error) {
|
||||
@ -204,8 +210,10 @@ type PullReqClosedPayload struct {
|
||||
ReferenceDetailsSegment
|
||||
}
|
||||
|
||||
func (s *Service) handleEventPullReqClosed(ctx context.Context,
|
||||
event *events.Event[*pullreqevents.ClosedPayload]) error {
|
||||
func (s *Service) handleEventPullReqClosed(
|
||||
ctx context.Context,
|
||||
event *events.Event[*pullreqevents.ClosedPayload],
|
||||
) error {
|
||||
return s.triggerForEventWithPullReq(ctx, enum.WebhookTriggerPullReqClosed,
|
||||
event.ID, event.Payload.PrincipalID, event.Payload.PullReqID,
|
||||
func(principal *types.Principal, pr *types.PullReq, targetRepo, sourceRepo *types.Repository) (any, error) {
|
||||
@ -255,8 +263,10 @@ type PullReqMergedPayload struct {
|
||||
ReferenceDetailsSegment
|
||||
}
|
||||
|
||||
func (s *Service) handleEventPullReqMerged(ctx context.Context,
|
||||
event *events.Event[*pullreqevents.MergedPayload]) error {
|
||||
func (s *Service) handleEventPullReqMerged(
|
||||
ctx context.Context,
|
||||
event *events.Event[*pullreqevents.MergedPayload],
|
||||
) error {
|
||||
return s.triggerForEventWithPullReq(ctx, enum.WebhookTriggerPullReqMerged,
|
||||
event.ID, event.Payload.PrincipalID, event.Payload.PullReqID,
|
||||
func(principal *types.Principal, pr *types.PullReq, targetRepo, sourceRepo *types.Repository) (any, error) {
|
||||
@ -654,7 +664,7 @@ func (s *Service) handleEventPullReqReviewSubmitted(
|
||||
targetRepoInfo := repositoryInfoFrom(ctx, targetRepo, s.urlProvider)
|
||||
sourceRepoInfo := repositoryInfoFrom(ctx, sourceRepo, s.urlProvider)
|
||||
|
||||
reviewer, err := s.findPrincipalForEvent(ctx, event.Payload.ReviewerID)
|
||||
reviewer, err := s.WebhookExecutor.FindPrincipalForEvent(ctx, event.Payload.ReviewerID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get reviewer by id for reviewer id %d: %w", event.Payload.ReviewerID, err)
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ func newHTTPClient(allowLoopback bool, allowPrivateNetwork bool, disableSSLVerif
|
||||
}
|
||||
|
||||
// Clone http.DefaultTransport (used by http.DefaultClient)
|
||||
tr := http.DefaultTransport.(*http.Transport).Clone()
|
||||
tr := http.DefaultTransport.(*http.Transport).Clone() //nolint:errcheck
|
||||
|
||||
tr.TLSClientConfig.InsecureSkipVerify = disableSSLVerification
|
||||
|
||||
|
@ -22,7 +22,7 @@ import (
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
// Listreturns the webhooks from the provided scope.
|
||||
// List returns the webhooks from the provided scope.
|
||||
func (s *Service) List(
|
||||
ctx context.Context,
|
||||
parentID int64,
|
||||
|
101
app/services/webhook/repository.go
Normal file
101
app/services/webhook/repository.go
Normal file
@ -0,0 +1,101 @@
|
||||
// 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"
|
||||
|
||||
gitnessstore "github.com/harness/gitness/app/store"
|
||||
"github.com/harness/gitness/types"
|
||||
)
|
||||
|
||||
type GitnessWebhookExecutorStore struct {
|
||||
webhookStore gitnessstore.WebhookStore
|
||||
webhookExecutionStore gitnessstore.WebhookExecutionStore
|
||||
}
|
||||
|
||||
func (s *GitnessWebhookExecutorStore) Find(ctx context.Context, id int64) (*types.WebhookExecutionCore, error) {
|
||||
execution, err := s.webhookExecutionStore.Find(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
executionCore := GitnessWebhookExecutionToWebhookExecutionCore(execution)
|
||||
return executionCore, nil
|
||||
}
|
||||
|
||||
func (s *GitnessWebhookExecutorStore) ListWebhooks(
|
||||
ctx context.Context,
|
||||
parents []types.WebhookParentInfo,
|
||||
) ([]*types.WebhookCore, error) {
|
||||
webhooks, err := s.webhookStore.List(ctx, parents, &types.WebhookFilter{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
webhooksCore := GitnessWebhooksToWebhooksCore(webhooks)
|
||||
return webhooksCore, nil
|
||||
}
|
||||
|
||||
func (s *GitnessWebhookExecutorStore) ListForTrigger(
|
||||
ctx context.Context,
|
||||
triggerID string,
|
||||
) ([]*types.WebhookExecutionCore, error) {
|
||||
executions, err := s.webhookExecutionStore.ListForTrigger(ctx, triggerID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
webhookExecutionsCore := make([]*types.WebhookExecutionCore, 0)
|
||||
for _, e := range executions {
|
||||
executionCore := GitnessWebhookExecutionToWebhookExecutionCore(e)
|
||||
webhookExecutionsCore = append(webhookExecutionsCore, executionCore)
|
||||
}
|
||||
return webhookExecutionsCore, nil
|
||||
}
|
||||
|
||||
func (s *GitnessWebhookExecutorStore) CreateWebhookExecution(
|
||||
ctx context.Context,
|
||||
hook *types.WebhookExecutionCore,
|
||||
) error {
|
||||
webhookExecution := CoreWebhookExecutionToGitnessWebhookExecution(hook)
|
||||
return s.webhookExecutionStore.Create(ctx, webhookExecution)
|
||||
}
|
||||
|
||||
func (s *GitnessWebhookExecutorStore) UpdateOptLock(
|
||||
ctx context.Context, hook *types.WebhookCore,
|
||||
execution *types.WebhookExecutionCore,
|
||||
) (*types.WebhookCore, error) {
|
||||
webhook := CoreWebhookToGitnessWebhook(hook)
|
||||
fn := func(hook *types.Webhook) error {
|
||||
hook.LatestExecutionResult = &execution.Result
|
||||
return nil
|
||||
}
|
||||
gitnessWebhook, err := s.webhookStore.UpdateOptLock(ctx, webhook, fn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
webhookCore := GitnessWebhookToWebhookCore(gitnessWebhook)
|
||||
return webhookCore, err
|
||||
}
|
||||
|
||||
func (s *GitnessWebhookExecutorStore) FindWebhook(
|
||||
ctx context.Context,
|
||||
id int64,
|
||||
) (*types.WebhookCore, error) {
|
||||
webhook, err := s.webhookStore.Find(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
webhookCore := GitnessWebhookToWebhookCore(webhook)
|
||||
return webhookCore, nil
|
||||
}
|
@ -29,8 +29,10 @@ import (
|
||||
"github.com/harness/gitness/encrypt"
|
||||
"github.com/harness/gitness/events"
|
||||
"github.com/harness/gitness/git"
|
||||
"github.com/harness/gitness/secret"
|
||||
"github.com/harness/gitness/store/database/dbtx"
|
||||
"github.com/harness/gitness/stream"
|
||||
"github.com/harness/gitness/types"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -59,16 +61,16 @@ func (c *Config) Prepare() error {
|
||||
return errors.New("config is required")
|
||||
}
|
||||
if c.EventReaderName == "" {
|
||||
return errors.New("config.EventReaderName is required")
|
||||
return errors.New("Config.EventReaderName is required")
|
||||
}
|
||||
if c.UserAgentIdentity == "" {
|
||||
return errors.New("config.UserAgentIdentity is required")
|
||||
return errors.New("Config.UserAgentIdentity is required")
|
||||
}
|
||||
if c.Concurrency < 1 {
|
||||
return errors.New("config.Concurrency has to be a positive number")
|
||||
return errors.New("Config.Concurrency has to be a positive number")
|
||||
}
|
||||
if c.MaxRetries < 0 {
|
||||
return errors.New("config.MaxRetries can't be negative")
|
||||
return errors.New("Config.MaxRetries can't be negative")
|
||||
}
|
||||
|
||||
// Backfill data
|
||||
@ -79,10 +81,76 @@ func (c *Config) Prepare() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type WebhookExecutorStore interface {
|
||||
Find(ctx context.Context, id int64) (*types.WebhookExecutionCore, error)
|
||||
ListWebhooks(
|
||||
ctx context.Context,
|
||||
parents []types.WebhookParentInfo,
|
||||
) ([]*types.WebhookCore, error)
|
||||
|
||||
UpdateOptLock(
|
||||
ctx context.Context, hook *types.WebhookCore,
|
||||
execution *types.WebhookExecutionCore,
|
||||
) (*types.WebhookCore, error)
|
||||
|
||||
FindWebhook(
|
||||
ctx context.Context,
|
||||
id int64,
|
||||
) (*types.WebhookCore, error)
|
||||
|
||||
ListForTrigger(
|
||||
ctx context.Context,
|
||||
triggerID string,
|
||||
) ([]*types.WebhookExecutionCore, error)
|
||||
|
||||
CreateWebhookExecution(ctx context.Context, hook *types.WebhookExecutionCore) error
|
||||
}
|
||||
|
||||
type WebhookExecutor struct {
|
||||
secureHTTPClient *http.Client
|
||||
insecureHTTPClient *http.Client
|
||||
secureHTTPClientInternal *http.Client
|
||||
insecureHTTPClientInternal *http.Client
|
||||
config Config
|
||||
webhookURLProvider URLProvider
|
||||
encrypter encrypt.Encrypter
|
||||
spacePathStore store.SpacePathStore
|
||||
secretService secret.Service
|
||||
principalStore store.PrincipalStore
|
||||
webhookExecutorStore WebhookExecutorStore
|
||||
source string
|
||||
}
|
||||
|
||||
func NewWebhookExecutor(
|
||||
config Config,
|
||||
webhookURLProvider URLProvider,
|
||||
encrypter encrypt.Encrypter,
|
||||
spacePathStore store.SpacePathStore,
|
||||
secretService secret.Service,
|
||||
principalStore store.PrincipalStore,
|
||||
webhookExecutorStore WebhookExecutorStore,
|
||||
source string,
|
||||
) *WebhookExecutor {
|
||||
return &WebhookExecutor{
|
||||
webhookExecutorStore: webhookExecutorStore,
|
||||
secureHTTPClient: newHTTPClient(config.AllowLoopback, config.AllowPrivateNetwork, false),
|
||||
insecureHTTPClient: newHTTPClient(config.AllowLoopback, config.AllowPrivateNetwork, true),
|
||||
secureHTTPClientInternal: newHTTPClient(config.AllowLoopback, true, false),
|
||||
insecureHTTPClientInternal: newHTTPClient(config.AllowLoopback, true, true),
|
||||
config: config,
|
||||
webhookURLProvider: webhookURLProvider,
|
||||
encrypter: encrypter,
|
||||
spacePathStore: spacePathStore,
|
||||
secretService: secretService,
|
||||
principalStore: principalStore,
|
||||
source: source,
|
||||
}
|
||||
}
|
||||
|
||||
// Service is responsible for processing webhook events.
|
||||
type Service struct {
|
||||
tx dbtx.Transactor
|
||||
|
||||
WebhookExecutor *WebhookExecutor
|
||||
tx dbtx.Transactor
|
||||
webhookStore store.WebhookStore
|
||||
webhookExecutionStore store.WebhookExecutionStore
|
||||
urlProvider url.Provider
|
||||
@ -95,17 +163,8 @@ type Service struct {
|
||||
labelStore store.LabelStore
|
||||
labelValueStore store.LabelValueStore
|
||||
encrypter encrypt.Encrypter
|
||||
|
||||
secureHTTPClient *http.Client
|
||||
insecureHTTPClient *http.Client
|
||||
|
||||
secureHTTPClientInternal *http.Client
|
||||
insecureHTTPClientInternal *http.Client
|
||||
|
||||
config Config
|
||||
webhookURLProvider URLProvider
|
||||
|
||||
sseStreamer sse.Streamer
|
||||
config Config
|
||||
sseStreamer sse.Streamer
|
||||
}
|
||||
|
||||
func NewService(
|
||||
@ -128,11 +187,21 @@ func NewService(
|
||||
webhookURLProvider URLProvider,
|
||||
labelValueStore store.LabelValueStore,
|
||||
sseStreamer sse.Streamer,
|
||||
secretService secret.Service,
|
||||
spacePathStore store.SpacePathStore,
|
||||
) (*Service, error) {
|
||||
if err := config.Prepare(); err != nil {
|
||||
return nil, fmt.Errorf("provided webhook service config is invalid: %w", err)
|
||||
return nil, fmt.Errorf("provided webhook service Config is invalid: %w", err)
|
||||
}
|
||||
webhookExecutorStore := &GitnessWebhookExecutorStore{
|
||||
webhookStore: webhookStore,
|
||||
webhookExecutionStore: webhookExecutionStore,
|
||||
}
|
||||
executor := NewWebhookExecutor(config, webhookURLProvider, encrypter, spacePathStore,
|
||||
secretService, principalStore, webhookExecutorStore, RepoTrigger)
|
||||
|
||||
service := &Service{
|
||||
WebhookExecutor: executor,
|
||||
tx: tx,
|
||||
webhookStore: webhookStore,
|
||||
webhookExecutionStore: webhookExecutionStore,
|
||||
@ -144,20 +213,10 @@ func NewService(
|
||||
principalStore: principalStore,
|
||||
git: git,
|
||||
encrypter: encrypter,
|
||||
|
||||
secureHTTPClient: newHTTPClient(config.AllowLoopback, config.AllowPrivateNetwork, false),
|
||||
insecureHTTPClient: newHTTPClient(config.AllowLoopback, config.AllowPrivateNetwork, true),
|
||||
|
||||
secureHTTPClientInternal: newHTTPClient(config.AllowLoopback, true, false),
|
||||
insecureHTTPClientInternal: newHTTPClient(config.AllowLoopback, true, true),
|
||||
|
||||
config: config,
|
||||
|
||||
labelStore: labelStore,
|
||||
labelValueStore: labelValueStore,
|
||||
webhookURLProvider: webhookURLProvider,
|
||||
|
||||
sseStreamer: sseStreamer,
|
||||
config: config,
|
||||
labelStore: labelStore,
|
||||
labelValueStore: labelValueStore,
|
||||
sseStreamer: sseStreamer,
|
||||
}
|
||||
|
||||
_, err := gitReaderFactory.Launch(ctx, eventsReaderGroupName, config.EventReaderName,
|
||||
|
@ -25,7 +25,9 @@ import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
gitnessstore "github.com/harness/gitness/app/store"
|
||||
"github.com/harness/gitness/crypto"
|
||||
"github.com/harness/gitness/secret"
|
||||
"github.com/harness/gitness/store"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
@ -46,6 +48,11 @@ const (
|
||||
responseBodyBytesLimit = 1024
|
||||
)
|
||||
|
||||
const (
|
||||
RepoTrigger = "Trigger"
|
||||
ArtifactRegistryTrigger = "Artifact-Registry-Trigger"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrWebhookNotRetriggerable is returned in case the webhook can't be retriggered due to an incomplete execution.
|
||||
// This should only occur if we failed to generate the request body (most likely out of memory).
|
||||
@ -55,8 +62,8 @@ var (
|
||||
type TriggerResult struct {
|
||||
TriggerID string
|
||||
TriggerType enum.WebhookTrigger
|
||||
Webhook *types.Webhook
|
||||
Execution *types.WebhookExecution
|
||||
Webhook *types.WebhookCore
|
||||
Execution *types.WebhookExecutionCore
|
||||
Err error
|
||||
}
|
||||
|
||||
@ -64,31 +71,32 @@ func (r *TriggerResult) Skipped() bool {
|
||||
return r.Execution == nil
|
||||
}
|
||||
|
||||
func (s *Service) triggerWebhooksFor(
|
||||
func (w *WebhookExecutor) triggerWebhooksFor(
|
||||
ctx context.Context,
|
||||
parents []types.WebhookParentInfo,
|
||||
triggerID string,
|
||||
triggerType enum.WebhookTrigger,
|
||||
body any,
|
||||
) ([]TriggerResult, error) {
|
||||
webhooks, err := s.webhookStore.List(ctx, parents, &types.WebhookFilter{})
|
||||
webhooks, err := w.webhookExecutorStore.ListWebhooks(ctx, parents)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to list webhooks for: %w", err)
|
||||
}
|
||||
|
||||
return s.triggerWebhooks(ctx, webhooks, triggerID, triggerType, body)
|
||||
return w.triggerWebhooks(ctx, webhooks, triggerID, triggerType, body)
|
||||
}
|
||||
|
||||
//nolint:gocognit // refactor if needed
|
||||
func (s *Service) triggerWebhooks(ctx context.Context, webhooks []*types.Webhook,
|
||||
triggerID string, triggerType enum.WebhookTrigger, body any) ([]TriggerResult, error) {
|
||||
func (w *WebhookExecutor) triggerWebhooks(
|
||||
ctx context.Context, webhooks []*types.WebhookCore,
|
||||
triggerID string, triggerType enum.WebhookTrigger, body any,
|
||||
) ([]TriggerResult, error) {
|
||||
// return immediately if webhooks are empty
|
||||
if len(webhooks) == 0 {
|
||||
return []TriggerResult{}, nil
|
||||
}
|
||||
|
||||
// get all previous execution for the same trigger
|
||||
executions, err := s.webhookExecutionStore.ListForTrigger(ctx, triggerID)
|
||||
executions, err := w.webhookExecutorStore.ListForTrigger(ctx, triggerID)
|
||||
if err != nil && !errors.Is(err, store.ErrResourceNotFound) {
|
||||
return nil, fmt.Errorf("failed to get executions for trigger '%s'", triggerID)
|
||||
}
|
||||
@ -134,15 +142,18 @@ func (s *Service) triggerWebhooks(ctx context.Context, webhooks []*types.Webhook
|
||||
}
|
||||
|
||||
// execute trigger and store output in result
|
||||
results[i].Execution, results[i].Err = s.executeWebhook(ctx, webhook, triggerID, triggerType, body, nil)
|
||||
results[i].Execution, results[i].Err = w.executeWebhook(ctx, webhook, triggerID, triggerType, body, nil)
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func (s *Service) RetriggerWebhookExecution(ctx context.Context, webhookExecutionID int64) (*TriggerResult, error) {
|
||||
func (w *WebhookExecutor) RetriggerWebhookExecution(
|
||||
ctx context.Context,
|
||||
webhookExecutionID int64,
|
||||
) (*TriggerResult, error) {
|
||||
// find execution
|
||||
webhookExecution, err := s.webhookExecutionStore.Find(ctx, webhookExecutionID)
|
||||
webhookExecution, err := w.webhookExecutorStore.Find(ctx, webhookExecutionID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to find webhook execution with id %d: %w", webhookExecutionID, err)
|
||||
}
|
||||
@ -153,7 +164,7 @@ func (s *Service) RetriggerWebhookExecution(ctx context.Context, webhookExecutio
|
||||
}
|
||||
|
||||
// find webhook
|
||||
webhook, err := s.webhookStore.Find(ctx, webhookExecution.WebhookID)
|
||||
webhook, err := w.webhookExecutorStore.FindWebhook(ctx, webhookExecution.WebhookID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to find webhook with id %d: %w", webhookExecution.WebhookID, err)
|
||||
}
|
||||
@ -167,7 +178,7 @@ func (s *Service) RetriggerWebhookExecution(ctx context.Context, webhookExecutio
|
||||
// NOTE: bBuff.Write(v) will always return (len(v), nil) - no need to error handle
|
||||
body.WriteString(webhookExecution.Request.Body)
|
||||
|
||||
newExecution, err := s.executeWebhook(ctx, webhook, triggerID, triggerType, body, &webhookExecution.ID)
|
||||
newExecution, err := w.executeWebhook(ctx, webhook, triggerID, triggerType, body, &webhookExecution.ID)
|
||||
return &TriggerResult{
|
||||
TriggerID: triggerID,
|
||||
TriggerType: triggerType,
|
||||
@ -178,10 +189,12 @@ func (s *Service) RetriggerWebhookExecution(ctx context.Context, webhookExecutio
|
||||
}
|
||||
|
||||
//nolint:gocognit // refactor into smaller chunks if necessary.
|
||||
func (s *Service) executeWebhook(ctx context.Context, webhook *types.Webhook, triggerID string,
|
||||
triggerType enum.WebhookTrigger, body any, rerunOfID *int64) (*types.WebhookExecution, error) {
|
||||
func (w *WebhookExecutor) executeWebhook(
|
||||
ctx context.Context, webhook *types.WebhookCore, triggerID string,
|
||||
triggerType enum.WebhookTrigger, body any, rerunOfID *int64,
|
||||
) (*types.WebhookExecutionCore, error) {
|
||||
// build execution entry on the fly (save no matter what)
|
||||
execution := types.WebhookExecution{
|
||||
execution := types.WebhookExecutionCore{
|
||||
RetriggerOf: rerunOfID,
|
||||
WebhookID: webhook.ID,
|
||||
TriggerID: triggerID,
|
||||
@ -196,7 +209,7 @@ func (s *Service) executeWebhook(ctx context.Context, webhook *types.Webhook, tr
|
||||
execution.Created = time.Now().UnixMilli()
|
||||
|
||||
// TODO: what if saving execution failed? For now we will rerun it in case of error or not show it in history
|
||||
err := s.webhookExecutionStore.Create(oCtx, &execution)
|
||||
err := w.webhookExecutorStore.CreateWebhookExecution(oCtx, &execution)
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Warn().Err(err).Msgf(
|
||||
"failed to store webhook execution that ended with Result: %s, Response.Status: '%s', Error: '%s'",
|
||||
@ -205,10 +218,7 @@ func (s *Service) executeWebhook(ctx context.Context, webhook *types.Webhook, tr
|
||||
|
||||
// update latest execution result of webhook IFF it's different from before (best effort)
|
||||
if webhook.LatestExecutionResult == nil || *webhook.LatestExecutionResult != execution.Result {
|
||||
_, err = s.webhookStore.UpdateOptLock(oCtx, webhook, func(hook *types.Webhook) error {
|
||||
hook.LatestExecutionResult = &execution.Result
|
||||
return nil
|
||||
})
|
||||
_, err = w.webhookExecutorStore.UpdateOptLock(oCtx, webhook, &execution)
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Warn().Err(err).Msgf(
|
||||
"failed to update latest execution result to %s for webhook %d",
|
||||
@ -222,7 +232,7 @@ func (s *Service) executeWebhook(ctx context.Context, webhook *types.Webhook, tr
|
||||
defer cancel()
|
||||
|
||||
// create request from webhook and body
|
||||
req, err := s.prepareHTTPRequest(ctx, &execution, triggerType, webhook, body)
|
||||
req, err := w.prepareHTTPRequest(ctx, &execution, triggerType, webhook, body)
|
||||
if err != nil {
|
||||
return &execution, err
|
||||
}
|
||||
@ -231,13 +241,13 @@ func (s *Service) executeWebhook(ctx context.Context, webhook *types.Webhook, tr
|
||||
var resp *http.Response
|
||||
switch {
|
||||
case webhook.Type == enum.WebhookTypeInternal && webhook.Insecure:
|
||||
resp, err = s.insecureHTTPClientInternal.Do(req)
|
||||
resp, err = w.insecureHTTPClientInternal.Do(req)
|
||||
case webhook.Type == enum.WebhookTypeInternal:
|
||||
resp, err = s.secureHTTPClientInternal.Do(req)
|
||||
resp, err = w.secureHTTPClientInternal.Do(req)
|
||||
case webhook.Insecure:
|
||||
resp, err = s.insecureHTTPClient.Do(req)
|
||||
resp, err = w.insecureHTTPClient.Do(req)
|
||||
default:
|
||||
resp, err = s.secureHTTPClient.Do(req)
|
||||
resp, err = w.secureHTTPClient.Do(req)
|
||||
}
|
||||
|
||||
// always close the body!
|
||||
@ -283,9 +293,11 @@ func (s *Service) executeWebhook(ctx context.Context, webhook *types.Webhook, tr
|
||||
// prepareHTTPRequest prepares a new http.Request object for the webhook using the provided body as request body.
|
||||
// All execution.Request.XXX values are set accordingly.
|
||||
// NOTE: if the body is an io.Reader, the value is used as response body as is, otherwise it'll be JSON serialized.
|
||||
func (s *Service) prepareHTTPRequest(ctx context.Context, execution *types.WebhookExecution,
|
||||
triggerType enum.WebhookTrigger, webhook *types.Webhook, body any) (*http.Request, error) {
|
||||
url, err := s.webhookURLProvider.GetWebhookURL(ctx, webhook)
|
||||
func (w *WebhookExecutor) prepareHTTPRequest(
|
||||
ctx context.Context, execution *types.WebhookExecutionCore,
|
||||
triggerType enum.WebhookTrigger, webhook *types.WebhookCore, body any,
|
||||
) (*http.Request, error) {
|
||||
url, err := w.webhookURLProvider.GetWebhookURL(ctx, webhook)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("webhook url is not resolvable: %w", err)
|
||||
}
|
||||
@ -336,27 +348,46 @@ func (s *Service) prepareHTTPRequest(ctx context.Context, execution *types.Webho
|
||||
}
|
||||
|
||||
// setup headers
|
||||
req.Header.Add("User-Agent", fmt.Sprintf("%s/%s", s.config.UserAgentIdentity, version.Version))
|
||||
req.Header.Add("User-Agent", fmt.Sprintf("%s/%s", w.config.UserAgentIdentity, version.Version))
|
||||
req.Header.Add("Content-Type", "application/json")
|
||||
req.Header.Add(s.toXHeader("Trigger"), string(triggerType))
|
||||
req.Header.Add(s.toXHeader("Webhook-Parent-Type"), string(webhook.ParentType))
|
||||
req.Header.Add(s.toXHeader("Webhook-Parent-Id"), fmt.Sprint(webhook.ParentID))
|
||||
// TODO [CODE-1363]: remove after identifier migration.
|
||||
req.Header.Add(s.toXHeader("Webhook-Uid"), fmt.Sprint(webhook.Identifier))
|
||||
req.Header.Add(s.toXHeader("Webhook-Identifier"), fmt.Sprint(webhook.Identifier))
|
||||
|
||||
// add HMAC only if a secret was provided
|
||||
req.Header.Add(w.toXHeader("Webhook-Parent-Type"), string(webhook.ParentType))
|
||||
req.Header.Add(w.toXHeader("Webhook-Parent-Id"), fmt.Sprint(webhook.ParentID))
|
||||
// TODO [CODE-1363]: remove after identifier migration.
|
||||
req.Header.Add(w.toXHeader("Webhook-Uid"), fmt.Sprint(webhook.Identifier))
|
||||
req.Header.Add(w.toXHeader("Webhook-Identifier"), fmt.Sprint(webhook.Identifier))
|
||||
req.Header.Add(w.toXHeader(w.source), string(triggerType))
|
||||
|
||||
if webhook.ExtraHeaders != nil {
|
||||
for _, h := range webhook.ExtraHeaders {
|
||||
req.Header.Add(h.Key, h.Value)
|
||||
}
|
||||
}
|
||||
|
||||
var secretValue string
|
||||
if webhook.Secret != "" {
|
||||
decryptedSecret, err := s.encrypter.Decrypt([]byte(webhook.Secret))
|
||||
decryptedSecret, err := w.encrypter.Decrypt([]byte(webhook.Secret))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decrypt webhook secret: %w", err)
|
||||
}
|
||||
secretValue = decryptedSecret
|
||||
} else if webhook.SecretIdentifier != "" {
|
||||
decryptedSecret, err := getSecretValue(ctx, w.spacePathStore, w.secretService,
|
||||
int64(webhook.SecretSpaceID), webhook.SecretIdentifier)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed get secret secret value: %w", err)
|
||||
}
|
||||
secretValue = decryptedSecret
|
||||
}
|
||||
|
||||
// add HMAC only if a secret was provided
|
||||
if secretValue != "" {
|
||||
var hmac string
|
||||
hmac, err = crypto.GenerateHMACSHA256(bBuff.Bytes(), []byte(decryptedSecret))
|
||||
hmac, err = crypto.GenerateHMACSHA256(bBuff.Bytes(), []byte(secretValue))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to generate SHA256 based HMAC: %w", err)
|
||||
}
|
||||
req.Header.Add(s.toXHeader("Signature"), hmac)
|
||||
req.Header.Add(w.toXHeader("Signature"), hmac)
|
||||
}
|
||||
|
||||
hBuffer := &bytes.Buffer{}
|
||||
@ -372,12 +403,12 @@ func (s *Service) prepareHTTPRequest(ctx context.Context, execution *types.Webho
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func (s *Service) toXHeader(name string) string {
|
||||
return fmt.Sprintf("X-%s-%s", s.config.HeaderIdentity, name)
|
||||
func (w *WebhookExecutor) toXHeader(name string) string {
|
||||
return fmt.Sprintf("X-%s-%s", w.config.HeaderIdentity, name)
|
||||
}
|
||||
|
||||
//nolint:funlen // refactor if needed
|
||||
func handleWebhookResponse(execution *types.WebhookExecution, resp *http.Response) error {
|
||||
func handleWebhookResponse(execution *types.WebhookExecutionCore, resp *http.Response) error {
|
||||
// store status (handle status later - want to first read body)
|
||||
execution.Response.StatusCode = resp.StatusCode
|
||||
execution.Response.Status = resp.Status
|
||||
@ -473,3 +504,111 @@ func handleWebhookResponse(execution *types.WebhookExecution, resp *http.Respons
|
||||
return fmt.Errorf("received response with unsupported status code %d", code)
|
||||
}
|
||||
}
|
||||
|
||||
func getSecretValue(
|
||||
ctx context.Context, spacePathStore gitnessstore.SpacePathStore, secretService secret.Service,
|
||||
secretSpaceID int64, secretSpacePath string,
|
||||
) (string, error) {
|
||||
spacePath, err := spacePathStore.FindPrimaryBySpaceID(ctx, secretSpaceID)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("failed to find space path: %w", err)
|
||||
log.Error().Msg(err.Error())
|
||||
return "", err
|
||||
}
|
||||
decryptedSecret, err := secretService.DecryptSecret(ctx, spacePath.Value, secretSpacePath)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("failed to decrypt secret: %w", err)
|
||||
log.Error().Msg(err.Error())
|
||||
return "", err
|
||||
}
|
||||
return decryptedSecret, nil
|
||||
}
|
||||
|
||||
func CoreWebhookExecutionToGitnessWebhookExecution(execution *types.WebhookExecutionCore) *types.WebhookExecution {
|
||||
return &types.WebhookExecution{
|
||||
ID: execution.ID,
|
||||
WebhookID: execution.WebhookID,
|
||||
TriggerID: execution.TriggerID,
|
||||
TriggerType: execution.TriggerType,
|
||||
Result: execution.Result,
|
||||
Error: execution.Error,
|
||||
Request: execution.Request,
|
||||
Response: execution.Response,
|
||||
RetriggerOf: execution.RetriggerOf,
|
||||
Retriggerable: execution.Retriggerable,
|
||||
Duration: execution.Duration,
|
||||
Created: execution.Created,
|
||||
}
|
||||
}
|
||||
|
||||
func GitnessWebhookExecutionToWebhookExecutionCore(execution *types.WebhookExecution) *types.WebhookExecutionCore {
|
||||
return &types.WebhookExecutionCore{
|
||||
ID: execution.ID,
|
||||
WebhookID: execution.WebhookID,
|
||||
TriggerID: execution.TriggerID,
|
||||
TriggerType: execution.TriggerType,
|
||||
Result: execution.Result,
|
||||
Error: execution.Error,
|
||||
Request: execution.Request,
|
||||
Response: execution.Response,
|
||||
RetriggerOf: execution.RetriggerOf,
|
||||
Retriggerable: execution.Retriggerable,
|
||||
Duration: execution.Duration,
|
||||
Created: execution.Created,
|
||||
}
|
||||
}
|
||||
|
||||
func GitnessWebhookToWebhookCore(webhook *types.Webhook) *types.WebhookCore {
|
||||
return &types.WebhookCore{
|
||||
ID: webhook.ID,
|
||||
Version: webhook.Version,
|
||||
ParentID: webhook.ParentID,
|
||||
ParentType: webhook.ParentType,
|
||||
CreatedBy: webhook.CreatedBy,
|
||||
Created: webhook.Created,
|
||||
Updated: webhook.Updated,
|
||||
Type: webhook.Type,
|
||||
Scope: webhook.Scope,
|
||||
Identifier: webhook.Identifier,
|
||||
DisplayName: webhook.DisplayName,
|
||||
Description: webhook.Description,
|
||||
URL: webhook.URL,
|
||||
Secret: webhook.Secret,
|
||||
Enabled: webhook.Enabled,
|
||||
Insecure: webhook.Insecure,
|
||||
Triggers: webhook.Triggers,
|
||||
LatestExecutionResult: webhook.LatestExecutionResult,
|
||||
}
|
||||
}
|
||||
|
||||
func CoreWebhookToGitnessWebhook(webhook *types.WebhookCore) *types.Webhook {
|
||||
return &types.Webhook{
|
||||
ID: webhook.ID,
|
||||
Version: webhook.Version,
|
||||
ParentID: webhook.ParentID,
|
||||
ParentType: webhook.ParentType,
|
||||
CreatedBy: webhook.CreatedBy,
|
||||
Created: webhook.Created,
|
||||
Updated: webhook.Updated,
|
||||
Type: webhook.Type,
|
||||
Scope: webhook.Scope,
|
||||
Identifier: webhook.Identifier,
|
||||
DisplayName: webhook.DisplayName,
|
||||
Description: webhook.Description,
|
||||
URL: webhook.URL,
|
||||
Secret: webhook.Secret,
|
||||
Enabled: webhook.Enabled,
|
||||
Insecure: webhook.Insecure,
|
||||
Triggers: webhook.Triggers,
|
||||
LatestExecutionResult: webhook.LatestExecutionResult,
|
||||
}
|
||||
}
|
||||
|
||||
func GitnessWebhooksToWebhooksCore(webhooks []*types.Webhook) []*types.WebhookCore {
|
||||
webhooksCore := make([]*types.WebhookCore, 0)
|
||||
for _, webhook := range webhooks {
|
||||
webhookCore := GitnessWebhookToWebhookCore(webhook)
|
||||
webhooksCore = append(webhooksCore, webhookCore)
|
||||
}
|
||||
return webhooksCore
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ func NewURLProvider(_ context.Context) *GitnessURLProvider {
|
||||
return &GitnessURLProvider{}
|
||||
}
|
||||
|
||||
func (u *GitnessURLProvider) GetWebhookURL(_ context.Context, webhook *types.Webhook) (string, error) {
|
||||
func (u *GitnessURLProvider) GetWebhookURL(_ context.Context, webhook *types.WebhookCore) (string, error) {
|
||||
// set URL as is (already has been validated, any other error will be caught in request creation)
|
||||
return webhook.URL, nil
|
||||
}
|
||||
|
@ -21,5 +21,5 @@ import (
|
||||
)
|
||||
|
||||
type URLProvider interface {
|
||||
GetWebhookURL(ctx context.Context, webhook *types.Webhook) (string, error)
|
||||
GetWebhookURL(ctx context.Context, webhook *types.WebhookCore) (string, error)
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ import (
|
||||
"github.com/harness/gitness/encrypt"
|
||||
"github.com/harness/gitness/events"
|
||||
"github.com/harness/gitness/git"
|
||||
"github.com/harness/gitness/secret"
|
||||
"github.com/harness/gitness/store/database/dbtx"
|
||||
|
||||
"github.com/google/wire"
|
||||
@ -56,6 +57,8 @@ func ProvideService(
|
||||
webhookURLProvider URLProvider,
|
||||
labelValueStore store.LabelValueStore,
|
||||
sseStreamer sse.Streamer,
|
||||
secretService secret.Service,
|
||||
spacePathStore store.SpacePathStore,
|
||||
) (*Service, error) {
|
||||
return NewService(
|
||||
ctx,
|
||||
@ -76,6 +79,8 @@ func ProvideService(
|
||||
webhookURLProvider,
|
||||
labelValueStore,
|
||||
sseStreamer,
|
||||
secretService,
|
||||
spacePathStore,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -29,6 +29,7 @@ import (
|
||||
"github.com/harness/gitness/app/services/trigger"
|
||||
"github.com/harness/gitness/app/services/webhook"
|
||||
"github.com/harness/gitness/job"
|
||||
registrywebhooks "github.com/harness/gitness/registry/services/webhook"
|
||||
|
||||
"github.com/google/wire"
|
||||
)
|
||||
@ -38,20 +39,21 @@ var WireSet = wire.NewSet(
|
||||
)
|
||||
|
||||
type Services struct {
|
||||
Webhook *webhook.Service
|
||||
PullReq *pullreq.Service
|
||||
Trigger *trigger.Service
|
||||
JobScheduler *job.Scheduler
|
||||
MetricCollector *metric.Collector
|
||||
RepoSizeCalculator *repo.SizeCalculator
|
||||
Repo *repo.Service
|
||||
Cleanup *cleanup.Service
|
||||
Notification *notification.Service
|
||||
Keywordsearch *keywordsearch.Service
|
||||
GitspaceService *GitspaceServices
|
||||
Instrumentation instrument.Service
|
||||
instrumentConsumer instrument.Consumer
|
||||
instrumentRepoCounter *instrument.RepositoryCount
|
||||
Webhook *webhook.Service
|
||||
PullReq *pullreq.Service
|
||||
Trigger *trigger.Service
|
||||
JobScheduler *job.Scheduler
|
||||
MetricCollector *metric.Collector
|
||||
RepoSizeCalculator *repo.SizeCalculator
|
||||
Repo *repo.Service
|
||||
Cleanup *cleanup.Service
|
||||
Notification *notification.Service
|
||||
Keywordsearch *keywordsearch.Service
|
||||
GitspaceService *GitspaceServices
|
||||
Instrumentation instrument.Service
|
||||
instrumentConsumer instrument.Consumer
|
||||
instrumentRepoCounter *instrument.RepositoryCount
|
||||
registryWebhooksService *registrywebhooks.Service
|
||||
}
|
||||
|
||||
type GitspaceServices struct {
|
||||
@ -90,21 +92,23 @@ func ProvideServices(
|
||||
instrumentation instrument.Service,
|
||||
instrumentConsumer instrument.Consumer,
|
||||
instrumentRepoCounter *instrument.RepositoryCount,
|
||||
registryWebhooksService *registrywebhooks.Service,
|
||||
) Services {
|
||||
return Services{
|
||||
Webhook: webhooksSvc,
|
||||
PullReq: pullReqSvc,
|
||||
Trigger: triggerSvc,
|
||||
JobScheduler: jobScheduler,
|
||||
MetricCollector: metricCollector,
|
||||
RepoSizeCalculator: repoSizeCalculator,
|
||||
Repo: repo,
|
||||
Cleanup: cleanupSvc,
|
||||
Notification: notificationSvc,
|
||||
Keywordsearch: keywordsearchSvc,
|
||||
GitspaceService: gitspaceSvc,
|
||||
Instrumentation: instrumentation,
|
||||
instrumentConsumer: instrumentConsumer,
|
||||
instrumentRepoCounter: instrumentRepoCounter,
|
||||
Webhook: webhooksSvc,
|
||||
PullReq: pullReqSvc,
|
||||
Trigger: triggerSvc,
|
||||
JobScheduler: jobScheduler,
|
||||
MetricCollector: metricCollector,
|
||||
RepoSizeCalculator: repoSizeCalculator,
|
||||
Repo: repo,
|
||||
Cleanup: cleanupSvc,
|
||||
Notification: notificationSvc,
|
||||
Keywordsearch: keywordsearchSvc,
|
||||
GitspaceService: gitspaceSvc,
|
||||
Instrumentation: instrumentation,
|
||||
instrumentConsumer: instrumentConsumer,
|
||||
instrumentRepoCounter: instrumentRepoCounter,
|
||||
registryWebhooksService: registryWebhooksService,
|
||||
}
|
||||
}
|
||||
|
@ -259,7 +259,12 @@ type (
|
||||
FindActiveByUID(ctx context.Context, parentSpaceID int64, uid string) (*types.Repository, error)
|
||||
|
||||
// FindDeletedByUID finds a deleted repo by UID.
|
||||
FindDeletedByUID(ctx context.Context, parentSpaceID int64, uid string, deletedAt int64) (*types.Repository, error)
|
||||
FindDeletedByUID(
|
||||
ctx context.Context,
|
||||
parentSpaceID int64,
|
||||
uid string,
|
||||
deletedAt int64,
|
||||
) (*types.Repository, error)
|
||||
|
||||
// Create a new repo.
|
||||
Create(ctx context.Context, repo *types.Repository) error
|
||||
@ -429,7 +434,11 @@ type (
|
||||
Stream(ctx context.Context, opts *types.PullReqFilter) (<-chan *types.PullReq, <-chan error)
|
||||
|
||||
// ListOpenByBranchName returns open pull requests for each branch.
|
||||
ListOpenByBranchName(ctx context.Context, repoID int64, branchNames []string) (map[string][]*types.PullReq, error)
|
||||
ListOpenByBranchName(
|
||||
ctx context.Context,
|
||||
repoID int64,
|
||||
branchNames []string,
|
||||
) (map[string][]*types.PullReq, error)
|
||||
}
|
||||
|
||||
PullReqActivityStore interface {
|
||||
|
@ -271,8 +271,10 @@ func (s *WebhookStore) Update(ctx context.Context, hook *types.Webhook) error {
|
||||
}
|
||||
|
||||
// UpdateOptLock updates the webhook using the optimistic locking mechanism.
|
||||
func (s *WebhookStore) UpdateOptLock(ctx context.Context, hook *types.Webhook,
|
||||
mutateFn func(hook *types.Webhook) error) (*types.Webhook, error) {
|
||||
func (s *WebhookStore) UpdateOptLock(
|
||||
ctx context.Context, hook *types.Webhook,
|
||||
mutateFn func(hook *types.Webhook) error,
|
||||
) (*types.Webhook, error) {
|
||||
for {
|
||||
dup := *hook
|
||||
|
||||
|
@ -23,7 +23,7 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/harness/gitness/app/paths"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -80,6 +80,9 @@ type Provider interface {
|
||||
RegistryURL(ctx context.Context, params ...string) string
|
||||
|
||||
GetUIBaseURL(ctx context.Context, params ...string) string
|
||||
|
||||
// GenerateUIRegistryURL returns the url for the UI screen of a registry.
|
||||
GenerateUIRegistryURL(ctx context.Context, parentSpacePath string, registryName string) string
|
||||
}
|
||||
|
||||
// Provider provides the URLs of the Harness system.
|
||||
@ -239,12 +242,7 @@ func (p *provider) GetAPIProto(context.Context) string {
|
||||
}
|
||||
|
||||
func (p *provider) RegistryURL(_ context.Context, params ...string) string {
|
||||
u, err := url.Parse(p.registryURL.String())
|
||||
if err != nil {
|
||||
log.Warn().Msgf("failed to parse registry url: %v", err)
|
||||
return p.registryURL.String()
|
||||
}
|
||||
|
||||
u := *p.registryURL
|
||||
segments := []string{u.Path}
|
||||
if len(params) > 0 {
|
||||
if len(params) > 1 && (params[1] == "generic" || params[1] == "maven") {
|
||||
@ -263,6 +261,15 @@ func (p *provider) GetUIBaseURL(_ context.Context, _ ...string) string {
|
||||
return p.uiURL.String()
|
||||
}
|
||||
|
||||
func (p *provider) GenerateUIRegistryURL(_ context.Context, parentSpacePath string, registryName string) string {
|
||||
segments := paths.Segments(parentSpacePath)
|
||||
if len(segments) < 1 {
|
||||
return ""
|
||||
}
|
||||
space := segments[0]
|
||||
return p.uiURL.String() + "/spaces/" + space + "/registries/" + registryName
|
||||
}
|
||||
|
||||
func BuildGITCloneSSHURL(user string, sshURL *url.URL, repoPath string) string {
|
||||
repoPath = path.Clean(repoPath)
|
||||
if !strings.HasSuffix(repoPath, GITSuffix) {
|
||||
|
@ -126,7 +126,9 @@ import (
|
||||
"github.com/harness/gitness/livelog"
|
||||
"github.com/harness/gitness/lock"
|
||||
"github.com/harness/gitness/pubsub"
|
||||
registryevents "github.com/harness/gitness/registry/app/events"
|
||||
"github.com/harness/gitness/registry/app/pkg/docker"
|
||||
registrywebhooks "github.com/harness/gitness/registry/services/webhook"
|
||||
"github.com/harness/gitness/ssh"
|
||||
"github.com/harness/gitness/store/database/dbtx"
|
||||
"github.com/harness/gitness/types"
|
||||
@ -273,6 +275,8 @@ func initSystem(ctx context.Context, config *types.Config) (*cliserver.System, e
|
||||
secretservice.WireSet,
|
||||
runarg.WireSet,
|
||||
usage.WireSet,
|
||||
registryevents.WireSet,
|
||||
registrywebhooks.WireSet,
|
||||
)
|
||||
return &cliserver.System{}, nil
|
||||
}
|
||||
|
@ -119,6 +119,7 @@ import (
|
||||
"github.com/harness/gitness/pubsub"
|
||||
api2 "github.com/harness/gitness/registry/app/api"
|
||||
"github.com/harness/gitness/registry/app/api/router"
|
||||
events8 "github.com/harness/gitness/registry/app/events"
|
||||
"github.com/harness/gitness/registry/app/pkg"
|
||||
"github.com/harness/gitness/registry/app/pkg/docker"
|
||||
"github.com/harness/gitness/registry/app/pkg/filemanager"
|
||||
@ -127,6 +128,7 @@ import (
|
||||
"github.com/harness/gitness/registry/app/pkg/pypi"
|
||||
database2 "github.com/harness/gitness/registry/app/store/database"
|
||||
"github.com/harness/gitness/registry/gc"
|
||||
webhook3 "github.com/harness/gitness/registry/services/webhook"
|
||||
"github.com/harness/gitness/ssh"
|
||||
"github.com/harness/gitness/store/database/dbtx"
|
||||
"github.com/harness/gitness/types"
|
||||
@ -384,7 +386,8 @@ func initSystem(ctx context.Context, config *types.Config) (*server.System, erro
|
||||
webhookStore := database.ProvideWebhookStore(db)
|
||||
webhookExecutionStore := database.ProvideWebhookExecutionStore(db)
|
||||
urlProvider := webhook.ProvideURLProvider(ctx)
|
||||
webhookService, err := webhook.ProvideService(ctx, webhookConfig, transactor, readerFactory, eventsReaderFactory, webhookStore, webhookExecutionStore, spaceStore, repoStore, pullReqStore, pullReqActivityStore, provider, principalStore, gitInterface, encrypter, labelStore, urlProvider, labelValueStore, streamer)
|
||||
secretService := secret3.ProvideSecretService(secretStore, encrypter, spaceFinder)
|
||||
webhookService, err := webhook.ProvideService(ctx, webhookConfig, transactor, readerFactory, eventsReaderFactory, webhookStore, webhookExecutionStore, spaceStore, repoStore, pullReqStore, pullReqActivityStore, provider, principalStore, gitInterface, encrypter, labelStore, urlProvider, labelValueStore, streamer, secretService, spacePathStore)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -451,13 +454,16 @@ func initSystem(ctx context.Context, config *types.Config) (*server.System, erro
|
||||
layerRepository := database2.ProvideLayerDao(db, mediaTypesRepository)
|
||||
eventReporter := docker.ProvideReporter()
|
||||
ociImageIndexMappingRepository := database2.ProvideOCIImageIndexMappingDao(db)
|
||||
manifestService := docker.ManifestServiceProvider(registryRepository, manifestRepository, blobRepository, mediaTypesRepository, manifestReferenceRepository, tagRepository, imageRepository, artifactRepository, layerRepository, gcService, transactor, eventReporter, spaceFinder, ociImageIndexMappingRepository)
|
||||
reporter6, err := events8.ProvideArtifactReporter(eventsSystem)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
manifestService := docker.ManifestServiceProvider(registryRepository, manifestRepository, blobRepository, mediaTypesRepository, manifestReferenceRepository, tagRepository, imageRepository, artifactRepository, layerRepository, gcService, transactor, eventReporter, spaceFinder, ociImageIndexMappingRepository, reporter6, provider)
|
||||
registryBlobRepository := database2.ProvideRegistryBlobDao(db)
|
||||
bandwidthStatRepository := database2.ProvideBandwidthStatDao(db)
|
||||
downloadStatRepository := database2.ProvideDownloadStatDao(db)
|
||||
localRegistry := docker.LocalRegistryProvider(app, manifestService, blobRepository, registryRepository, manifestRepository, registryBlobRepository, mediaTypesRepository, tagRepository, imageRepository, artifactRepository, bandwidthStatRepository, downloadStatRepository, gcService, transactor)
|
||||
upstreamProxyConfigRepository := database2.ProvideUpstreamDao(db, registryRepository, spaceFinder)
|
||||
secretService := secret3.ProvideSecretService(secretStore, encrypter, spaceFinder)
|
||||
proxyController := docker.ProvideProxyController(localRegistry, manifestService, secretService, spaceFinder)
|
||||
remoteRegistry := docker.RemoteRegistryProvider(localRegistry, app, upstreamProxyConfigRepository, spaceFinder, secretService, proxyController)
|
||||
coreController := pkg.CoreControllerProvider(registryRepository)
|
||||
@ -471,7 +477,16 @@ func initSystem(ctx context.Context, config *types.Config) (*server.System, erro
|
||||
fileManager := filemanager.Provider(filemanagerApp, registryRepository, genericBlobRepository, nodesRepository, transactor)
|
||||
cleanupPolicyRepository := database2.ProvideCleanupPolicyDao(db, transactor)
|
||||
webhooksRepository := database2.ProvideWebhookDao(db)
|
||||
apiHandler := router.APIHandlerProvider(registryRepository, upstreamProxyConfigRepository, fileManager, tagRepository, manifestRepository, cleanupPolicyRepository, imageRepository, storageDriver, spaceFinder, transactor, authenticator, provider, authorizer, auditService, artifactRepository, webhooksRepository)
|
||||
webhooksExecutionRepository := database2.ProvideWebhookExecutionDao(db)
|
||||
readerFactory2, err := events8.ProvideReaderFactory(eventsSystem)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
service2, err := webhook3.ProvideService(ctx, webhookConfig, transactor, readerFactory2, webhooksRepository, webhooksExecutionRepository, spaceStore, provider, principalStore, urlProvider, spacePathStore, secretService, registryRepository, encrypter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
apiHandler := router.APIHandlerProvider(registryRepository, upstreamProxyConfigRepository, fileManager, tagRepository, manifestRepository, cleanupPolicyRepository, imageRepository, storageDriver, spaceFinder, transactor, authenticator, provider, authorizer, auditService, artifactRepository, webhooksRepository, webhooksExecutionRepository, service2, spacePathStore)
|
||||
mavenDBStore := maven.DBStoreProvider(registryRepository, imageRepository, artifactRepository, spaceStore, bandwidthStatRepository, downloadStatRepository, nodesRepository, upstreamProxyConfigRepository)
|
||||
mavenLocalRegistry := maven.LocalRegistryProvider(mavenDBStore, transactor, fileManager)
|
||||
mavenController := maven.ProvideProxyController(mavenLocalRegistry, secretService, spaceFinder)
|
||||
@ -514,11 +529,11 @@ func initSystem(ctx context.Context, config *types.Config) (*server.System, erro
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
readerFactory2, err := events2.ProvideReaderFactory(eventsSystem)
|
||||
readerFactory3, err := events2.ProvideReaderFactory(eventsSystem)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
repoService, err := repo2.ProvideService(ctx, config, reporter, readerFactory2, repoStore, provider, gitInterface, lockerLocker)
|
||||
repoService, err := repo2.ProvideService(ctx, config, reporter, readerFactory3, repoStore, provider, gitInterface, lockerLocker)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -535,24 +550,24 @@ func initSystem(ctx context.Context, config *types.Config) (*server.System, erro
|
||||
return nil, err
|
||||
}
|
||||
keywordsearchConfig := server.ProvideKeywordSearchConfig(config)
|
||||
keywordsearchService, err := keywordsearch.ProvideService(ctx, keywordsearchConfig, readerFactory, readerFactory2, repoStore, indexer)
|
||||
keywordsearchService, err := keywordsearch.ProvideService(ctx, keywordsearchConfig, readerFactory, readerFactory3, repoStore, indexer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
gitspaceeventConfig := server.ProvideGitspaceEventConfig(config)
|
||||
readerFactory3, err := events3.ProvideReaderFactory(eventsSystem)
|
||||
readerFactory4, err := events3.ProvideReaderFactory(eventsSystem)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
gitspaceeventService, err := gitspaceevent.ProvideService(ctx, gitspaceeventConfig, readerFactory3, gitspaceEventStore)
|
||||
gitspaceeventService, err := gitspaceevent.ProvideService(ctx, gitspaceeventConfig, readerFactory4, gitspaceEventStore)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
readerFactory4, err := events4.ProvideReaderFactory(eventsSystem)
|
||||
readerFactory5, err := events4.ProvideReaderFactory(eventsSystem)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
gitspaceinfraeventService, err := gitspaceinfraevent.ProvideService(ctx, gitspaceeventConfig, readerFactory4, orchestratorOrchestrator, gitspaceService, eventsReporter)
|
||||
gitspaceinfraeventService, err := gitspaceinfraevent.ProvideService(ctx, gitspaceeventConfig, readerFactory5, orchestratorOrchestrator, gitspaceService, eventsReporter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -565,7 +580,7 @@ func initSystem(ctx context.Context, config *types.Config) (*server.System, erro
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
servicesServices := services.ProvideServices(webhookService, pullreqService, triggerService, jobScheduler, collector, sizeCalculator, repoService, cleanupService, notificationService, keywordsearchService, gitspaceServices, instrumentService, consumer, repositoryCount)
|
||||
servicesServices := services.ProvideServices(webhookService, pullreqService, triggerService, jobScheduler, collector, sizeCalculator, repoService, cleanupService, notificationService, keywordsearchService, gitspaceServices, instrumentService, consumer, repositoryCount, service2)
|
||||
serverSystem := server.NewSystem(bootstrapBootstrap, serverServer, sshServer, poller, resolverManager, servicesServices)
|
||||
return serverSystem, nil
|
||||
}
|
||||
|
@ -22,13 +22,12 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/harness/gitness/app/paths"
|
||||
api "github.com/harness/gitness/registry/app/api/openapi/contracts/artifact"
|
||||
storagedriver "github.com/harness/gitness/registry/app/driver"
|
||||
"github.com/harness/gitness/registry/app/pkg/commons"
|
||||
"github.com/harness/gitness/registry/app/storage"
|
||||
"github.com/harness/gitness/registry/types"
|
||||
registryenum "github.com/harness/gitness/registry/types/enum"
|
||||
gitnessenum "github.com/harness/gitness/types/enum"
|
||||
|
||||
digest "github.com/opencontainers/go-digest"
|
||||
"github.com/rs/zerolog/log"
|
||||
@ -91,63 +90,6 @@ type ArtifactFilesRequestInfo struct {
|
||||
searchTerm string
|
||||
}
|
||||
|
||||
// GetRegistryRequestBaseInfo returns the base info for the registry request
|
||||
// One of the regRefParam or (parentRefParam + regIdentifierParam) should be provided.
|
||||
func (c *APIController) GetRegistryRequestBaseInfo(
|
||||
ctx context.Context,
|
||||
parentRef string,
|
||||
regRef string,
|
||||
) (*RegistryRequestBaseInfo, error) {
|
||||
// ---------- CHECKS ------------
|
||||
if commons.IsEmpty(parentRef) && !commons.IsEmpty(regRef) {
|
||||
parentRef, _, _ = paths.DisectLeaf(regRef)
|
||||
}
|
||||
|
||||
// ---------- PARENT ------------
|
||||
if commons.IsEmpty(parentRef) {
|
||||
return nil, fmt.Errorf("parent reference is required")
|
||||
}
|
||||
rootIdentifier, _, err := paths.DisectRoot(parentRef)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid parent reference: %w", err)
|
||||
}
|
||||
|
||||
rootSpace, err := c.SpaceFinder.FindByRef(ctx, rootIdentifier)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("root space not found: %w", err)
|
||||
}
|
||||
parentSpace, err := c.SpaceFinder.FindByRef(ctx, parentRef)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parent space not found: %w", err)
|
||||
}
|
||||
rootIdentifierID := rootSpace.ID
|
||||
parentID := parentSpace.ID
|
||||
|
||||
baseInfo := &RegistryRequestBaseInfo{
|
||||
ParentRef: parentRef,
|
||||
parentID: parentID,
|
||||
RootIdentifier: rootIdentifier,
|
||||
rootIdentifierID: rootIdentifierID,
|
||||
}
|
||||
|
||||
// ---------- REGISTRY ------------
|
||||
if !commons.IsEmpty(regRef) {
|
||||
_, regIdentifier, _ := paths.DisectLeaf(regRef)
|
||||
|
||||
reg, getRegistryErr := c.RegistryRepository.GetByParentIDAndName(ctx, parentID, regIdentifier)
|
||||
if getRegistryErr != nil {
|
||||
return nil, fmt.Errorf("registry not found: %w", err)
|
||||
}
|
||||
|
||||
baseInfo.RegistryRef = regRef
|
||||
baseInfo.RegistryIdentifier = regIdentifier
|
||||
baseInfo.RegistryID = reg.ID
|
||||
baseInfo.RegistryType = reg.Type
|
||||
}
|
||||
|
||||
return baseInfo, nil
|
||||
}
|
||||
|
||||
func (c *APIController) GetRegistryRequestInfo(
|
||||
ctx context.Context,
|
||||
registryRequestParams RegistryRequestParams,
|
||||
@ -188,7 +130,8 @@ func (c *APIController) GetRegistryRequestInfo(
|
||||
searchTerm = string(*registryRequestParams.search)
|
||||
}
|
||||
|
||||
baseInfo, err := c.GetRegistryRequestBaseInfo(ctx, registryRequestParams.ParentRef, registryRequestParams.RegRef)
|
||||
baseInfo, err := c.RegistryMetadataHelper.GetRegistryRequestBaseInfo(ctx, registryRequestParams.ParentRef,
|
||||
registryRequestParams.RegRef)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -419,97 +362,14 @@ func CreateUpstreamProxyResponseJSONResponse(upstreamproxy *types.UpstreamProxy)
|
||||
return response
|
||||
}
|
||||
|
||||
func (c *APIController) mapToWebhookResponseEntity(
|
||||
ctx context.Context,
|
||||
createdWebhook types.Webhook,
|
||||
) (*api.Webhook, error) {
|
||||
createdAt := GetTimeInMs(createdWebhook.CreatedAt)
|
||||
modifiedAt := GetTimeInMs(createdWebhook.UpdatedAt)
|
||||
webhookResponseEntity := &api.Webhook{
|
||||
Identifier: createdWebhook.Identifier,
|
||||
Name: createdWebhook.Name,
|
||||
Description: &createdWebhook.Description,
|
||||
Url: createdWebhook.URL,
|
||||
Version: &createdWebhook.Version,
|
||||
Enabled: createdWebhook.Enabled,
|
||||
Internal: &createdWebhook.Internal,
|
||||
Insecure: createdWebhook.Insecure,
|
||||
Triggers: &createdWebhook.Triggers,
|
||||
CreatedBy: &createdWebhook.CreatedBy,
|
||||
CreatedAt: &createdAt,
|
||||
ModifiedAt: &modifiedAt,
|
||||
LatestExecutionResult: createdWebhook.LatestExecutionResult,
|
||||
}
|
||||
if createdWebhook.ExtraHeaders != nil {
|
||||
webhookResponseEntity.ExtraHeaders = &createdWebhook.ExtraHeaders
|
||||
}
|
||||
secretSpacePath := ""
|
||||
if createdWebhook.SecretSpaceID > 0 {
|
||||
primary, err := c.SpaceFinder.FindByID(ctx, int64(createdWebhook.SecretSpaceID))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get secret space path: %w", err)
|
||||
}
|
||||
secretSpacePath = primary.Path
|
||||
}
|
||||
if createdWebhook.SecretIdentifier != "" {
|
||||
webhookResponseEntity.SecretIdentifier = &createdWebhook.SecretIdentifier
|
||||
}
|
||||
if secretSpacePath != "" {
|
||||
webhookResponseEntity.SecretSpacePath = &secretSpacePath
|
||||
}
|
||||
if createdWebhook.SecretSpaceID > 0 {
|
||||
webhookResponseEntity.SecretSpaceId = &createdWebhook.SecretSpaceID
|
||||
}
|
||||
|
||||
return webhookResponseEntity, nil
|
||||
}
|
||||
|
||||
func (c *APIController) mapToWebhook(
|
||||
ctx context.Context,
|
||||
webhookRequest api.WebhookRequest,
|
||||
regInfo *RegistryRequestBaseInfo,
|
||||
) (*types.Webhook, error) {
|
||||
webhook := &types.Webhook{
|
||||
Name: webhookRequest.Identifier,
|
||||
ParentType: registryenum.WebhookParentRegistry,
|
||||
ParentID: regInfo.RegistryID,
|
||||
Scope: webhookScopeRegistry,
|
||||
Identifier: webhookRequest.Identifier,
|
||||
URL: webhookRequest.Url,
|
||||
Enabled: webhookRequest.Enabled,
|
||||
Insecure: webhookRequest.Insecure,
|
||||
Triggers: deduplicateTriggers(*webhookRequest.Triggers),
|
||||
}
|
||||
if webhookRequest.Description != nil {
|
||||
webhook.Description = *webhookRequest.Description
|
||||
}
|
||||
if webhookRequest.SecretIdentifier != nil {
|
||||
webhook.SecretIdentifier = *webhookRequest.SecretIdentifier
|
||||
}
|
||||
if webhookRequest.ExtraHeaders != nil {
|
||||
webhook.ExtraHeaders = *webhookRequest.ExtraHeaders
|
||||
}
|
||||
|
||||
if webhookRequest.SecretSpacePath != nil && len(*webhookRequest.SecretSpacePath) > 0 {
|
||||
secretSpaceID, err := c.getSecretSpaceID(ctx, webhookRequest.SecretSpacePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
webhook.SecretSpaceID = secretSpaceID
|
||||
} else if webhookRequest.SecretSpaceId != nil {
|
||||
webhook.SecretSpaceID = *webhookRequest.SecretSpaceId
|
||||
}
|
||||
return webhook, nil
|
||||
}
|
||||
|
||||
// deduplicateTriggers de-duplicates the triggers provided by the user.
|
||||
func deduplicateTriggers(in []api.Trigger) []api.Trigger {
|
||||
func deduplicateTriggers(in []gitnessenum.WebhookTrigger) []gitnessenum.WebhookTrigger {
|
||||
if len(in) == 0 {
|
||||
return []api.Trigger{}
|
||||
return []gitnessenum.WebhookTrigger{}
|
||||
}
|
||||
|
||||
triggerSet := make(map[api.Trigger]bool, len(in))
|
||||
out := make([]api.Trigger, 0, len(in))
|
||||
triggerSet := make(map[gitnessenum.WebhookTrigger]bool, len(in))
|
||||
out := make([]gitnessenum.WebhookTrigger, 0, len(in))
|
||||
for _, trigger := range in {
|
||||
if triggerSet[trigger] {
|
||||
continue
|
||||
@ -547,7 +407,7 @@ func (c *APIController) GetArtifactFilesRequestInfo(
|
||||
searchTerm = string(*r.Params.SearchTerm)
|
||||
}
|
||||
|
||||
baseInfo, err := c.GetRegistryRequestBaseInfo(ctx, "", string(r.RegistryRef))
|
||||
baseInfo, err := c.RegistryMetadataHelper.GetRegistryRequestBaseInfo(ctx, "", string(r.RegistryRef))
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -22,28 +22,32 @@ import (
|
||||
storagedriver "github.com/harness/gitness/registry/app/driver"
|
||||
"github.com/harness/gitness/registry/app/pkg/filemanager"
|
||||
"github.com/harness/gitness/registry/app/store"
|
||||
registrywebhook "github.com/harness/gitness/registry/services/webhook"
|
||||
"github.com/harness/gitness/store/database/dbtx"
|
||||
)
|
||||
|
||||
// APIController simple struct.
|
||||
type APIController struct {
|
||||
ImageStore store.ImageRepository
|
||||
fileManager filemanager.FileManager
|
||||
BlobStore store.BlobRepository
|
||||
GenericBlobStore store.GenericBlobRepository
|
||||
RegistryRepository store.RegistryRepository
|
||||
UpstreamProxyStore store.UpstreamProxyConfigRepository
|
||||
TagStore store.TagRepository
|
||||
ManifestStore store.ManifestRepository
|
||||
CleanupPolicyStore store.CleanupPolicyRepository
|
||||
SpaceFinder refcache.SpaceFinder
|
||||
tx dbtx.Transactor
|
||||
StorageDriver storagedriver.StorageDriver
|
||||
URLProvider urlprovider.Provider
|
||||
Authorizer authz.Authorizer
|
||||
AuditService audit.Service
|
||||
ArtifactStore store.ArtifactRepository
|
||||
WebhooksRepository store.WebhooksRepository
|
||||
ImageStore store.ImageRepository
|
||||
fileManager filemanager.FileManager
|
||||
BlobStore store.BlobRepository
|
||||
GenericBlobStore store.GenericBlobRepository
|
||||
RegistryRepository store.RegistryRepository
|
||||
UpstreamProxyStore store.UpstreamProxyConfigRepository
|
||||
TagStore store.TagRepository
|
||||
ManifestStore store.ManifestRepository
|
||||
CleanupPolicyStore store.CleanupPolicyRepository
|
||||
SpaceFinder refcache.SpaceFinder
|
||||
tx dbtx.Transactor
|
||||
StorageDriver storagedriver.StorageDriver
|
||||
URLProvider urlprovider.Provider
|
||||
Authorizer authz.Authorizer
|
||||
AuditService audit.Service
|
||||
ArtifactStore store.ArtifactRepository
|
||||
WebhooksRepository store.WebhooksRepository
|
||||
WebhooksExecutionRepository store.WebhooksExecutionRepository
|
||||
RegistryMetadataHelper RegistryMetadataHelper
|
||||
WebhookService registrywebhook.Service
|
||||
}
|
||||
|
||||
func NewAPIController(
|
||||
@ -64,24 +68,30 @@ func NewAPIController(
|
||||
auditService audit.Service,
|
||||
artifactStore store.ArtifactRepository,
|
||||
webhooksRepository store.WebhooksRepository,
|
||||
webhooksExecutionRepository store.WebhooksExecutionRepository,
|
||||
registryMetadataHelper RegistryMetadataHelper,
|
||||
webhookService registrywebhook.Service,
|
||||
) *APIController {
|
||||
return &APIController{
|
||||
fileManager: fileManager,
|
||||
GenericBlobStore: genericBlobStore,
|
||||
BlobStore: blobStore,
|
||||
RegistryRepository: repositoryStore,
|
||||
UpstreamProxyStore: upstreamProxyStore,
|
||||
TagStore: tagStore,
|
||||
ManifestStore: manifestStore,
|
||||
CleanupPolicyStore: cleanupPolicyStore,
|
||||
ImageStore: imageStore,
|
||||
SpaceFinder: spaceFinder,
|
||||
StorageDriver: driver,
|
||||
tx: tx,
|
||||
URLProvider: urlProvider,
|
||||
Authorizer: authorizer,
|
||||
AuditService: auditService,
|
||||
ArtifactStore: artifactStore,
|
||||
WebhooksRepository: webhooksRepository,
|
||||
fileManager: fileManager,
|
||||
GenericBlobStore: genericBlobStore,
|
||||
BlobStore: blobStore,
|
||||
RegistryRepository: repositoryStore,
|
||||
UpstreamProxyStore: upstreamProxyStore,
|
||||
TagStore: tagStore,
|
||||
ManifestStore: manifestStore,
|
||||
CleanupPolicyStore: cleanupPolicyStore,
|
||||
ImageStore: imageStore,
|
||||
SpaceFinder: spaceFinder,
|
||||
StorageDriver: driver,
|
||||
tx: tx,
|
||||
URLProvider: urlProvider,
|
||||
Authorizer: authorizer,
|
||||
AuditService: auditService,
|
||||
ArtifactStore: artifactStore,
|
||||
WebhooksRepository: webhooksRepository,
|
||||
WebhooksExecutionRepository: webhooksExecutionRepository,
|
||||
RegistryMetadataHelper: registryMetadataHelper,
|
||||
WebhookService: webhookService,
|
||||
}
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ func (c *APIController) CreateRegistry(
|
||||
registryRequest := artifact.RegistryRequest(*r.Body)
|
||||
parentRef := artifact.SpaceRefPathParam(*registryRequest.ParentRef)
|
||||
|
||||
regInfo, err := c.GetRegistryRequestBaseInfo(ctx, string(parentRef), "")
|
||||
regInfo, err := c.RegistryMetadataHelper.GetRegistryRequestBaseInfo(ctx, string(parentRef), "")
|
||||
if err != nil {
|
||||
return artifact.CreateRegistry400JSONResponse{
|
||||
BadRequestJSONResponse: artifact.BadRequestJSONResponse(
|
||||
@ -332,7 +332,7 @@ func (c *APIController) CreateUpstreamProxyEntity(
|
||||
}
|
||||
|
||||
if res.SecretSpacePath != nil && len(*res.SecretSpacePath) > 0 {
|
||||
upstreamProxyConfigEntity.SecretSpaceID, err = c.getSecretSpaceID(ctx, res.SecretSpacePath)
|
||||
upstreamProxyConfigEntity.SecretSpaceID, err = c.RegistryMetadataHelper.getSecretSpaceID(ctx, res.SecretSpacePath)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@ -353,7 +353,8 @@ func (c *APIController) CreateUpstreamProxyEntity(
|
||||
return nil, nil, fmt.Errorf("failed to create upstream proxy: access_key_secret_identifier missing")
|
||||
default:
|
||||
if res.AccessKeySecretSpacePath != nil && len(*res.AccessKeySecretSpacePath) > 0 {
|
||||
upstreamProxyConfigEntity.UserNameSecretSpaceID, err = c.getSecretSpaceID(ctx, res.AccessKeySecretSpacePath)
|
||||
upstreamProxyConfigEntity.UserNameSecretSpaceID, err =
|
||||
c.RegistryMetadataHelper.getSecretSpaceID(ctx, res.AccessKeySecretSpacePath)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@ -364,7 +365,7 @@ func (c *APIController) CreateUpstreamProxyEntity(
|
||||
}
|
||||
|
||||
if res.SecretKeySpacePath != nil && len(*res.SecretKeySpacePath) > 0 {
|
||||
upstreamProxyConfigEntity.SecretSpaceID, err = c.getSecretSpaceID(ctx, res.SecretKeySpacePath)
|
||||
upstreamProxyConfigEntity.SecretSpaceID, err = c.RegistryMetadataHelper.getSecretSpaceID(ctx, res.SecretKeySpacePath)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
@ -34,7 +34,10 @@ func (c *APIController) CreateWebhook(
|
||||
r api.CreateWebhookRequestObject,
|
||||
) (api.CreateWebhookResponseObject, error) {
|
||||
webhookRequest := api.WebhookRequest(*r.Body)
|
||||
regInfo, err := c.GetRegistryRequestBaseInfo(ctx, "", string(r.RegistryRef))
|
||||
if webhookRequest.Identifier == internalWebhookIdentifier {
|
||||
return createWebhookBadRequestErrorResponse(fmt.Errorf("webhook identifier %s is reserved", internalWebhookIdentifier))
|
||||
}
|
||||
regInfo, err := c.RegistryMetadataHelper.GetRegistryRequestBaseInfo(ctx, "", string(r.RegistryRef))
|
||||
if err != nil {
|
||||
return createWebhookBadRequestErrorResponse(err)
|
||||
}
|
||||
@ -49,7 +52,8 @@ func (c *APIController) CreateWebhook(
|
||||
return createWebhookBadRequestErrorResponse(err)
|
||||
}
|
||||
session, _ := request.AuthSessionFrom(ctx)
|
||||
permissionChecks := GetPermissionChecks(space, regInfo.RegistryIdentifier, enum.PermissionRegistryEdit)
|
||||
permissionChecks := c.RegistryMetadataHelper.GetPermissionChecks(space,
|
||||
regInfo.RegistryIdentifier, enum.PermissionRegistryEdit)
|
||||
if err = apiauth.CheckRegistry(
|
||||
ctx,
|
||||
c.Authorizer,
|
||||
@ -65,8 +69,8 @@ func (c *APIController) CreateWebhook(
|
||||
}, err
|
||||
}
|
||||
|
||||
webhook, err := c.mapToWebhook(ctx, webhookRequest, regInfo)
|
||||
webhook.Internal = false
|
||||
webhook, err := c.RegistryMetadataHelper.MapToWebhookCore(ctx, webhookRequest, regInfo)
|
||||
webhook.Type = enum.WebhookTypeExternal
|
||||
webhook.CreatedBy = session.Principal.ID
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Error().Msgf("failed to store webhook: %s with error: %v", webhookRequest.Identifier, err)
|
||||
@ -93,7 +97,7 @@ func (c *APIController) CreateWebhook(
|
||||
return createWebhookInternalErrorResponse(fmt.Errorf("failed to stored webhook: %w", err))
|
||||
}
|
||||
|
||||
webhookResponseEntity, err := c.mapToWebhookResponseEntity(ctx, *createdWebhook)
|
||||
webhookResponseEntity, err := c.RegistryMetadataHelper.MapToWebhookResponseEntity(ctx, createdWebhook)
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Error().Msgf("failed to stored webhook: %s with error: %v",
|
||||
webhookRequest.Identifier, err)
|
||||
|
@ -31,7 +31,7 @@ import (
|
||||
|
||||
func (c *APIController) DeleteArtifact(ctx context.Context, r artifact.DeleteArtifactRequestObject) (
|
||||
artifact.DeleteArtifactResponseObject, error) {
|
||||
regInfo, err := c.GetRegistryRequestBaseInfo(ctx, "", string(r.RegistryRef))
|
||||
regInfo, err := c.RegistryMetadataHelper.GetRegistryRequestBaseInfo(ctx, "", string(r.RegistryRef))
|
||||
if err != nil {
|
||||
return artifact.DeleteArtifact400JSONResponse{
|
||||
BadRequestJSONResponse: artifact.BadRequestJSONResponse(
|
||||
|
@ -30,7 +30,7 @@ import (
|
||||
|
||||
func (c *APIController) DeleteArtifactVersion(ctx context.Context, r artifact.DeleteArtifactVersionRequestObject) (
|
||||
artifact.DeleteArtifactVersionResponseObject, error) {
|
||||
regInfo, err := c.GetRegistryRequestBaseInfo(ctx, "", string(r.RegistryRef))
|
||||
regInfo, err := c.RegistryMetadataHelper.GetRegistryRequestBaseInfo(ctx, "", string(r.RegistryRef))
|
||||
if err != nil {
|
||||
return artifact.DeleteArtifactVersion400JSONResponse{
|
||||
BadRequestJSONResponse: artifact.BadRequestJSONResponse(
|
||||
@ -88,7 +88,8 @@ func (c *APIController) DeleteArtifactVersion(ctx context.Context, r artifact.De
|
||||
|
||||
func (c *APIController) deleteTagWithAudit(
|
||||
ctx context.Context, regInfo *RegistryRequestBaseInfo,
|
||||
registryName string, principal types.Principal, artifactName string, versionName string) error {
|
||||
registryName string, principal types.Principal, artifactName string, versionName string,
|
||||
) error {
|
||||
err := c.TagStore.DeleteTag(ctx, regInfo.RegistryID, artifactName, versionName)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -36,7 +36,7 @@ func (c *APIController) DeleteRegistry(
|
||||
ctx context.Context,
|
||||
r artifact.DeleteRegistryRequestObject,
|
||||
) (artifact.DeleteRegistryResponseObject, error) {
|
||||
regInfo, err := c.GetRegistryRequestBaseInfo(ctx, "", string(r.RegistryRef))
|
||||
regInfo, err := c.RegistryMetadataHelper.GetRegistryRequestBaseInfo(ctx, "", string(r.RegistryRef))
|
||||
if err != nil {
|
||||
return artifact.DeleteRegistry400JSONResponse{
|
||||
BadRequestJSONResponse: artifact.BadRequestJSONResponse(
|
||||
@ -54,7 +54,8 @@ func (c *APIController) DeleteRegistry(
|
||||
}
|
||||
|
||||
session, _ := request.AuthSessionFrom(ctx)
|
||||
permissionChecks := GetPermissionChecks(space, regInfo.RegistryIdentifier, enum.PermissionRegistryDelete)
|
||||
permissionChecks := c.RegistryMetadataHelper.GetPermissionChecks(space,
|
||||
regInfo.RegistryIdentifier, enum.PermissionRegistryDelete)
|
||||
if err = apiauth.CheckRegistry(
|
||||
ctx,
|
||||
c.Authorizer,
|
||||
|
@ -16,19 +16,22 @@ package metadata
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
apiauth "github.com/harness/gitness/app/api/auth"
|
||||
"github.com/harness/gitness/app/api/request"
|
||||
api "github.com/harness/gitness/registry/app/api/openapi/contracts/artifact"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
func (c *APIController) DeleteWebhook(
|
||||
ctx context.Context,
|
||||
r api.DeleteWebhookRequestObject,
|
||||
) (api.DeleteWebhookResponseObject, error) {
|
||||
regInfo, err := c.GetRegistryRequestBaseInfo(ctx, "", string(r.RegistryRef))
|
||||
regInfo, err := c.RegistryMetadataHelper.GetRegistryRequestBaseInfo(ctx, "", string(r.RegistryRef))
|
||||
if err != nil {
|
||||
return deleteWebhookInternalErrorResponse(err)
|
||||
}
|
||||
@ -39,7 +42,8 @@ func (c *APIController) DeleteWebhook(
|
||||
}
|
||||
|
||||
session, _ := request.AuthSessionFrom(ctx)
|
||||
permissionChecks := GetPermissionChecks(space, regInfo.RegistryIdentifier, enum.PermissionRegistryEdit)
|
||||
permissionChecks := c.RegistryMetadataHelper.GetPermissionChecks(space,
|
||||
regInfo.RegistryIdentifier, enum.PermissionRegistryEdit)
|
||||
if err = apiauth.CheckRegistry(
|
||||
ctx,
|
||||
c.Authorizer,
|
||||
@ -54,6 +58,16 @@ func (c *APIController) DeleteWebhook(
|
||||
}
|
||||
|
||||
webhookIdentifier := string(r.WebhookIdentifier)
|
||||
existingWebhook, err := c.WebhooksRepository.GetByRegistryAndIdentifier(ctx, regInfo.RegistryID, webhookIdentifier)
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Error().Msgf("failed to get existing webhook: %s with error: %v",
|
||||
webhookIdentifier, err)
|
||||
return deleteWebhookInternalErrorResponse(fmt.Errorf("failed to get existing webhook"))
|
||||
}
|
||||
if existingWebhook.Type == enum.WebhookTypeInternal {
|
||||
return deleteWebhookBadRequestErrorResponse(fmt.Errorf("cannot delete internal webhook: %s", webhookIdentifier))
|
||||
}
|
||||
|
||||
err = c.WebhooksRepository.DeleteByRegistryAndIdentifier(ctx, regInfo.RegistryID, webhookIdentifier)
|
||||
if err != nil {
|
||||
return deleteWebhookInternalErrorResponse(err)
|
||||
@ -70,3 +84,11 @@ func deleteWebhookInternalErrorResponse(err error) (api.DeleteWebhookResponseObj
|
||||
),
|
||||
}, err
|
||||
}
|
||||
|
||||
func deleteWebhookBadRequestErrorResponse(err error) (api.DeleteWebhookResponseObject, error) {
|
||||
return api.DeleteWebhook400JSONResponse{
|
||||
BadRequestJSONResponse: api.BadRequestJSONResponse(
|
||||
*GetErrorResponse(http.StatusBadRequest, err.Error()),
|
||||
),
|
||||
}, err
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ func (c *APIController) GetArtifactDetails(
|
||||
ctx context.Context,
|
||||
r artifact.GetArtifactDetailsRequestObject,
|
||||
) (artifact.GetArtifactDetailsResponseObject, error) {
|
||||
regInfo, err := c.GetRegistryRequestBaseInfo(ctx, "", string(r.RegistryRef))
|
||||
regInfo, err := c.RegistryMetadataHelper.GetRegistryRequestBaseInfo(ctx, "", string(r.RegistryRef))
|
||||
if err != nil {
|
||||
return artifact.GetArtifactDetails400JSONResponse{
|
||||
BadRequestJSONResponse: artifact.BadRequestJSONResponse(
|
||||
@ -49,7 +49,8 @@ func (c *APIController) GetArtifactDetails(
|
||||
}
|
||||
|
||||
session, _ := request.AuthSessionFrom(ctx)
|
||||
permissionChecks := GetPermissionChecks(space, regInfo.RegistryIdentifier, enum.PermissionRegistryView)
|
||||
permissionChecks := c.RegistryMetadataHelper.GetPermissionChecks(space,
|
||||
regInfo.RegistryIdentifier, enum.PermissionRegistryView)
|
||||
if err = apiauth.CheckRegistry(
|
||||
ctx,
|
||||
c.Authorizer,
|
||||
|
@ -51,7 +51,8 @@ func (c *APIController) GetArtifactFiles(
|
||||
}
|
||||
|
||||
session, _ := request.AuthSessionFrom(ctx)
|
||||
permissionChecks := GetPermissionChecks(space, reqInfo.RegistryIdentifier, enum.PermissionRegistryView)
|
||||
permissionChecks := c.RegistryMetadataHelper.GetPermissionChecks(space,
|
||||
reqInfo.RegistryIdentifier, enum.PermissionRegistryView)
|
||||
if err = apiauth.CheckRegistry(
|
||||
ctx,
|
||||
c.Authorizer,
|
||||
@ -109,7 +110,7 @@ func (c *APIController) GetArtifactFiles(
|
||||
reqInfo.sortByField, reqInfo.sortByOrder, reqInfo.limit, reqInfo.offset, reqInfo.searchTerm)
|
||||
|
||||
if err != nil {
|
||||
log.Error().Msgf(err.Error())
|
||||
log.Error().Msgf("Failed to fetch files for artifact, err: %v", err.Error())
|
||||
return artifact.GetArtifactFiles500JSONResponse{
|
||||
InternalServerErrorJSONResponse: artifact.InternalServerErrorJSONResponse(
|
||||
*GetErrorResponse(http.StatusInternalServerError,
|
||||
@ -121,7 +122,7 @@ func (c *APIController) GetArtifactFiles(
|
||||
count, err := c.fileManager.CountFilesByPath(ctx, filePathPrefix, img.RegistryID)
|
||||
|
||||
if err != nil {
|
||||
log.Error().Msgf(err.Error())
|
||||
log.Error().Msgf("Failed to count files for artifact, err: %v", err.Error())
|
||||
return artifact.GetArtifactFiles500JSONResponse{
|
||||
InternalServerErrorJSONResponse: artifact.InternalServerErrorJSONResponse(
|
||||
*GetErrorResponse(http.StatusInternalServerError,
|
||||
|
@ -24,6 +24,7 @@ import (
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
//nolint:nilnil
|
||||
func (c *APIController) GetArtifactStats(
|
||||
_ context.Context,
|
||||
_ artifact.GetArtifactStatsRequestObject,
|
||||
@ -31,12 +32,13 @@ func (c *APIController) GetArtifactStats(
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
//nolint:nilnil
|
||||
func (c *APIController) GetArtifactStatsForSpace(
|
||||
ctx context.Context,
|
||||
r artifact.GetArtifactStatsForSpaceRequestObject,
|
||||
) (artifact.GetArtifactStatsForSpaceResponseObject, error) {
|
||||
parentRef := r.SpaceRef
|
||||
regInfo, err := c.GetRegistryRequestBaseInfo(ctx, string(parentRef), "")
|
||||
regInfo, err := c.RegistryMetadataHelper.GetRegistryRequestBaseInfo(ctx, string(parentRef), "")
|
||||
if err != nil {
|
||||
return artifact.GetArtifactStatsForSpace400JSONResponse{
|
||||
BadRequestJSONResponse: artifact.BadRequestJSONResponse(
|
||||
@ -55,7 +57,8 @@ func (c *APIController) GetArtifactStatsForSpace(
|
||||
}
|
||||
|
||||
session, _ := request.AuthSessionFrom(ctx)
|
||||
permissionChecks := GetPermissionChecks(space, regInfo.RegistryIdentifier, enum.PermissionRegistryView)
|
||||
permissionChecks := c.RegistryMetadataHelper.GetPermissionChecks(space,
|
||||
regInfo.RegistryIdentifier, enum.PermissionRegistryView)
|
||||
if err = apiauth.CheckRegistry(
|
||||
ctx,
|
||||
c.Authorizer,
|
||||
@ -71,11 +74,12 @@ func (c *APIController) GetArtifactStatsForSpace(
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
//nolint:nilnil
|
||||
func (c *APIController) GetArtifactStatsForRegistry(
|
||||
ctx context.Context,
|
||||
r artifact.GetArtifactStatsForRegistryRequestObject,
|
||||
) (artifact.GetArtifactStatsForRegistryResponseObject, error) {
|
||||
regInfo, err := c.GetRegistryRequestBaseInfo(ctx, "", string(r.RegistryRef))
|
||||
regInfo, err := c.RegistryMetadataHelper.GetRegistryRequestBaseInfo(ctx, "", string(r.RegistryRef))
|
||||
if err != nil {
|
||||
return artifact.GetArtifactStatsForRegistry400JSONResponse{
|
||||
BadRequestJSONResponse: artifact.BadRequestJSONResponse(
|
||||
|
@ -57,7 +57,8 @@ func (c *APIController) GetAllArtifacts(
|
||||
}
|
||||
|
||||
session, _ := request.AuthSessionFrom(ctx)
|
||||
permissionChecks := GetPermissionChecks(space, regInfo.RegistryIdentifier, enum.PermissionRegistryView)
|
||||
permissionChecks := c.RegistryMetadataHelper.GetPermissionChecks(space,
|
||||
regInfo.RegistryIdentifier, enum.PermissionRegistryView)
|
||||
if err = apiauth.CheckRegistry(
|
||||
ctx,
|
||||
c.Authorizer,
|
||||
|
@ -34,7 +34,7 @@ func (c *APIController) GetDockerArtifactDetails(
|
||||
ctx context.Context,
|
||||
r artifact.GetDockerArtifactDetailsRequestObject,
|
||||
) (artifact.GetDockerArtifactDetailsResponseObject, error) {
|
||||
regInfo, err := c.GetRegistryRequestBaseInfo(ctx, "", string(r.RegistryRef))
|
||||
regInfo, err := c.RegistryMetadataHelper.GetRegistryRequestBaseInfo(ctx, "", string(r.RegistryRef))
|
||||
if err != nil {
|
||||
return artifact.GetDockerArtifactDetails400JSONResponse{
|
||||
BadRequestJSONResponse: artifact.BadRequestJSONResponse(
|
||||
@ -53,7 +53,8 @@ func (c *APIController) GetDockerArtifactDetails(
|
||||
}
|
||||
|
||||
session, _ := request.AuthSessionFrom(ctx)
|
||||
permissionChecks := GetPermissionChecks(space, regInfo.RegistryIdentifier, enum.PermissionRegistryView)
|
||||
permissionChecks := c.RegistryMetadataHelper.GetPermissionChecks(space,
|
||||
regInfo.RegistryIdentifier, enum.PermissionRegistryView)
|
||||
if err = apiauth.CheckRegistry(
|
||||
ctx,
|
||||
c.Authorizer,
|
||||
|
@ -47,7 +47,7 @@ func (c *APIController) GetDockerArtifactLayers(
|
||||
ctx context.Context,
|
||||
r artifact.GetDockerArtifactLayersRequestObject,
|
||||
) (artifact.GetDockerArtifactLayersResponseObject, error) {
|
||||
regInfo, _ := c.GetRegistryRequestBaseInfo(ctx, "", string(r.RegistryRef))
|
||||
regInfo, _ := c.RegistryMetadataHelper.GetRegistryRequestBaseInfo(ctx, "", string(r.RegistryRef))
|
||||
|
||||
space, err := c.SpaceFinder.FindByRef(ctx, regInfo.ParentRef)
|
||||
if err != nil {
|
||||
@ -59,7 +59,8 @@ func (c *APIController) GetDockerArtifactLayers(
|
||||
}
|
||||
|
||||
session, _ := request.AuthSessionFrom(ctx)
|
||||
permissionChecks := GetPermissionChecks(space, regInfo.RegistryIdentifier, enum.PermissionRegistryView)
|
||||
permissionChecks := c.RegistryMetadataHelper.GetPermissionChecks(space,
|
||||
regInfo.RegistryIdentifier, enum.PermissionRegistryView)
|
||||
if err = apiauth.CheckRegistry(
|
||||
ctx,
|
||||
c.Authorizer,
|
||||
|
@ -31,7 +31,7 @@ func (c *APIController) GetDockerArtifactManifest(
|
||||
ctx context.Context,
|
||||
r artifact.GetDockerArtifactManifestRequestObject,
|
||||
) (artifact.GetDockerArtifactManifestResponseObject, error) {
|
||||
regInfo, err := c.GetRegistryRequestBaseInfo(ctx, "", string(r.RegistryRef))
|
||||
regInfo, err := c.RegistryMetadataHelper.GetRegistryRequestBaseInfo(ctx, "", string(r.RegistryRef))
|
||||
if err != nil {
|
||||
return artifact.GetDockerArtifactManifest400JSONResponse{
|
||||
BadRequestJSONResponse: artifact.BadRequestJSONResponse(
|
||||
@ -50,7 +50,8 @@ func (c *APIController) GetDockerArtifactManifest(
|
||||
}
|
||||
|
||||
session, _ := request.AuthSessionFrom(ctx)
|
||||
permissionChecks := GetPermissionChecks(space, regInfo.RegistryIdentifier, enum.PermissionRegistryView)
|
||||
permissionChecks := c.RegistryMetadataHelper.GetPermissionChecks(space,
|
||||
regInfo.RegistryIdentifier, enum.PermissionRegistryView)
|
||||
if err = apiauth.CheckRegistry(
|
||||
ctx,
|
||||
c.Authorizer,
|
||||
|
@ -39,7 +39,7 @@ func (c *APIController) GetDockerArtifactManifests(
|
||||
ctx context.Context,
|
||||
r artifact.GetDockerArtifactManifestsRequestObject,
|
||||
) (artifact.GetDockerArtifactManifestsResponseObject, error) {
|
||||
regInfo, err := c.GetRegistryRequestBaseInfo(ctx, "", string(r.RegistryRef))
|
||||
regInfo, err := c.RegistryMetadataHelper.GetRegistryRequestBaseInfo(ctx, "", string(r.RegistryRef))
|
||||
if err != nil {
|
||||
return artifact.GetDockerArtifactManifests400JSONResponse{
|
||||
BadRequestJSONResponse: artifact.BadRequestJSONResponse(
|
||||
@ -58,7 +58,8 @@ func (c *APIController) GetDockerArtifactManifests(
|
||||
}
|
||||
|
||||
session, _ := request.AuthSessionFrom(ctx)
|
||||
permissionChecks := GetPermissionChecks(space, regInfo.RegistryIdentifier, enum.PermissionRegistryView)
|
||||
permissionChecks := c.RegistryMetadataHelper.GetPermissionChecks(space,
|
||||
regInfo.RegistryIdentifier, enum.PermissionRegistryView)
|
||||
if err = apiauth.CheckRegistry(
|
||||
ctx,
|
||||
c.Authorizer,
|
||||
@ -136,7 +137,8 @@ func artifactManifestsErrorRs(err error) artifact.GetDockerArtifactManifestsResp
|
||||
}
|
||||
|
||||
func getManifestDetails(
|
||||
m *types.Manifest, mConfig *manifestConfig, downloadsCount int64) artifact.DockerManifestDetails {
|
||||
m *types.Manifest, mConfig *manifestConfig, downloadsCount int64,
|
||||
) artifact.DockerManifestDetails {
|
||||
createdAt := GetTimeInMs(m.CreatedAt)
|
||||
size := GetSize(m.TotalSize)
|
||||
|
||||
|
@ -31,7 +31,7 @@ func (c *APIController) GetHelmArtifactDetails(
|
||||
ctx context.Context,
|
||||
r artifact.GetHelmArtifactDetailsRequestObject,
|
||||
) (artifact.GetHelmArtifactDetailsResponseObject, error) {
|
||||
regInfo, err := c.GetRegistryRequestBaseInfo(ctx, "", string(r.RegistryRef))
|
||||
regInfo, err := c.RegistryMetadataHelper.GetRegistryRequestBaseInfo(ctx, "", string(r.RegistryRef))
|
||||
if err != nil {
|
||||
return artifact.GetHelmArtifactDetails400JSONResponse{
|
||||
BadRequestJSONResponse: artifact.BadRequestJSONResponse(
|
||||
@ -49,7 +49,8 @@ func (c *APIController) GetHelmArtifactDetails(
|
||||
}
|
||||
|
||||
session, _ := request.AuthSessionFrom(ctx)
|
||||
permissionChecks := GetPermissionChecks(space, regInfo.RegistryIdentifier, enum.PermissionRegistryView)
|
||||
permissionChecks := c.RegistryMetadataHelper.GetPermissionChecks(space, regInfo.RegistryIdentifier,
|
||||
enum.PermissionRegistryView)
|
||||
if err = apiauth.CheckRegistry(
|
||||
ctx,
|
||||
c.Authorizer,
|
||||
|
@ -30,7 +30,7 @@ func (c *APIController) GetHelmArtifactManifest(
|
||||
ctx context.Context,
|
||||
r artifact.GetHelmArtifactManifestRequestObject,
|
||||
) (artifact.GetHelmArtifactManifestResponseObject, error) {
|
||||
regInfo, err := c.GetRegistryRequestBaseInfo(ctx, "", string(r.RegistryRef))
|
||||
regInfo, err := c.RegistryMetadataHelper.GetRegistryRequestBaseInfo(ctx, "", string(r.RegistryRef))
|
||||
if err != nil {
|
||||
return c.get400Error(err)
|
||||
}
|
||||
@ -45,7 +45,8 @@ func (c *APIController) GetHelmArtifactManifest(
|
||||
}
|
||||
|
||||
session, _ := request.AuthSessionFrom(ctx)
|
||||
permissionChecks := GetPermissionChecks(space, regInfo.RegistryIdentifier, enum.PermissionRegistryView)
|
||||
permissionChecks := c.RegistryMetadataHelper.GetPermissionChecks(space, regInfo.RegistryIdentifier,
|
||||
enum.PermissionRegistryView)
|
||||
if err = apiauth.CheckRegistry(
|
||||
ctx,
|
||||
c.Authorizer,
|
||||
|
@ -61,7 +61,8 @@ func (c *APIController) ListArtifactLabels(
|
||||
}
|
||||
|
||||
session, _ := request.AuthSessionFrom(ctx)
|
||||
permissionChecks := GetPermissionChecks(space, regInfo.RegistryIdentifier, enum.PermissionRegistryView)
|
||||
permissionChecks := c.RegistryMetadataHelper.GetPermissionChecks(space, regInfo.RegistryIdentifier,
|
||||
enum.PermissionRegistryView)
|
||||
if err = apiauth.CheckRegistry(
|
||||
ctx,
|
||||
c.Authorizer,
|
||||
|
@ -29,7 +29,7 @@ func (c *APIController) GetArtifactSummary(
|
||||
ctx context.Context,
|
||||
r artifact.GetArtifactSummaryRequestObject,
|
||||
) (artifact.GetArtifactSummaryResponseObject, error) {
|
||||
regInfo, err := c.GetRegistryRequestBaseInfo(ctx, "", string(r.RegistryRef))
|
||||
regInfo, err := c.RegistryMetadataHelper.GetRegistryRequestBaseInfo(ctx, "", string(r.RegistryRef))
|
||||
if err != nil {
|
||||
return artifact.GetArtifactSummary400JSONResponse{
|
||||
BadRequestJSONResponse: artifact.BadRequestJSONResponse(
|
||||
@ -48,7 +48,8 @@ func (c *APIController) GetArtifactSummary(
|
||||
}
|
||||
|
||||
session, _ := request.AuthSessionFrom(ctx)
|
||||
permissionChecks := GetPermissionChecks(space, regInfo.RegistryIdentifier, enum.PermissionRegistryView)
|
||||
permissionChecks := c.RegistryMetadataHelper.GetPermissionChecks(space, regInfo.RegistryIdentifier,
|
||||
enum.PermissionRegistryView)
|
||||
if err = apiauth.CheckRegistry(
|
||||
ctx,
|
||||
c.Authorizer,
|
||||
|
@ -48,7 +48,7 @@ func (c *APIController) FetchArtifactSummary(
|
||||
ctx context.Context,
|
||||
r artifact.GetArtifactVersionSummaryRequestObject,
|
||||
) (string, string, artifact.PackageType, error) {
|
||||
regInfo, err := c.GetRegistryRequestBaseInfo(ctx, "", string(r.RegistryRef))
|
||||
regInfo, err := c.RegistryMetadataHelper.GetRegistryRequestBaseInfo(ctx, "", string(r.RegistryRef))
|
||||
|
||||
if err != nil {
|
||||
return "", "", "", fmt.Errorf("failed to get registry request base info: %w", err)
|
||||
@ -60,7 +60,8 @@ func (c *APIController) FetchArtifactSummary(
|
||||
}
|
||||
|
||||
session, _ := request.AuthSessionFrom(ctx)
|
||||
permissionChecks := GetPermissionChecks(space, regInfo.RegistryIdentifier, enum.PermissionRegistryView)
|
||||
permissionChecks := c.RegistryMetadataHelper.GetPermissionChecks(space, regInfo.RegistryIdentifier,
|
||||
enum.PermissionRegistryView)
|
||||
if err = apiauth.CheckRegistry(
|
||||
ctx,
|
||||
c.Authorizer,
|
||||
|
@ -61,7 +61,8 @@ func (c *APIController) GetAllArtifactVersions(
|
||||
}
|
||||
|
||||
session, _ := request.AuthSessionFrom(ctx)
|
||||
permissionChecks := GetPermissionChecks(space, regInfo.RegistryIdentifier, enum.PermissionRegistryView)
|
||||
permissionChecks := c.RegistryMetadataHelper.GetPermissionChecks(space, regInfo.RegistryIdentifier,
|
||||
enum.PermissionRegistryView)
|
||||
if err = apiauth.CheckRegistry(
|
||||
ctx,
|
||||
c.Authorizer,
|
||||
|
@ -35,7 +35,7 @@ func (c *APIController) GetClientSetupDetails(
|
||||
imageParam := r.Params.Artifact
|
||||
tagParam := r.Params.Version
|
||||
|
||||
regInfo, _ := c.GetRegistryRequestBaseInfo(ctx, "", string(regRefParam))
|
||||
regInfo, _ := c.RegistryMetadataHelper.GetRegistryRequestBaseInfo(ctx, "", string(regRefParam))
|
||||
|
||||
space, err := c.SpaceFinder.FindByRef(ctx, regInfo.ParentRef)
|
||||
if err != nil {
|
||||
@ -47,7 +47,8 @@ func (c *APIController) GetClientSetupDetails(
|
||||
}
|
||||
|
||||
session, _ := request.AuthSessionFrom(ctx)
|
||||
permissionChecks := GetPermissionChecks(space, regInfo.RegistryIdentifier, enum.PermissionRegistryView)
|
||||
permissionChecks := c.RegistryMetadataHelper.GetPermissionChecks(space, regInfo.RegistryIdentifier,
|
||||
enum.PermissionRegistryView)
|
||||
if err = apiauth.CheckRegistry(
|
||||
ctx,
|
||||
c.Authorizer,
|
||||
|
@ -28,7 +28,7 @@ func (c *APIController) GetRegistry(
|
||||
ctx context.Context,
|
||||
r artifact.GetRegistryRequestObject,
|
||||
) (artifact.GetRegistryResponseObject, error) {
|
||||
regInfo, err := c.GetRegistryRequestBaseInfo(ctx, "", string(r.RegistryRef))
|
||||
regInfo, err := c.RegistryMetadataHelper.GetRegistryRequestBaseInfo(ctx, "", string(r.RegistryRef))
|
||||
if err != nil {
|
||||
return artifact.GetRegistry400JSONResponse{
|
||||
BadRequestJSONResponse: artifact.BadRequestJSONResponse(
|
||||
@ -46,7 +46,8 @@ func (c *APIController) GetRegistry(
|
||||
}
|
||||
|
||||
session, _ := request.AuthSessionFrom(ctx)
|
||||
permissionChecks := GetPermissionChecks(space, regInfo.RegistryIdentifier, enum.PermissionRegistryView)
|
||||
permissionChecks := c.RegistryMetadataHelper.GetPermissionChecks(space, regInfo.RegistryIdentifier,
|
||||
enum.PermissionRegistryView)
|
||||
if err = apiauth.CheckRegistry(
|
||||
ctx,
|
||||
c.Authorizer,
|
||||
|
@ -57,7 +57,8 @@ func (c *APIController) GetAllArtifactsByRegistry(
|
||||
}
|
||||
|
||||
session, _ := request.AuthSessionFrom(ctx)
|
||||
permissionChecks := GetPermissionChecks(space, regInfo.RegistryIdentifier, enum.PermissionRegistryView)
|
||||
permissionChecks := c.RegistryMetadataHelper.GetPermissionChecks(space, regInfo.RegistryIdentifier,
|
||||
enum.PermissionRegistryView)
|
||||
if err = apiauth.CheckRegistry(
|
||||
ctx,
|
||||
c.Authorizer,
|
||||
|
@ -31,7 +31,7 @@ func (c *APIController) GetWebhook(
|
||||
ctx context.Context,
|
||||
r api.GetWebhookRequestObject,
|
||||
) (api.GetWebhookResponseObject, error) {
|
||||
regInfo, err := c.GetRegistryRequestBaseInfo(ctx, "", string(r.RegistryRef))
|
||||
regInfo, err := c.RegistryMetadataHelper.GetRegistryRequestBaseInfo(ctx, "", string(r.RegistryRef))
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Error().Msgf("failed to get registry details: %v", err)
|
||||
return getWebhookInternalErrorResponse(err)
|
||||
@ -44,7 +44,8 @@ func (c *APIController) GetWebhook(
|
||||
}
|
||||
|
||||
session, _ := request.AuthSessionFrom(ctx)
|
||||
permissionChecks := GetPermissionChecks(space, regInfo.RegistryIdentifier, enum.PermissionRegistryView)
|
||||
permissionChecks := c.RegistryMetadataHelper.GetPermissionChecks(space, regInfo.RegistryIdentifier,
|
||||
enum.PermissionRegistryView)
|
||||
if err = apiauth.CheckRegistry(
|
||||
ctx,
|
||||
c.Authorizer,
|
||||
@ -67,7 +68,7 @@ func (c *APIController) GetWebhook(
|
||||
return getWebhookInternalErrorResponse(fmt.Errorf("failed to get webhook"))
|
||||
}
|
||||
|
||||
webhookResponseEntity, err := c.mapToWebhookResponseEntity(ctx, *webhook)
|
||||
webhookResponseEntity, err := c.RegistryMetadataHelper.MapToWebhookResponseEntity(ctx, webhook)
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Error().Msgf("failed to get webhook: %s with error: %v", webhookIdentifier, err)
|
||||
return getWebhookInternalErrorResponse(fmt.Errorf("failed to get webhook"))
|
||||
|
@ -16,18 +16,82 @@ package metadata
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
apiauth "github.com/harness/gitness/app/api/auth"
|
||||
"github.com/harness/gitness/app/api/request"
|
||||
api "github.com/harness/gitness/registry/app/api/openapi/contracts/artifact"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
const getWebhookErrMsg = "failed to get webhook execution for registry: %s, webhook: %s with error: %v"
|
||||
|
||||
func (c *APIController) GetWebhookExecution(
|
||||
_ context.Context,
|
||||
_ api.GetWebhookExecutionRequestObject,
|
||||
ctx context.Context,
|
||||
r api.GetWebhookExecutionRequestObject,
|
||||
) (api.GetWebhookExecutionResponseObject, error) {
|
||||
regInfo, err := c.RegistryMetadataHelper.GetRegistryRequestBaseInfo(ctx, "", string(r.RegistryRef))
|
||||
if err != nil {
|
||||
return getWebhooksExecutionsInternalErrorResponse(err)
|
||||
}
|
||||
|
||||
space, err := c.SpaceFinder.FindByRef(ctx, regInfo.ParentRef)
|
||||
if err != nil {
|
||||
return getWebhooksExecutionsInternalErrorResponse(err)
|
||||
}
|
||||
session, _ := request.AuthSessionFrom(ctx)
|
||||
permissionChecks := c.RegistryMetadataHelper.GetPermissionChecks(space, regInfo.RegistryIdentifier,
|
||||
enum.PermissionRegistryView)
|
||||
if err = apiauth.CheckRegistry(
|
||||
ctx,
|
||||
c.Authorizer,
|
||||
session,
|
||||
permissionChecks...,
|
||||
); err != nil {
|
||||
log.Ctx(ctx).Error().Msgf("permission check failed while get webhook execution for registry: %s, error: %v",
|
||||
regInfo.RegistryIdentifier, err)
|
||||
return api.GetWebhookExecution403JSONResponse{
|
||||
UnauthorizedJSONResponse: api.UnauthorizedJSONResponse(
|
||||
*GetErrorResponse(http.StatusForbidden, err.Error()),
|
||||
),
|
||||
}, err
|
||||
}
|
||||
|
||||
webhookExecutionID, err := strconv.ParseInt(string(r.WebhookExecutionId), 10, 64)
|
||||
if err != nil || webhookExecutionID <= 0 {
|
||||
log.Ctx(ctx).Error().Msgf("invalid webhook execution identifier: %s, err: %v", string(r.WebhookExecutionId), err)
|
||||
return api.GetWebhookExecution400JSONResponse{
|
||||
BadRequestJSONResponse: api.BadRequestJSONResponse(
|
||||
*GetErrorResponse(http.StatusBadRequest, err.Error()),
|
||||
),
|
||||
}, err
|
||||
}
|
||||
|
||||
w, err := c.WebhooksExecutionRepository.Find(ctx, webhookExecutionID)
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Error().Msgf(getWebhookErrMsg, regInfo.RegistryRef, r.WebhookIdentifier, err)
|
||||
return getWebhooksExecutionsInternalErrorResponse(err)
|
||||
}
|
||||
webhookExecution, err := MapToWebhookExecutionResponseEntity(*w)
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Error().Msgf(getWebhookErrMsg, regInfo.RegistryRef, r.WebhookIdentifier, err)
|
||||
return getWebhooksExecutionsInternalErrorResponse(err)
|
||||
}
|
||||
return api.GetWebhookExecution200JSONResponse{
|
||||
WebhookExecutionResponseJSONResponse: api.WebhookExecutionResponseJSONResponse{
|
||||
Data: api.WebhookExecution{},
|
||||
Data: *webhookExecution,
|
||||
Status: api.StatusSUCCESS,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func getWebhooksExecutionsInternalErrorResponse(err error) (api.GetWebhookExecution500JSONResponse, error) {
|
||||
return api.GetWebhookExecution500JSONResponse{
|
||||
InternalServerErrorJSONResponse: api.InternalServerErrorJSONResponse(
|
||||
*GetErrorResponse(http.StatusInternalServerError, err.Error()),
|
||||
),
|
||||
}, err
|
||||
}
|
||||
|
@ -16,18 +16,168 @@ package metadata
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
apiauth "github.com/harness/gitness/app/api/auth"
|
||||
"github.com/harness/gitness/app/api/request"
|
||||
api "github.com/harness/gitness/registry/app/api/openapi/contracts/artifact"
|
||||
gitnesstypes "github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
const listWebhooksErrMsg = "failed to list webhooks executions for registry: %s, webhook: %s with error: %v"
|
||||
|
||||
func (c *APIController) ListWebhookExecutions(
|
||||
_ context.Context,
|
||||
_ api.ListWebhookExecutionsRequestObject,
|
||||
ctx context.Context,
|
||||
r api.ListWebhookExecutionsRequestObject,
|
||||
) (api.ListWebhookExecutionsResponseObject, error) {
|
||||
regInfo, err := c.RegistryMetadataHelper.GetRegistryRequestBaseInfo(ctx, "", string(r.RegistryRef))
|
||||
if err != nil {
|
||||
return listWebhooksExecutionsInternalErrorResponse(err)
|
||||
}
|
||||
|
||||
space, err := c.SpaceFinder.FindByRef(ctx, regInfo.ParentRef)
|
||||
if err != nil {
|
||||
return listWebhooksExecutionsInternalErrorResponse(err)
|
||||
}
|
||||
session, _ := request.AuthSessionFrom(ctx)
|
||||
permissionChecks := c.RegistryMetadataHelper.GetPermissionChecks(space, regInfo.RegistryIdentifier,
|
||||
enum.PermissionRegistryView)
|
||||
if err = apiauth.CheckRegistry(
|
||||
ctx,
|
||||
c.Authorizer,
|
||||
session,
|
||||
permissionChecks...,
|
||||
); err != nil {
|
||||
log.Ctx(ctx).Error().Msgf("permission check failed while listing webhooks for registry: %s, error: %v",
|
||||
regInfo.RegistryIdentifier, err)
|
||||
return api.ListWebhookExecutions403JSONResponse{
|
||||
UnauthorizedJSONResponse: api.UnauthorizedJSONResponse(
|
||||
*GetErrorResponse(http.StatusForbidden, err.Error()),
|
||||
),
|
||||
}, err
|
||||
}
|
||||
|
||||
size := GetOffset(r.Params.Size, r.Params.Page)
|
||||
limit := GetPageLimit(r.Params.Size)
|
||||
pageNumber := GetPageNumber(r.Params.Page)
|
||||
reg, err := c.RegistryRepository.GetByParentIDAndName(ctx, space.ID, regInfo.RegistryIdentifier)
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Error().Msgf(listWebhooksErrMsg, regInfo.RegistryRef, r.WebhookIdentifier, err)
|
||||
return listWebhooksExecutionsInternalErrorResponse(err)
|
||||
}
|
||||
webhook, err := c.WebhooksRepository.GetByRegistryAndIdentifier(ctx, reg.ID, string(r.WebhookIdentifier))
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Error().Msgf(listWebhooksErrMsg, regInfo.RegistryRef, r.WebhookIdentifier, err)
|
||||
return listWebhooksExecutionsInternalErrorResponse(err)
|
||||
}
|
||||
we, err := c.WebhooksExecutionRepository.ListForWebhook(ctx, webhook.ID, limit, int(pageNumber), size)
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Error().Msgf(listWebhooksErrMsg, regInfo.RegistryRef, r.WebhookIdentifier, err)
|
||||
return listWebhooksExecutionsInternalErrorResponse(err)
|
||||
}
|
||||
webhookExecutions, err := mapToAPIListWebhooksExecutions(we)
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Error().Msgf(listWebhooksErrMsg, regInfo.RegistryRef, r.WebhookIdentifier, err)
|
||||
return listWebhooksExecutionsInternalErrorResponse(err)
|
||||
}
|
||||
count, err := c.WebhooksExecutionRepository.CountForWebhook(ctx, webhook.ID)
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Error().Msgf(listWebhooksErrMsg, regInfo.RegistryRef, r.WebhookIdentifier, err)
|
||||
return listWebhooksExecutionsInternalErrorResponse(err)
|
||||
}
|
||||
pageCount := GetPageCount(count, limit)
|
||||
currentPageSize := len(webhookExecutions)
|
||||
return api.ListWebhookExecutions200JSONResponse{
|
||||
ListWebhooksExecutionResponseJSONResponse: api.ListWebhooksExecutionResponseJSONResponse{
|
||||
Data: api.ListWebhooksExecutions{},
|
||||
Data: api.ListWebhooksExecutions{
|
||||
Executions: webhookExecutions,
|
||||
ItemCount: &count,
|
||||
PageCount: &pageCount,
|
||||
PageIndex: &pageNumber,
|
||||
PageSize: ¤tPageSize,
|
||||
},
|
||||
Status: api.StatusSUCCESS,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func listWebhooksExecutionsInternalErrorResponse(err error) (api.ListWebhookExecutionsResponseObject, error) {
|
||||
return api.ListWebhookExecutions500JSONResponse{
|
||||
InternalServerErrorJSONResponse: api.InternalServerErrorJSONResponse(
|
||||
*GetErrorResponse(http.StatusInternalServerError, err.Error()),
|
||||
),
|
||||
}, err
|
||||
}
|
||||
|
||||
func mapToAPIListWebhooksExecutions(executions []*gitnesstypes.WebhookExecutionCore) ([]api.WebhookExecution, error) {
|
||||
webhooksExecutionEntities := make([]api.WebhookExecution, 0, len(executions))
|
||||
for _, e := range executions {
|
||||
webhookExecution, err := MapToWebhookExecutionResponseEntity(*e)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
webhooksExecutionEntities = append(webhooksExecutionEntities, *webhookExecution)
|
||||
}
|
||||
return webhooksExecutionEntities, nil
|
||||
}
|
||||
|
||||
func MapToWebhookExecutionResponseEntity(
|
||||
execution gitnesstypes.WebhookExecutionCore,
|
||||
) (*api.WebhookExecution, error) {
|
||||
webhookResponseEntity := api.WebhookExecution{
|
||||
Created: &execution.Created,
|
||||
Duration: &execution.Duration,
|
||||
Id: &execution.ID,
|
||||
Error: &execution.Error,
|
||||
Request: &api.WebhookExecRequest{
|
||||
Body: &execution.Request.Body,
|
||||
Headers: &execution.Request.Headers,
|
||||
Url: &execution.Request.URL,
|
||||
},
|
||||
Response: &api.WebhookExecResponse{
|
||||
Body: &execution.Response.Body,
|
||||
Headers: &execution.Response.Headers,
|
||||
Status: &execution.Response.Status,
|
||||
StatusCode: &execution.Response.StatusCode,
|
||||
},
|
||||
RetriggerOf: execution.RetriggerOf,
|
||||
Retriggerable: &execution.Retriggerable,
|
||||
WebhookId: &execution.WebhookID,
|
||||
}
|
||||
webhookExecResult := mapTpAPIExecutionResult(execution.Result)
|
||||
if webhookExecResult != "" {
|
||||
webhookResponseEntity.Result = &webhookExecResult
|
||||
}
|
||||
triggerType := mapTpAPITriggerType(execution.TriggerType)
|
||||
if triggerType != "" {
|
||||
webhookResponseEntity.TriggerType = &triggerType
|
||||
}
|
||||
return &webhookResponseEntity, nil
|
||||
}
|
||||
|
||||
func mapTpAPIExecutionResult(result enum.WebhookExecutionResult) api.WebhookExecResult {
|
||||
switch result {
|
||||
case enum.WebhookExecutionResultSuccess:
|
||||
return api.WebhookExecResultSUCCESS
|
||||
case enum.WebhookExecutionResultFatalError:
|
||||
return api.WebhookExecResultFATALERROR
|
||||
case enum.WebhookExecutionResultRetriableError:
|
||||
return api.WebhookExecResultRETRIABLEERROR
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func mapTpAPITriggerType(trigger enum.WebhookTrigger) api.Trigger {
|
||||
switch trigger {
|
||||
case enum.WebhookTriggerArtifactCreated:
|
||||
return api.TriggerARTIFACTCREATION
|
||||
case enum.WebhookTriggerArtifactUpdated:
|
||||
return api.TriggerARTIFACTMODIFICATION
|
||||
case enum.WebhookTriggerArtifactDeleted:
|
||||
return api.TriggerARTIFACTDELETION
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ import (
|
||||
apiauth "github.com/harness/gitness/app/api/auth"
|
||||
"github.com/harness/gitness/app/api/request"
|
||||
api "github.com/harness/gitness/registry/app/api/openapi/contracts/artifact"
|
||||
"github.com/harness/gitness/registry/types"
|
||||
gitnesstypes "github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
@ -32,7 +32,7 @@ func (c *APIController) ListWebhooks(
|
||||
ctx context.Context,
|
||||
r api.ListWebhooksRequestObject,
|
||||
) (api.ListWebhooksResponseObject, error) {
|
||||
regInfo, err := c.GetRegistryRequestBaseInfo(ctx, "", string(r.RegistryRef))
|
||||
regInfo, err := c.RegistryMetadataHelper.GetRegistryRequestBaseInfo(ctx, "", string(r.RegistryRef))
|
||||
if err != nil {
|
||||
return listWebhookInternalErrorResponse(err)
|
||||
}
|
||||
@ -43,7 +43,8 @@ func (c *APIController) ListWebhooks(
|
||||
}
|
||||
|
||||
session, _ := request.AuthSessionFrom(ctx)
|
||||
permissionChecks := GetPermissionChecks(space, regInfo.RegistryIdentifier, enum.PermissionRegistryView)
|
||||
permissionChecks := c.RegistryMetadataHelper.GetPermissionChecks(space, regInfo.RegistryIdentifier,
|
||||
enum.PermissionRegistryView)
|
||||
if err = apiauth.CheckRegistry(
|
||||
ctx,
|
||||
c.Authorizer,
|
||||
@ -126,11 +127,11 @@ func listWebhookInternalErrorResponse(err error) (api.ListWebhooksResponseObject
|
||||
|
||||
func (c *APIController) mapToListWebhookResponseEntity(
|
||||
ctx context.Context,
|
||||
webhooks *[]types.Webhook,
|
||||
webhooks []*gitnesstypes.WebhookCore,
|
||||
) ([]api.Webhook, error) {
|
||||
webhooksEntities := make([]api.Webhook, 0, len(*webhooks))
|
||||
for _, d := range *webhooks {
|
||||
webhook, err := c.mapToWebhookResponseEntity(ctx, d)
|
||||
webhooksEntities := make([]api.Webhook, 0, len(webhooks))
|
||||
for _, d := range webhooks {
|
||||
webhook, err := c.RegistryMetadataHelper.MapToWebhookResponseEntity(ctx, d)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
296
registry/app/api/controller/metadata/registry_metadata_helper.go
Normal file
296
registry/app/api/controller/metadata/registry_metadata_helper.go
Normal file
@ -0,0 +1,296 @@
|
||||
// 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 metadata
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/harness/gitness/app/paths"
|
||||
"github.com/harness/gitness/app/services/refcache"
|
||||
corestore "github.com/harness/gitness/app/store"
|
||||
api "github.com/harness/gitness/registry/app/api/openapi/contracts/artifact"
|
||||
"github.com/harness/gitness/registry/app/pkg/commons"
|
||||
"github.com/harness/gitness/registry/app/store"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
type RegistryMetadataHelper struct {
|
||||
spacePathStore corestore.SpacePathStore
|
||||
spaceFinder refcache.SpaceFinder
|
||||
registryRepository store.RegistryRepository
|
||||
}
|
||||
|
||||
func NewRegistryMetadataHelper(
|
||||
spacePathStore corestore.SpacePathStore,
|
||||
spaceFinder refcache.SpaceFinder,
|
||||
registryRepository store.RegistryRepository,
|
||||
) *RegistryMetadataHelper {
|
||||
return &RegistryMetadataHelper{
|
||||
spacePathStore: spacePathStore,
|
||||
spaceFinder: spaceFinder,
|
||||
registryRepository: registryRepository,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *RegistryMetadataHelper) getSecretSpaceID(ctx context.Context, secretSpacePath *string) (int, error) {
|
||||
if secretSpacePath == nil {
|
||||
return -1, fmt.Errorf("secret space path is missing")
|
||||
}
|
||||
|
||||
path, err := r.spacePathStore.FindByPath(ctx, *secretSpacePath)
|
||||
if err != nil {
|
||||
return -1, fmt.Errorf("failed to get Space Path: %w", err)
|
||||
}
|
||||
return int(path.SpaceID), nil
|
||||
}
|
||||
|
||||
// GetRegistryRequestBaseInfo returns the base info for the registry request
|
||||
// One of the regRefParam or (parentRefParam + regIdentifierParam) should be provided.
|
||||
func (r *RegistryMetadataHelper) GetRegistryRequestBaseInfo(
|
||||
ctx context.Context,
|
||||
parentRef string,
|
||||
regRef string,
|
||||
) (*RegistryRequestBaseInfo, error) {
|
||||
// ---------- CHECKS ------------
|
||||
if commons.IsEmpty(parentRef) && !commons.IsEmpty(regRef) {
|
||||
parentRef, _, _ = paths.DisectLeaf(regRef)
|
||||
}
|
||||
|
||||
// ---------- PARENT ------------
|
||||
if commons.IsEmpty(parentRef) {
|
||||
return nil, fmt.Errorf("parent reference is required")
|
||||
}
|
||||
rootIdentifier, _, err := paths.DisectRoot(parentRef)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid parent reference: %w", err)
|
||||
}
|
||||
|
||||
rootSpace, err := r.spaceFinder.FindByRef(ctx, rootIdentifier)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("root space not found: %w", err)
|
||||
}
|
||||
parentSpace, err := r.spaceFinder.FindByRef(ctx, parentRef)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parent space not found: %w", err)
|
||||
}
|
||||
rootIdentifierID := rootSpace.ID
|
||||
parentID := parentSpace.ID
|
||||
|
||||
baseInfo := &RegistryRequestBaseInfo{
|
||||
ParentRef: parentRef,
|
||||
parentID: parentID,
|
||||
RootIdentifier: rootIdentifier,
|
||||
rootIdentifierID: rootIdentifierID,
|
||||
}
|
||||
|
||||
// ---------- REGISTRY ------------
|
||||
if !commons.IsEmpty(regRef) {
|
||||
_, regIdentifier, _ := paths.DisectLeaf(regRef)
|
||||
|
||||
reg, getRegistryErr := r.registryRepository.GetByParentIDAndName(ctx, parentID, regIdentifier)
|
||||
if getRegistryErr != nil {
|
||||
return nil, fmt.Errorf("registry not found: %w", err)
|
||||
}
|
||||
|
||||
baseInfo.RegistryRef = regRef
|
||||
baseInfo.RegistryIdentifier = regIdentifier
|
||||
baseInfo.RegistryID = reg.ID
|
||||
baseInfo.RegistryType = reg.Type
|
||||
}
|
||||
|
||||
return baseInfo, nil
|
||||
}
|
||||
|
||||
func (r *RegistryMetadataHelper) GetPermissionChecks(
|
||||
space *types.SpaceCore,
|
||||
registryIdentifier string,
|
||||
permission enum.Permission,
|
||||
) []types.PermissionCheck {
|
||||
var permissionChecks []types.PermissionCheck
|
||||
permissionCheck := &types.PermissionCheck{
|
||||
Scope: types.Scope{SpacePath: space.Path},
|
||||
Resource: types.Resource{Type: enum.ResourceTypeRegistry, Identifier: registryIdentifier},
|
||||
Permission: permission,
|
||||
}
|
||||
permissionChecks = append(permissionChecks, *permissionCheck)
|
||||
return permissionChecks
|
||||
}
|
||||
|
||||
func (r *RegistryMetadataHelper) MapToWebhookCore(
|
||||
ctx context.Context,
|
||||
webhookRequest api.WebhookRequest,
|
||||
regInfo *RegistryRequestBaseInfo,
|
||||
) (*types.WebhookCore, error) {
|
||||
webhook := &types.WebhookCore{
|
||||
DisplayName: webhookRequest.Name,
|
||||
ParentType: enum.WebhookParentRegistry,
|
||||
ParentID: regInfo.RegistryID,
|
||||
Scope: webhookScopeRegistry,
|
||||
Identifier: webhookRequest.Identifier,
|
||||
URL: webhookRequest.Url,
|
||||
Enabled: webhookRequest.Enabled,
|
||||
Insecure: webhookRequest.Insecure,
|
||||
}
|
||||
|
||||
if webhookRequest.Triggers != nil {
|
||||
triggers := r.MapToInternalWebhookTriggers(*webhookRequest.Triggers)
|
||||
webhook.Triggers = deduplicateTriggers(triggers)
|
||||
}
|
||||
|
||||
if webhookRequest.Description != nil {
|
||||
webhook.Description = *webhookRequest.Description
|
||||
}
|
||||
if webhookRequest.SecretIdentifier != nil {
|
||||
webhook.SecretIdentifier = *webhookRequest.SecretIdentifier
|
||||
}
|
||||
if webhookRequest.SecretSpacePath != nil && len(*webhookRequest.SecretSpacePath) > 0 {
|
||||
secretSpaceID, err := r.getSecretSpaceID(ctx, webhookRequest.SecretSpacePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
webhook.SecretSpaceID = secretSpaceID
|
||||
} else if webhookRequest.SecretSpaceId != nil {
|
||||
webhook.SecretSpaceID = *webhookRequest.SecretSpaceId
|
||||
}
|
||||
if webhookRequest.ExtraHeaders != nil {
|
||||
webhook.ExtraHeaders = mapToDTOHeaders(webhookRequest.ExtraHeaders)
|
||||
}
|
||||
|
||||
return webhook, nil
|
||||
}
|
||||
|
||||
func mapToDTOHeaders(extraHeaders *[]api.ExtraHeader) []types.ExtraHeader {
|
||||
var headers []types.ExtraHeader
|
||||
for _, h := range *extraHeaders {
|
||||
headers = append(headers, types.ExtraHeader{Key: h.Key, Value: h.Value})
|
||||
}
|
||||
return headers
|
||||
}
|
||||
|
||||
func (r *RegistryMetadataHelper) MapToWebhookResponseEntity(
|
||||
ctx context.Context,
|
||||
createdWebhook *types.WebhookCore,
|
||||
) (*api.Webhook, error) {
|
||||
createdAt := strconv.FormatInt(createdWebhook.Created, 10)
|
||||
modifiedAt := strconv.FormatInt(createdWebhook.Updated, 10)
|
||||
triggers := r.MapToAPIWebhookTriggers(createdWebhook.Triggers)
|
||||
|
||||
webhookResponseEntity := &api.Webhook{
|
||||
Identifier: createdWebhook.Identifier,
|
||||
Name: createdWebhook.DisplayName,
|
||||
Description: &createdWebhook.Description,
|
||||
Url: createdWebhook.URL,
|
||||
Version: &createdWebhook.Version,
|
||||
Enabled: createdWebhook.Enabled,
|
||||
Insecure: createdWebhook.Insecure,
|
||||
Triggers: &triggers,
|
||||
CreatedBy: &createdWebhook.CreatedBy,
|
||||
CreatedAt: &createdAt,
|
||||
ModifiedAt: &modifiedAt,
|
||||
}
|
||||
isInternal := false
|
||||
if createdWebhook.Type == enum.WebhookTypeInternal {
|
||||
isInternal = true
|
||||
} else {
|
||||
isInternal = false
|
||||
}
|
||||
webhookResponseEntity.Internal = &isInternal
|
||||
|
||||
if createdWebhook.LatestExecutionResult != nil {
|
||||
result := r.MapToAPIExecutionResult(*createdWebhook.LatestExecutionResult)
|
||||
webhookResponseEntity.LatestExecutionResult = &result
|
||||
}
|
||||
|
||||
if createdWebhook.ExtraHeaders != nil {
|
||||
extraHeaders := r.MapToAPIExtraHeaders(createdWebhook.ExtraHeaders)
|
||||
webhookResponseEntity.ExtraHeaders = &extraHeaders
|
||||
}
|
||||
secretSpacePath := ""
|
||||
if createdWebhook.SecretSpaceID > 0 {
|
||||
primary, err := r.spacePathStore.FindPrimaryBySpaceID(ctx, int64(createdWebhook.SecretSpaceID))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get secret space path: %w", err)
|
||||
}
|
||||
secretSpacePath = primary.Value
|
||||
}
|
||||
if createdWebhook.SecretIdentifier != "" {
|
||||
webhookResponseEntity.SecretIdentifier = &createdWebhook.SecretIdentifier
|
||||
}
|
||||
if secretSpacePath != "" {
|
||||
webhookResponseEntity.SecretSpacePath = &secretSpacePath
|
||||
}
|
||||
if createdWebhook.SecretSpaceID > 0 {
|
||||
webhookResponseEntity.SecretSpaceId = &createdWebhook.SecretSpaceID
|
||||
}
|
||||
|
||||
return webhookResponseEntity, nil
|
||||
}
|
||||
|
||||
func (r *RegistryMetadataHelper) MapToInternalWebhookTriggers(
|
||||
triggers []api.Trigger,
|
||||
) []enum.WebhookTrigger {
|
||||
var webhookTriggers = make([]enum.WebhookTrigger, 0)
|
||||
for _, trigger := range triggers {
|
||||
switch trigger {
|
||||
case api.TriggerARTIFACTCREATION:
|
||||
webhookTriggers = append(webhookTriggers, enum.WebhookTriggerArtifactCreated)
|
||||
case api.TriggerARTIFACTMODIFICATION:
|
||||
webhookTriggers = append(webhookTriggers, enum.WebhookTriggerArtifactUpdated)
|
||||
case api.TriggerARTIFACTDELETION:
|
||||
webhookTriggers = append(webhookTriggers, enum.WebhookTriggerArtifactDeleted)
|
||||
}
|
||||
}
|
||||
return webhookTriggers
|
||||
}
|
||||
|
||||
func (r *RegistryMetadataHelper) MapToAPIExecutionResult(result enum.WebhookExecutionResult) api.WebhookExecResult {
|
||||
switch result {
|
||||
case enum.WebhookExecutionResultSuccess:
|
||||
return api.WebhookExecResultSUCCESS
|
||||
case enum.WebhookExecutionResultRetriableError:
|
||||
return api.WebhookExecResultRETRIABLEERROR
|
||||
case enum.WebhookExecutionResultFatalError:
|
||||
return api.WebhookExecResultFATALERROR
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func (r *RegistryMetadataHelper) MapToAPIWebhookTriggers(triggers []enum.WebhookTrigger) []api.Trigger {
|
||||
var webhookTriggers = make([]api.Trigger, 0)
|
||||
for _, trigger := range triggers {
|
||||
//nolint:exhaustive
|
||||
switch trigger {
|
||||
case enum.WebhookTriggerArtifactCreated:
|
||||
webhookTriggers = append(webhookTriggers, api.TriggerARTIFACTCREATION)
|
||||
case enum.WebhookTriggerArtifactUpdated:
|
||||
webhookTriggers = append(webhookTriggers, api.TriggerARTIFACTMODIFICATION)
|
||||
case enum.WebhookTriggerArtifactDeleted:
|
||||
webhookTriggers = append(webhookTriggers, api.TriggerARTIFACTDELETION)
|
||||
}
|
||||
}
|
||||
return webhookTriggers
|
||||
}
|
||||
|
||||
func (r *RegistryMetadataHelper) MapToAPIExtraHeaders(headers []types.ExtraHeader) []api.ExtraHeader {
|
||||
apiHeaders := make([]api.ExtraHeader, 0)
|
||||
for _, h := range headers {
|
||||
apiHeaders = append(apiHeaders, api.ExtraHeader{Key: h.Key, Value: h.Value})
|
||||
}
|
||||
return apiHeaders
|
||||
}
|
@ -16,18 +16,80 @@ package metadata
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
apiauth "github.com/harness/gitness/app/api/auth"
|
||||
"github.com/harness/gitness/app/api/request"
|
||||
api "github.com/harness/gitness/registry/app/api/openapi/contracts/artifact"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
func (c *APIController) ReTriggerWebhookExecution(
|
||||
_ context.Context,
|
||||
_ api.ReTriggerWebhookExecutionRequestObject,
|
||||
ctx context.Context,
|
||||
r api.ReTriggerWebhookExecutionRequestObject,
|
||||
) (api.ReTriggerWebhookExecutionResponseObject, error) {
|
||||
regInfo, err := c.RegistryMetadataHelper.GetRegistryRequestBaseInfo(ctx, "", string(r.RegistryRef))
|
||||
if err != nil {
|
||||
return getReTriggerWebhooksExecutionsInternalErrorResponse(err)
|
||||
}
|
||||
|
||||
space, err := c.SpaceFinder.FindByRef(ctx, regInfo.ParentRef)
|
||||
if err != nil {
|
||||
return getReTriggerWebhooksExecutionsInternalErrorResponse(err)
|
||||
}
|
||||
session, _ := request.AuthSessionFrom(ctx)
|
||||
permissionChecks := c.RegistryMetadataHelper.GetPermissionChecks(space, regInfo.RegistryIdentifier,
|
||||
enum.PermissionRegistryEdit)
|
||||
if err = apiauth.CheckRegistry(
|
||||
ctx,
|
||||
c.Authorizer,
|
||||
session,
|
||||
permissionChecks...,
|
||||
); err != nil {
|
||||
log.Ctx(ctx).Error().Msgf("permission check failed while retrigger webhook execution for registry: %s, error: %v",
|
||||
regInfo.RegistryIdentifier, err)
|
||||
return api.ReTriggerWebhookExecution403JSONResponse{
|
||||
UnauthorizedJSONResponse: api.UnauthorizedJSONResponse(
|
||||
*GetErrorResponse(http.StatusForbidden, err.Error()),
|
||||
),
|
||||
}, err
|
||||
}
|
||||
|
||||
webhookExecutionID, err := strconv.ParseInt(string(r.WebhookExecutionId), 10, 64)
|
||||
if err != nil || webhookExecutionID <= 0 {
|
||||
log.Ctx(ctx).Error().Msgf("invalid webhook execution identifier: %s, err: %v", string(r.WebhookExecutionId), err)
|
||||
return api.ReTriggerWebhookExecution400JSONResponse{
|
||||
BadRequestJSONResponse: api.BadRequestJSONResponse(
|
||||
*GetErrorResponse(http.StatusBadRequest, err.Error()),
|
||||
),
|
||||
}, err
|
||||
}
|
||||
result, err := c.WebhookService.WebhookExecutor.RetriggerWebhookExecution(ctx, webhookExecutionID)
|
||||
if err != nil {
|
||||
return getReTriggerWebhooksExecutionsInternalErrorResponse(err)
|
||||
}
|
||||
webhookExecution, err := MapToWebhookExecutionResponseEntity(*result.Execution)
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Error().Msgf(getWebhookErrMsg, regInfo.RegistryRef, r.WebhookIdentifier, err)
|
||||
return getReTriggerWebhooksExecutionsInternalErrorResponse(err)
|
||||
}
|
||||
return api.ReTriggerWebhookExecution200JSONResponse{
|
||||
WebhookExecutionResponseJSONResponse: api.WebhookExecutionResponseJSONResponse{
|
||||
Data: api.WebhookExecution{},
|
||||
Data: *webhookExecution,
|
||||
Status: api.StatusSUCCESS,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func getReTriggerWebhooksExecutionsInternalErrorResponse(
|
||||
err error,
|
||||
) (api.ReTriggerWebhookExecution500JSONResponse, error) {
|
||||
return api.ReTriggerWebhookExecution500JSONResponse{
|
||||
InternalServerErrorJSONResponse: api.InternalServerErrorJSONResponse(
|
||||
*GetErrorResponse(http.StatusInternalServerError, err.Error()),
|
||||
),
|
||||
}, err
|
||||
}
|
||||
|
@ -54,7 +54,8 @@ func (c *APIController) UpdateArtifactLabels(
|
||||
}
|
||||
|
||||
session, _ := request.AuthSessionFrom(ctx)
|
||||
permissionChecks := GetPermissionChecks(space, regInfo.RegistryIdentifier, enum.PermissionRegistryEdit)
|
||||
permissionChecks := c.RegistryMetadataHelper.GetPermissionChecks(space, regInfo.RegistryIdentifier,
|
||||
enum.PermissionRegistryEdit)
|
||||
if err = apiauth.CheckRegistry(
|
||||
ctx,
|
||||
c.Authorizer,
|
||||
|
@ -35,7 +35,7 @@ func (c *APIController) ModifyRegistry(
|
||||
ctx context.Context,
|
||||
r artifact.ModifyRegistryRequestObject,
|
||||
) (artifact.ModifyRegistryResponseObject, error) {
|
||||
regInfo, err := c.GetRegistryRequestBaseInfo(ctx, "", string(r.RegistryRef))
|
||||
regInfo, err := c.RegistryMetadataHelper.GetRegistryRequestBaseInfo(ctx, "", string(r.RegistryRef))
|
||||
if err != nil {
|
||||
return artifact.ModifyRegistry400JSONResponse{
|
||||
BadRequestJSONResponse: artifact.BadRequestJSONResponse(
|
||||
@ -53,7 +53,8 @@ func (c *APIController) ModifyRegistry(
|
||||
}
|
||||
|
||||
session, _ := request.AuthSessionFrom(ctx)
|
||||
permissionChecks := GetPermissionChecks(space, regInfo.RegistryIdentifier, gitnessenum.PermissionRegistryEdit)
|
||||
permissionChecks := c.RegistryMetadataHelper.GetPermissionChecks(space,
|
||||
regInfo.RegistryIdentifier, gitnessenum.PermissionRegistryEdit)
|
||||
if err = apiauth.CheckRegistry(
|
||||
ctx,
|
||||
c.Authorizer,
|
||||
@ -392,7 +393,7 @@ func (c *APIController) UpdateUpstreamProxyEntity(
|
||||
}
|
||||
|
||||
if res.SecretSpacePath != nil && len(*res.SecretSpacePath) > 0 {
|
||||
upstreamProxyConfigEntity.SecretSpaceID, err = c.getSecretSpaceID(ctx, res.SecretSpacePath)
|
||||
upstreamProxyConfigEntity.SecretSpaceID, err = c.RegistryMetadataHelper.getSecretSpaceID(ctx, res.SecretSpacePath)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@ -412,7 +413,8 @@ func (c *APIController) UpdateUpstreamProxyEntity(
|
||||
return nil, nil, fmt.Errorf("failed to create upstream proxy: access_key_secret_identifier missing")
|
||||
default:
|
||||
if res.AccessKeySecretSpacePath != nil && len(*res.AccessKeySecretSpacePath) > 0 {
|
||||
upstreamProxyConfigEntity.UserNameSecretSpaceID, err = c.getSecretSpaceID(ctx, res.AccessKeySecretSpacePath)
|
||||
upstreamProxyConfigEntity.UserNameSecretSpaceID, err =
|
||||
c.RegistryMetadataHelper.getSecretSpaceID(ctx, res.AccessKeySecretSpacePath)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@ -423,7 +425,8 @@ func (c *APIController) UpdateUpstreamProxyEntity(
|
||||
}
|
||||
|
||||
if res.SecretKeySpacePath != nil && len(*res.SecretKeySpacePath) > 0 {
|
||||
upstreamProxyConfigEntity.SecretSpaceID, err = c.getSecretSpaceID(ctx, res.SecretKeySpacePath)
|
||||
upstreamProxyConfigEntity.SecretSpaceID, err =
|
||||
c.RegistryMetadataHelper.getSecretSpaceID(ctx, res.SecretKeySpacePath)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ func (c *APIController) UpdateWebhook(
|
||||
r api.UpdateWebhookRequestObject,
|
||||
) (api.UpdateWebhookResponseObject, error) {
|
||||
webhookRequest := api.WebhookRequest(*r.Body)
|
||||
regInfo, err := c.GetRegistryRequestBaseInfo(ctx, "", string(r.RegistryRef))
|
||||
regInfo, err := c.RegistryMetadataHelper.GetRegistryRequestBaseInfo(ctx, "", string(r.RegistryRef))
|
||||
if err != nil {
|
||||
return updateWebhookInternalErrorResponse(err)
|
||||
}
|
||||
@ -41,7 +41,8 @@ func (c *APIController) UpdateWebhook(
|
||||
return updateWebhookInternalErrorResponse(err)
|
||||
}
|
||||
session, _ := request.AuthSessionFrom(ctx)
|
||||
permissionChecks := GetPermissionChecks(space, regInfo.RegistryIdentifier, enum.PermissionRegistryEdit)
|
||||
permissionChecks := c.RegistryMetadataHelper.GetPermissionChecks(space, regInfo.RegistryIdentifier,
|
||||
enum.PermissionRegistryEdit)
|
||||
if err = apiauth.CheckRegistry(
|
||||
ctx,
|
||||
c.Authorizer,
|
||||
@ -56,8 +57,19 @@ func (c *APIController) UpdateWebhook(
|
||||
),
|
||||
}, err
|
||||
}
|
||||
existingWebhook, err := c.WebhooksRepository.GetByRegistryAndIdentifier(ctx,
|
||||
regInfo.RegistryID, webhookRequest.Identifier)
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Error().Msgf("failed to get existing webhook: %s with error: %v",
|
||||
webhookRequest.Identifier, err)
|
||||
return updateWebhookInternalErrorResponse(fmt.Errorf("failed to get existing webhook"))
|
||||
}
|
||||
if existingWebhook.Type == enum.WebhookTypeInternal {
|
||||
return updateWebhookBadRequestErrorResponse(fmt.Errorf("cannot edit internal webhook: %s",
|
||||
webhookRequest.Identifier))
|
||||
}
|
||||
|
||||
webhook, err := c.mapToWebhook(ctx, webhookRequest, regInfo)
|
||||
webhook, err := c.RegistryMetadataHelper.MapToWebhookCore(ctx, webhookRequest, regInfo)
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Error().Msgf("failed to update webhook: %s with error: %v", webhookRequest.Identifier, err)
|
||||
return updateWebhookBadRequestErrorResponse(fmt.Errorf("failed to update webhook"))
|
||||
@ -80,7 +92,7 @@ func (c *APIController) UpdateWebhook(
|
||||
return updateWebhookInternalErrorResponse(fmt.Errorf("failed to get updated webhook"))
|
||||
}
|
||||
|
||||
webhookResponseEntity, err := c.mapToWebhookResponseEntity(ctx, *updatedWebhook)
|
||||
webhookResponseEntity, err := c.RegistryMetadataHelper.MapToWebhookResponseEntity(ctx, updatedWebhook)
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Error().Msgf("failed to get updated webhook: %s with error: %v",
|
||||
webhookRequest.Identifier, err)
|
||||
|
@ -26,8 +26,6 @@ import (
|
||||
|
||||
a "github.com/harness/gitness/registry/app/api/openapi/contracts/artifact"
|
||||
"github.com/harness/gitness/registry/app/pkg/commons"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
|
||||
"github.com/inhies/go-bytesize"
|
||||
"github.com/rs/zerolog/log"
|
||||
@ -49,7 +47,8 @@ const (
|
||||
ArtifactFilesResource = "artifactFiles"
|
||||
RegistryIdentifierErrorMsg = "registry name should be 1~255 characters long with lower case characters, numbers " +
|
||||
"and ._- and must be start with numbers or characters"
|
||||
RegexIdentifierPattern = "^[a-z0-9]+(?:[._-][a-z0-9]+)*$"
|
||||
RegexIdentifierPattern = "^[a-z0-9]+(?:[._-][a-z0-9]+)*$"
|
||||
internalWebhookIdentifier = "harnesstriggerwebhok"
|
||||
)
|
||||
|
||||
var RegistrySortMap = map[string]string{
|
||||
@ -443,18 +442,3 @@ func CleanURLPath(input *string) {
|
||||
// Update the input string with the cleaned URL string representation
|
||||
*input = u.String()
|
||||
}
|
||||
|
||||
func GetPermissionChecks(
|
||||
space *types.SpaceCore,
|
||||
registryIdentifier string,
|
||||
permission enum.Permission,
|
||||
) []types.PermissionCheck {
|
||||
var permissionChecks []types.PermissionCheck
|
||||
permissionCheck := &types.PermissionCheck{
|
||||
Scope: types.Scope{SpacePath: space.Path},
|
||||
Resource: types.Resource{Type: enum.ResourceTypeRegistry, Identifier: registryIdentifier},
|
||||
Permission: permission,
|
||||
}
|
||||
permissionChecks = append(permissionChecks, *permissionCheck)
|
||||
return permissionChecks
|
||||
}
|
||||
|
@ -229,11 +229,12 @@ func (h *Handler) GetRegistryInfo(r *http.Request, remoteSupport bool) (pkg.Regi
|
||||
RegIdentifier: registryIdentifier,
|
||||
Image: image,
|
||||
},
|
||||
Reference: ref,
|
||||
Digest: dgst,
|
||||
Tag: tag,
|
||||
URLBuilder: v2.NewURLBuilderFromRequest(r, h.OCIRelativeURL),
|
||||
Path: r.URL.Path,
|
||||
Reference: ref,
|
||||
Digest: dgst,
|
||||
Tag: tag,
|
||||
URLBuilder: v2.NewURLBuilderFromRequest(r, h.OCIRelativeURL),
|
||||
Path: r.URL.Path,
|
||||
PackageType: registry.PackageType,
|
||||
}
|
||||
|
||||
log.Ctx(ctx).Info().Msgf("Dispatch: URI: %s", path)
|
||||
|
@ -22,7 +22,7 @@ import (
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
// PutManifest validates and stores a manifest in the registry.
|
||||
// DeleteManifest a manifest from the registry.
|
||||
func (h *Handler) DeleteManifest(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
info, err := h.GetRegistryInfo(r, false)
|
||||
|
@ -2172,6 +2172,9 @@ components:
|
||||
type: string
|
||||
value:
|
||||
type: string
|
||||
required:
|
||||
- key
|
||||
- value
|
||||
WebhookExecResult:
|
||||
type: string
|
||||
description: refers to webhook execution
|
||||
|
@ -1,6 +1,6 @@
|
||||
// Package artifact provides primitives to interact with the openapi HTTP API.
|
||||
//
|
||||
// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.4.1 DO NOT EDIT.
|
||||
// Code generated by github.com/deepmap/oapi-codegen/v2 version v2.1.0 DO NOT EDIT.
|
||||
package artifact
|
||||
|
||||
import (
|
||||
@ -346,6 +346,7 @@ type MiddlewareFunc func(http.Handler) http.Handler
|
||||
|
||||
// CreateRegistry operation middleware
|
||||
func (siw *ServerInterfaceWrapper) CreateRegistry(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
var err error
|
||||
|
||||
@ -368,11 +369,12 @@ func (siw *ServerInterfaceWrapper) CreateRegistry(w http.ResponseWriter, r *http
|
||||
handler = middleware(handler)
|
||||
}
|
||||
|
||||
handler.ServeHTTP(w, r)
|
||||
handler.ServeHTTP(w, r.WithContext(ctx))
|
||||
}
|
||||
|
||||
// DeleteRegistry operation middleware
|
||||
func (siw *ServerInterfaceWrapper) DeleteRegistry(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
var err error
|
||||
|
||||
@ -393,11 +395,12 @@ func (siw *ServerInterfaceWrapper) DeleteRegistry(w http.ResponseWriter, r *http
|
||||
handler = middleware(handler)
|
||||
}
|
||||
|
||||
handler.ServeHTTP(w, r)
|
||||
handler.ServeHTTP(w, r.WithContext(ctx))
|
||||
}
|
||||
|
||||
// GetRegistry operation middleware
|
||||
func (siw *ServerInterfaceWrapper) GetRegistry(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
var err error
|
||||
|
||||
@ -418,11 +421,12 @@ func (siw *ServerInterfaceWrapper) GetRegistry(w http.ResponseWriter, r *http.Re
|
||||
handler = middleware(handler)
|
||||
}
|
||||
|
||||
handler.ServeHTTP(w, r)
|
||||
handler.ServeHTTP(w, r.WithContext(ctx))
|
||||
}
|
||||
|
||||
// ModifyRegistry operation middleware
|
||||
func (siw *ServerInterfaceWrapper) ModifyRegistry(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
var err error
|
||||
|
||||
@ -443,11 +447,12 @@ func (siw *ServerInterfaceWrapper) ModifyRegistry(w http.ResponseWriter, r *http
|
||||
handler = middleware(handler)
|
||||
}
|
||||
|
||||
handler.ServeHTTP(w, r)
|
||||
handler.ServeHTTP(w, r.WithContext(ctx))
|
||||
}
|
||||
|
||||
// ListArtifactLabels operation middleware
|
||||
func (siw *ServerInterfaceWrapper) ListArtifactLabels(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
var err error
|
||||
|
||||
@ -495,11 +500,12 @@ func (siw *ServerInterfaceWrapper) ListArtifactLabels(w http.ResponseWriter, r *
|
||||
handler = middleware(handler)
|
||||
}
|
||||
|
||||
handler.ServeHTTP(w, r)
|
||||
handler.ServeHTTP(w, r.WithContext(ctx))
|
||||
}
|
||||
|
||||
// GetArtifactStatsForRegistry operation middleware
|
||||
func (siw *ServerInterfaceWrapper) GetArtifactStatsForRegistry(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
var err error
|
||||
|
||||
@ -539,11 +545,12 @@ func (siw *ServerInterfaceWrapper) GetArtifactStatsForRegistry(w http.ResponseWr
|
||||
handler = middleware(handler)
|
||||
}
|
||||
|
||||
handler.ServeHTTP(w, r)
|
||||
handler.ServeHTTP(w, r.WithContext(ctx))
|
||||
}
|
||||
|
||||
// DeleteArtifact operation middleware
|
||||
func (siw *ServerInterfaceWrapper) DeleteArtifact(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
var err error
|
||||
|
||||
@ -573,11 +580,12 @@ func (siw *ServerInterfaceWrapper) DeleteArtifact(w http.ResponseWriter, r *http
|
||||
handler = middleware(handler)
|
||||
}
|
||||
|
||||
handler.ServeHTTP(w, r)
|
||||
handler.ServeHTTP(w, r.WithContext(ctx))
|
||||
}
|
||||
|
||||
// UpdateArtifactLabels operation middleware
|
||||
func (siw *ServerInterfaceWrapper) UpdateArtifactLabels(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
var err error
|
||||
|
||||
@ -607,11 +615,12 @@ func (siw *ServerInterfaceWrapper) UpdateArtifactLabels(w http.ResponseWriter, r
|
||||
handler = middleware(handler)
|
||||
}
|
||||
|
||||
handler.ServeHTTP(w, r)
|
||||
handler.ServeHTTP(w, r.WithContext(ctx))
|
||||
}
|
||||
|
||||
// GetArtifactStats operation middleware
|
||||
func (siw *ServerInterfaceWrapper) GetArtifactStats(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
var err error
|
||||
|
||||
@ -660,11 +669,12 @@ func (siw *ServerInterfaceWrapper) GetArtifactStats(w http.ResponseWriter, r *ht
|
||||
handler = middleware(handler)
|
||||
}
|
||||
|
||||
handler.ServeHTTP(w, r)
|
||||
handler.ServeHTTP(w, r.WithContext(ctx))
|
||||
}
|
||||
|
||||
// GetArtifactSummary operation middleware
|
||||
func (siw *ServerInterfaceWrapper) GetArtifactSummary(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
var err error
|
||||
|
||||
@ -694,11 +704,12 @@ func (siw *ServerInterfaceWrapper) GetArtifactSummary(w http.ResponseWriter, r *
|
||||
handler = middleware(handler)
|
||||
}
|
||||
|
||||
handler.ServeHTTP(w, r)
|
||||
handler.ServeHTTP(w, r.WithContext(ctx))
|
||||
}
|
||||
|
||||
// DeleteArtifactVersion operation middleware
|
||||
func (siw *ServerInterfaceWrapper) DeleteArtifactVersion(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
var err error
|
||||
|
||||
@ -737,11 +748,12 @@ func (siw *ServerInterfaceWrapper) DeleteArtifactVersion(w http.ResponseWriter,
|
||||
handler = middleware(handler)
|
||||
}
|
||||
|
||||
handler.ServeHTTP(w, r)
|
||||
handler.ServeHTTP(w, r.WithContext(ctx))
|
||||
}
|
||||
|
||||
// GetArtifactDetails operation middleware
|
||||
func (siw *ServerInterfaceWrapper) GetArtifactDetails(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
var err error
|
||||
|
||||
@ -791,11 +803,12 @@ func (siw *ServerInterfaceWrapper) GetArtifactDetails(w http.ResponseWriter, r *
|
||||
handler = middleware(handler)
|
||||
}
|
||||
|
||||
handler.ServeHTTP(w, r)
|
||||
handler.ServeHTTP(w, r.WithContext(ctx))
|
||||
}
|
||||
|
||||
// GetDockerArtifactDetails operation middleware
|
||||
func (siw *ServerInterfaceWrapper) GetDockerArtifactDetails(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
var err error
|
||||
|
||||
@ -852,11 +865,12 @@ func (siw *ServerInterfaceWrapper) GetDockerArtifactDetails(w http.ResponseWrite
|
||||
handler = middleware(handler)
|
||||
}
|
||||
|
||||
handler.ServeHTTP(w, r)
|
||||
handler.ServeHTTP(w, r.WithContext(ctx))
|
||||
}
|
||||
|
||||
// GetDockerArtifactLayers operation middleware
|
||||
func (siw *ServerInterfaceWrapper) GetDockerArtifactLayers(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
var err error
|
||||
|
||||
@ -913,11 +927,12 @@ func (siw *ServerInterfaceWrapper) GetDockerArtifactLayers(w http.ResponseWriter
|
||||
handler = middleware(handler)
|
||||
}
|
||||
|
||||
handler.ServeHTTP(w, r)
|
||||
handler.ServeHTTP(w, r.WithContext(ctx))
|
||||
}
|
||||
|
||||
// GetDockerArtifactManifest operation middleware
|
||||
func (siw *ServerInterfaceWrapper) GetDockerArtifactManifest(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
var err error
|
||||
|
||||
@ -974,11 +989,12 @@ func (siw *ServerInterfaceWrapper) GetDockerArtifactManifest(w http.ResponseWrit
|
||||
handler = middleware(handler)
|
||||
}
|
||||
|
||||
handler.ServeHTTP(w, r)
|
||||
handler.ServeHTTP(w, r.WithContext(ctx))
|
||||
}
|
||||
|
||||
// GetDockerArtifactManifests operation middleware
|
||||
func (siw *ServerInterfaceWrapper) GetDockerArtifactManifests(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
var err error
|
||||
|
||||
@ -1017,11 +1033,12 @@ func (siw *ServerInterfaceWrapper) GetDockerArtifactManifests(w http.ResponseWri
|
||||
handler = middleware(handler)
|
||||
}
|
||||
|
||||
handler.ServeHTTP(w, r)
|
||||
handler.ServeHTTP(w, r.WithContext(ctx))
|
||||
}
|
||||
|
||||
// GetArtifactFiles operation middleware
|
||||
func (siw *ServerInterfaceWrapper) GetArtifactFiles(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
var err error
|
||||
|
||||
@ -1103,11 +1120,12 @@ func (siw *ServerInterfaceWrapper) GetArtifactFiles(w http.ResponseWriter, r *ht
|
||||
handler = middleware(handler)
|
||||
}
|
||||
|
||||
handler.ServeHTTP(w, r)
|
||||
handler.ServeHTTP(w, r.WithContext(ctx))
|
||||
}
|
||||
|
||||
// GetHelmArtifactDetails operation middleware
|
||||
func (siw *ServerInterfaceWrapper) GetHelmArtifactDetails(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
var err error
|
||||
|
||||
@ -1146,11 +1164,12 @@ func (siw *ServerInterfaceWrapper) GetHelmArtifactDetails(w http.ResponseWriter,
|
||||
handler = middleware(handler)
|
||||
}
|
||||
|
||||
handler.ServeHTTP(w, r)
|
||||
handler.ServeHTTP(w, r.WithContext(ctx))
|
||||
}
|
||||
|
||||
// GetHelmArtifactManifest operation middleware
|
||||
func (siw *ServerInterfaceWrapper) GetHelmArtifactManifest(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
var err error
|
||||
|
||||
@ -1189,11 +1208,12 @@ func (siw *ServerInterfaceWrapper) GetHelmArtifactManifest(w http.ResponseWriter
|
||||
handler = middleware(handler)
|
||||
}
|
||||
|
||||
handler.ServeHTTP(w, r)
|
||||
handler.ServeHTTP(w, r.WithContext(ctx))
|
||||
}
|
||||
|
||||
// GetArtifactVersionSummary operation middleware
|
||||
func (siw *ServerInterfaceWrapper) GetArtifactVersionSummary(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
var err error
|
||||
|
||||
@ -1232,11 +1252,12 @@ func (siw *ServerInterfaceWrapper) GetArtifactVersionSummary(w http.ResponseWrit
|
||||
handler = middleware(handler)
|
||||
}
|
||||
|
||||
handler.ServeHTTP(w, r)
|
||||
handler.ServeHTTP(w, r.WithContext(ctx))
|
||||
}
|
||||
|
||||
// GetAllArtifactVersions operation middleware
|
||||
func (siw *ServerInterfaceWrapper) GetAllArtifactVersions(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
var err error
|
||||
|
||||
@ -1309,11 +1330,12 @@ func (siw *ServerInterfaceWrapper) GetAllArtifactVersions(w http.ResponseWriter,
|
||||
handler = middleware(handler)
|
||||
}
|
||||
|
||||
handler.ServeHTTP(w, r)
|
||||
handler.ServeHTTP(w, r.WithContext(ctx))
|
||||
}
|
||||
|
||||
// GetAllArtifactsByRegistry operation middleware
|
||||
func (siw *ServerInterfaceWrapper) GetAllArtifactsByRegistry(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
var err error
|
||||
|
||||
@ -1385,11 +1407,12 @@ func (siw *ServerInterfaceWrapper) GetAllArtifactsByRegistry(w http.ResponseWrit
|
||||
handler = middleware(handler)
|
||||
}
|
||||
|
||||
handler.ServeHTTP(w, r)
|
||||
handler.ServeHTTP(w, r.WithContext(ctx))
|
||||
}
|
||||
|
||||
// GetClientSetupDetails operation middleware
|
||||
func (siw *ServerInterfaceWrapper) GetClientSetupDetails(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
var err error
|
||||
|
||||
@ -1429,11 +1452,12 @@ func (siw *ServerInterfaceWrapper) GetClientSetupDetails(w http.ResponseWriter,
|
||||
handler = middleware(handler)
|
||||
}
|
||||
|
||||
handler.ServeHTTP(w, r)
|
||||
handler.ServeHTTP(w, r.WithContext(ctx))
|
||||
}
|
||||
|
||||
// ListWebhooks operation middleware
|
||||
func (siw *ServerInterfaceWrapper) ListWebhooks(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
var err error
|
||||
|
||||
@ -1497,11 +1521,12 @@ func (siw *ServerInterfaceWrapper) ListWebhooks(w http.ResponseWriter, r *http.R
|
||||
handler = middleware(handler)
|
||||
}
|
||||
|
||||
handler.ServeHTTP(w, r)
|
||||
handler.ServeHTTP(w, r.WithContext(ctx))
|
||||
}
|
||||
|
||||
// CreateWebhook operation middleware
|
||||
func (siw *ServerInterfaceWrapper) CreateWebhook(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
var err error
|
||||
|
||||
@ -1522,11 +1547,12 @@ func (siw *ServerInterfaceWrapper) CreateWebhook(w http.ResponseWriter, r *http.
|
||||
handler = middleware(handler)
|
||||
}
|
||||
|
||||
handler.ServeHTTP(w, r)
|
||||
handler.ServeHTTP(w, r.WithContext(ctx))
|
||||
}
|
||||
|
||||
// DeleteWebhook operation middleware
|
||||
func (siw *ServerInterfaceWrapper) DeleteWebhook(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
var err error
|
||||
|
||||
@ -1556,11 +1582,12 @@ func (siw *ServerInterfaceWrapper) DeleteWebhook(w http.ResponseWriter, r *http.
|
||||
handler = middleware(handler)
|
||||
}
|
||||
|
||||
handler.ServeHTTP(w, r)
|
||||
handler.ServeHTTP(w, r.WithContext(ctx))
|
||||
}
|
||||
|
||||
// GetWebhook operation middleware
|
||||
func (siw *ServerInterfaceWrapper) GetWebhook(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
var err error
|
||||
|
||||
@ -1590,11 +1617,12 @@ func (siw *ServerInterfaceWrapper) GetWebhook(w http.ResponseWriter, r *http.Req
|
||||
handler = middleware(handler)
|
||||
}
|
||||
|
||||
handler.ServeHTTP(w, r)
|
||||
handler.ServeHTTP(w, r.WithContext(ctx))
|
||||
}
|
||||
|
||||
// UpdateWebhook operation middleware
|
||||
func (siw *ServerInterfaceWrapper) UpdateWebhook(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
var err error
|
||||
|
||||
@ -1624,11 +1652,12 @@ func (siw *ServerInterfaceWrapper) UpdateWebhook(w http.ResponseWriter, r *http.
|
||||
handler = middleware(handler)
|
||||
}
|
||||
|
||||
handler.ServeHTTP(w, r)
|
||||
handler.ServeHTTP(w, r.WithContext(ctx))
|
||||
}
|
||||
|
||||
// ListWebhookExecutions operation middleware
|
||||
func (siw *ServerInterfaceWrapper) ListWebhookExecutions(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
var err error
|
||||
|
||||
@ -1677,11 +1706,12 @@ func (siw *ServerInterfaceWrapper) ListWebhookExecutions(w http.ResponseWriter,
|
||||
handler = middleware(handler)
|
||||
}
|
||||
|
||||
handler.ServeHTTP(w, r)
|
||||
handler.ServeHTTP(w, r.WithContext(ctx))
|
||||
}
|
||||
|
||||
// GetWebhookExecution operation middleware
|
||||
func (siw *ServerInterfaceWrapper) GetWebhookExecution(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
var err error
|
||||
|
||||
@ -1720,11 +1750,12 @@ func (siw *ServerInterfaceWrapper) GetWebhookExecution(w http.ResponseWriter, r
|
||||
handler = middleware(handler)
|
||||
}
|
||||
|
||||
handler.ServeHTTP(w, r)
|
||||
handler.ServeHTTP(w, r.WithContext(ctx))
|
||||
}
|
||||
|
||||
// ReTriggerWebhookExecution operation middleware
|
||||
func (siw *ServerInterfaceWrapper) ReTriggerWebhookExecution(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
var err error
|
||||
|
||||
@ -1763,11 +1794,12 @@ func (siw *ServerInterfaceWrapper) ReTriggerWebhookExecution(w http.ResponseWrit
|
||||
handler = middleware(handler)
|
||||
}
|
||||
|
||||
handler.ServeHTTP(w, r)
|
||||
handler.ServeHTTP(w, r.WithContext(ctx))
|
||||
}
|
||||
|
||||
// GetArtifactStatsForSpace operation middleware
|
||||
func (siw *ServerInterfaceWrapper) GetArtifactStatsForSpace(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
var err error
|
||||
|
||||
@ -1807,11 +1839,12 @@ func (siw *ServerInterfaceWrapper) GetArtifactStatsForSpace(w http.ResponseWrite
|
||||
handler = middleware(handler)
|
||||
}
|
||||
|
||||
handler.ServeHTTP(w, r)
|
||||
handler.ServeHTTP(w, r.WithContext(ctx))
|
||||
}
|
||||
|
||||
// GetAllArtifacts operation middleware
|
||||
func (siw *ServerInterfaceWrapper) GetAllArtifacts(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
var err error
|
||||
|
||||
@ -1899,11 +1932,12 @@ func (siw *ServerInterfaceWrapper) GetAllArtifacts(w http.ResponseWriter, r *htt
|
||||
handler = middleware(handler)
|
||||
}
|
||||
|
||||
handler.ServeHTTP(w, r)
|
||||
handler.ServeHTTP(w, r.WithContext(ctx))
|
||||
}
|
||||
|
||||
// GetAllRegistries operation middleware
|
||||
func (siw *ServerInterfaceWrapper) GetAllRegistries(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
var err error
|
||||
|
||||
@ -1991,7 +2025,7 @@ func (siw *ServerInterfaceWrapper) GetAllRegistries(w http.ResponseWriter, r *ht
|
||||
handler = middleware(handler)
|
||||
}
|
||||
|
||||
handler.ServeHTTP(w, r)
|
||||
handler.ServeHTTP(w, r.WithContext(ctx))
|
||||
}
|
||||
|
||||
type UnescapedCookieParamError struct {
|
||||
@ -5777,53 +5811,54 @@ var swaggerSpec = []string{
|
||||
"DdlCC524daPPixn3CyKlhn5DvhbZa6x0YY17mmUqwUPkW9xlCKrMg5dQMNqk1jPVrMzM3NlKzxnHbwuL",
|
||||
"PANKJIcjmmxnVQOTiiLdtpMrtekOIKnOnnkTs52i1DEj9yqtSmpgcNxeEpJyp1CHFVL8td3358r8Kpgw",
|
||||
"oXEYBCH9E0RSjTrgMcmIQ5ZQOJ5qSF5BjMHCQB6CANP9MPtThCODMIKB67WqFjYa2bqWWT8JAoWVXUlQ",
|
||||
"Ii69WSEn3yaV+frDcF3bxahTIhRqRNBvRgNlCf0fOFt1PEy0s2ua7AXjbr7TAZNIMVOMot65Sqxu/pqu",
|
||||
"75rW/AWv177ol1qwmkyN835dH8Fo1Wp+5v6SDRd/+7RNe+tzJ+vTeAXdhENdUMU+LE9tZEQLDF/a6iy5",
|
||||
"tjdEe8ky2CgR2Ka6bXhY7b61DxI7uSCxCswKHLTh7FoeuliHFvIElnX78CAI2OZqsEeNJWoafC504SUW",
|
||||
"KiYP/zBqqm+yQMfWOmmu6hVsr8BevwLLvdq76K6G+7keAMcOcy7SW24/p1ZqQULHrA8qaFQoa4PjCdpv",
|
||||
"VdJ6NfgbqcE87MpCZApJKQKkejV4amrw2WJG9TNppQ2U4JBGnZe324Y8JSJyOwwqgYwarxmbxlsb7cKZ",
|
||||
"UhRRrx9PWj8qk6yDqTn+oOnIaUVrtZ85yQIT/ZndAiVZOrE9jpqWzw6rUVVziLBDEkccsSlX/yLsRga0",
|
||||
"iPiUIqZGBMjoXAGMMRZNzEnXaXhg3pgtfZMtWL/cBFGUPMNgCgiBKO52fvAYJf6PLev6VZ9CS2cStZau",
|
||||
"2XyibAy/wsmr5VC88Sjfc8Nm59oTcts2HXzrr1lKeZ2Fa43dkbbRtH7VISm1VysO4eG9Hw/ul3TUrohT",
|
||||
"bYpvs0ehKEUSAJ9pzG8hIhmInAQ5X1NMEAQrVU81+X7mL9YYWCjby90+5WM3hvKClD05fVZbay5dobXu",
|
||||
"6Gnjnag+FmTvsFnb79svJGZxzbdmnSKIWjTsdi5z+1fLrSpih7tO0x2mlL9b011md4BYLgNC5atjqiwK",
|
||||
"tJkmZBnjIHu741iWxS4IpbueGS3fejuusRxsbYY2W59WpPuj/IWd8Aw6T8VikgmFqltDDHq905tonqt6",
|
||||
"xzcQWsrLLEIkpIdyV8pEtIMIYNASlWe0qCbxC1gWFOyE85Iv1DPADubZWuYZ41ycENV5+utoNL69dT33",
|
||||
"aji5/jqjvY9nsy8zbfdqzIJmZwsehUs51rmULw8f11KDnyboomUYji/Ni8qCDR7tyS3xzY5QFC4WOq8z",
|
||||
"RUREkWIyh7O7ydVwdPcwmo2Hd5MvdEec/3bz5XJyNRnVfr8cX4/Zb7oJr9gthr1xhnhQmjYqTDYxRclP",
|
||||
"3dUTyPiSaGd2lQLd2qyuIuKttWQ9YG5zv/EYcTZKNI/bYw9dZciH6iuM3NtzmT26njvKMGEv5w2f8din",
|
||||
"s8fOaUYwJgjQXdd0PQ21c2G1mucE15Sv5/58V1JI74QPYqEG6YSr/K3nl7LJLYPbU8pgi0wyGYbI4HFb",
|
||||
"GXNeks5Y2S7vAFi5U7G5Ls0qmN4xuFCeShst8xlciBNeWXSHPCB7sNRhDB6jknGcP6HnubBwmrXXkKqn",
|
||||
"re7kuRlyYYyhnyGoJygUGW71X/lOWE3axV4ItD4tFxV2yI1ySKkSi0aHpUusMppJsXCvtHsI0mBS8lMo",
|
||||
"cYohIadM9r1ZlPjE5NuSNqn6dHc3laLlyHpVEXtMAr0v97LAur3Sbqa8yJTWkXRRcS+0F+nTDJ9GImjA",
|
||||
"JiNHXWIaTJtaPjmtxTob380mww/X4wdusVIb9m54/WC2X2uXXPYa1xkrtGh1r61uFYuPZXEo4zU020bL",
|
||||
"JlAhCNY6LX+CBylYtNeIee4/tL06RVAoqy9z64GKGlRV6LW9KGBj0ymaL39fceuENPU3+roEEry2FfeN",
|
||||
"LHXVxUvypLRaGVY0fULJMJ4nMj+m8KMSz3CaD2nfOQF8ghFFExZ9XLhLQlJ8MRg8Pz+fLXnVszBhQwtJ",
|
||||
"1NzgkN2h5qu4+8fZ+dk5OxlPYQzS0L1w/8l+4ueZjK8DpNxTpolu2R2JFyLzjs5c1iRXh3SmRRH1HhMg",
|
||||
"sIKEzaJhZ1gUGWje3t3cq++Prk0QKD1RWn+ds/KA5T/O/zA3JMoNanmON577/vy8vaLy3hqrYtGXJhXu",
|
||||
"+/N/2tYrMtj+jw19ulcqWDpTGYIrZ1qdZwIWdApdZVN1TyvluBn8Uh/K3nD4RJBojKBL9rsCJCfkAYDA",
|
||||
"95Ms5u+R0v8vwicYOz9Y9psy0HgTWwNN+0g4h1oJJhbclEmfXwE63p+/b6+UJxzfH5xq823Ck+cuING9",
|
||||
"9U8yFOMCLiLetjtsPkJyCph5jarlWOAxTb4ZQ2mmwdBXlr4Z76R02J3i+iUAtPf1rQfhXkFYR88WS+JA",
|
||||
"XroPihtBrb67DjGpRqzVba1aHBzeEyK91nopWMDPzAXStjS7FrcoiyFA/vIOom1Vq/nRqx7eRnjrAKcA",
|
||||
"vIj4sMQ3lslttfD+CEklv+2ZbqEuZcq9StCe9W47FucoWV0CAq0rkEQpvhV69c+j98g1IreOpV1w+0v+",
|
||||
"ZbN9ka2fGTYnSqDTYfAqie93NIfa0ShTvAfMKWZBgwnbbhjwckcyDUwg7GjhavP0b3ZRqb0x0MnW3ac5",
|
||||
"oEB8/5bBMZHd2xC9DdEE9iKnoQXceeFmwBfJD1+VRVGhvwdlV1Dm874PWIqLocEv8UcXY1fm7W8zer8p",
|
||||
"GfNPVjnLBPO9vXyoG4C4BqSXwvRAyWHZrnyLM2Wj7lXeA3hNiG6v4y/DKPgmK+6u5Dmjeh1vIxUUkI9Q",
|
||||
"h8MXEgrmyGwlG/ok6loR0SXm/g0Fhecs3kVEdIzqBaWDoBgz+0txqRTYq9QUecSthSZP1t0iM0VS715k",
|
||||
"dCLD+dOLyg6ikkPsEKKippS1FhYlQW2LuKipbHuBaVpjJKd60dlBdBS4HVJ48FbSg+3FB7+J7Xnl9Yhe",
|
||||
"EvYgCS++jszDCFru3XnRhp37lSjwmy0VL+iEkyDyBQV2DdPCVyGMgoO49xRPafRyvM0BgxSWlzleWMJo",
|
||||
"ZXW4oHsgQyvD9VcX3saiVR93j/cOeDc8wCJRX/q8R+hbbXuMr3I0gv+1bnl2Rn+/g9kZ/5r9ywtIQKfb",
|
||||
"7srz34233pWnxd+CAOiH3otAx3vz+iPze7R7mv33sQOiiMWTVKkx+DRF0bD6qMhJI/1Nbj80D8n0Qtk1",
|
||||
"vkDB97bi2FX2MIvuUiIImuQPf1gfPNaAO1n2wtcmfNWUxb30dZS+miR0jmLjCRPfsYSJ79o2+zJ6c3Q9",
|
||||
"cUqP1ssQ3keAYeAksUwOL1Mv1gRUyRh4vIOArlbg9hZgfbg91O2DhU1w2wbv6osmjRi/Fu95yIRDpmOt",
|
||||
"0sM3v0HI5mmvGJLTbzCNRwVoEvn5TyxYXpvqRUK6Dco8UYiS0/BIAfGV7Exb5XvJ23ij6V6KWdQAxUZB",
|
||||
"Dn6Jvx6KnEl2eWCKrnU+5fuFV7vayZOFyUH0DuIHchBvhGBLcpg2VfURklcPpLerokqzp1/Ish3AwWMe",
|
||||
"Tw4f/Sp4QIhVMbDPVXBQfgnQSpHl+UrzvTK155p2E+PSS4RHh/DLbUp23gyo2aLf8K6gBJgXwnvxPf/t",
|
||||
"IQw224tBw8peSvH7CvD/XCF7EuzJQnjL+NbD4bDoHuSZjJtwzktoE1SXET6DIrVtj/Me58VZpxkUBrSz",
|
||||
"/Lp48Iv9e4icXSzB89ZpgPtMG28p0wbDigVSO9/9tvlb4MMAdFZ7xvPNHN63ly4/Z2o1yPydul1EWHXo",
|
||||
"6CW4611yB+lFxXWbnfgW93Mm+S2/7/TyAlyHnL3Qd6r0+4s7gn6GcPi0s+z2SYw7ym5JaOrCy57moA1w",
|
||||
"MapuWXKvEf5IxQCk4eDpDzZ/oq3ay+HTCX9mk90xeU7GTtk8J6LEIJUY8U6GQiAFkr61BSSiCaDoItFC",
|
||||
"oZ4aG5DP/zvJ3OGRl7rGatFt1m0uYbTStVhxvTa3p2XZc3GfK9rLbfzN/eb/AwAA//+7LTd+veMAAA==",
|
||||
"Ii69WSEn3yaV+frDcF3bYNSpNP5gO3deWEegErxQo49+M9ouS+j/wNmq4zmjncnTZEoYN/qdzp5E9pli",
|
||||
"FPXOVWJ1nGu62WsyBxa8Xrs9UGrByh7Q+PXXVRWMVq2Wae5K2XAnuE+ztTdMdzJMjbfTTTjUxVvswyjV",
|
||||
"Bk20wPClDdKS13tDIJgsg40SgW2q20aO1a5i+/ixk4sfq8CswEEbzq7leYx11CHPbVk3HQ+CgG1uDXvU",
|
||||
"WKKmwR1DF3lioWLyyBCjpvomC3RsrZPmqt7O9grs9Suw3OG9i+5quLrrAXDsCOgi8+X2c2qlFiR0zPqg",
|
||||
"gkaFsjY4nqD9ViWtV4O/kRrMI7IsRKaQlCJ2qleDp6YGny1mVD+TVtpAiRtp1Hl5u23IU4Ilt8OgEuOo",
|
||||
"caixaby10S6cKQUY9frxpPWjMsk6mJpDE5qOnFa0VvuZkyww0Z/ZLVCSpRPb46hp+eywGnA1hwg7JHHE",
|
||||
"EZviFSAicmSsiwhdKcJtROyMzkvAGH7RxJx0nYYH5o3Z0jfZgvV7TxBFyTMMpoAQiOJu5wePUeL/2LKu",
|
||||
"X3U3tPQzUWvpms0nysbwK/y/Wg7FG4/yPTds9rs9IY9u08G3/pqllPJZeN3YHWkbTetXHa1Se9DiEM7f",
|
||||
"+3Hufkkf7oo41ab4NnsUilLkB/CZxvwWIpKByEmQ8zXFBEGwUvVUk1to/piNgYWyvdwjVL6DYygvSNmT",
|
||||
"P2i1tebSFVrrPqA2jovqO0L2vpy1/b79QmIW13xr1im4qEXDbudNt3+13KoidrjrNN1hSvm7Nd1ldgeI",
|
||||
"5TIgVL46psqiQJtpQpYxRLK3O45lWeyCULrrmdHyrbfjGsvB1mZos/VpRbo/yh/fCc+g81QsJplQqLo1",
|
||||
"xKDXOz2X5rmq43wDoaWUzSJ6Qjovd6VMBEKI2AYtUXmyi2p+v4AlSMFOOC+5ST0D7GCeyGWeMc7FCVH9",
|
||||
"qr+ORuPbW9dzr4aT668z2vt4Nvsy03avhjNodrbgUXibY523+fLwIS81+GniMVqG4fjSvKgs2ODRntwS",
|
||||
"3+wIReFioXNIU0REFCkmczi7m1wNR3cPo9l4eDf5QnfE+W83Xy4nV5NR7ffL8fWY/aab8IrdYtgbZ4jH",
|
||||
"q2kDxmQTU5T81F09gYwviXZmVykGrs3qKoLhWkvWY+k29xuPEWejRPOQPvYGVoZ8qD7QyB1Bl9mj67mj",
|
||||
"DBP2qN7wGY99OnvsnGYEY4IA3XVN19NQOxdWq3lOcE35eu7PdyWF9E64JxZqkE64yt966imbtDO4PdsM",
|
||||
"tkgyk2GIDM64lTHnJemMle3yDoCVOxWb69Ksgukd4w7lqbTRMp/BhTjhlUV3SBGyB0sdxuAxKhnH+et6",
|
||||
"ngsLf1p7Dak64epOnpshF8YY+hmCeoJCkfxW/5XvhNV8XuzxQOvTclFhh7Qph5QqsWh0WLrEKqOZFAv3",
|
||||
"Srs3Ig0mJT+FEqcYEnLKZN+bRYlPTL4taZOqT3d3UylajqxXFbHHJNC7eS8LrNsr7WbKiyRqHUkXFfdC",
|
||||
"e5FZzfBpJOIJbJJ11CWmwbSppZrTWqyz8d1sMvxwPX7gFiu1Ye+G1w9m+7V2yWWvcZ2xQotW99rqVrH4",
|
||||
"WBaHMpRDs220bAIVgmCt0/LXeZCCRXuNmKcFRNurUwSFsvoytx6oqEFVhV7biwI2Np2i+fKnF7fOVVN/",
|
||||
"vq9LIMFrW3HfyFJXXbwkT0qrlWFF0+eaDON5IlNnCj8q8UKn+ZD2nRPAJxhRNGHRx4W7JCTFF4PB8/Pz",
|
||||
"2ZJXPQsTNrSQRM0NDtkdar6Ku3+cnZ+ds5PxFMYgDd0L95/sJ36eyfg6QMo9ZZrolt2ReDwy7+jMZU1y",
|
||||
"dUhnWhRR7zEBAitI2CwadoZFkYHmWd7Nvfo06doEgdLrpfWHOytvW/7j/A9zQ6LcoJYCeeO578/P2ysq",
|
||||
"T7GxKhZ9abLkvj//p229Irnt/9jQp3vAgmU6ldG5cqbVeSZgQafQVTZV97RSjpvBL/UN7Q2HTwSJxgi6",
|
||||
"ZL8rQHJCHhsIfD/JYv5UKf3/InyCscPD68pA401sDTTt++EcaiWYWHBT5oN+Beh4f/6+vVKei3x/cKrN",
|
||||
"twlPnruAGsUzgyRDMS7gIkJxu8PmIySngJnXqFqOBR7T5JsxlGYaDH1lmZ3xTkqH3SmuXwJAe1/fehDu",
|
||||
"FYR19GyxJA7kpfuguBHU6rvrEJNqxFrd1qrFweE9IdJrrZeCBfzMXCBtS7NrcYuyGALkL+8g2la1mt/D",
|
||||
"6uFthLcOcArAi4gPS3xjmfdWC++PkFRS357pFupSEt2rBO1Z77ZjcY6S1SUg0LoCSZTiW6FX/3J6j1wj",
|
||||
"cutY2gW3v+RfNtsX2fqZYXOiBDodBq+S+H5Hc6gdjTLFe8CcYhY0mLDthgEvdyTTwATCjhauNoX/ZheV",
|
||||
"2hsDnWzdfZoDCsT3bxkcE9m9DdHbEE1gL9IdWsCdF24GfJEX8VVZFBX6e1B2BWU+7/uApbgYGvwSf3Qx",
|
||||
"dmVK/zaj95uSTP9klbPMPd/by4e6AYhrQHopTA+U9Jbtyrc4UzbqXuWpgNeE6PY6/jKMgm+y4u5KnjOq",
|
||||
"1/E2UkEB+Qh1OHwhoWCOzFayoc+vrhURXc7u31BQeDrjXUREx6heUDoIijHpvxSXSoG9Sk2RYtxaaPI8",
|
||||
"3i0yU+T77kVGJzKcP72o7CAqOcQOISpqSllrYVES1LaIi5rKtheYpjVGcqoXnR1ER4HbIYUHbyU92F58",
|
||||
"8JvYnlceluglYQ+S8OLryDyMoOXenRdt2LlfiQK/2VLxgk44CSJfUGDXMC18FcIoOIh7T/GURi/H2xww",
|
||||
"SGF5meOFJYxWVocLugcytDJcf3XhbSxa9XH3eO+Ad8MDLBL1pc97hL7Vtsf4Kkcj+F/rlmdn9Pc7mJ3x",
|
||||
"r9m/vIAEdLrtrrwM3njrXXl1/C0IgH7ovQh0vDevvz+/R7un2X8fOyCKWDxJlRqDT1MUDauPipw00t/k",
|
||||
"9kPzkEwvlF3jCxR8byuOXWUPs+guJYKgSf7wh/XBYw24k2UvfG3CV01Z3EtfR+mrSULnKDaeMPEdS5j4",
|
||||
"rm2zL6M3R9cTp/SevQzhfQQYBk4Sy+TwMvViTUCVjIHHOwjoagVubwHWh9tD3T5Y2AS3bfCuvmjSiPFr",
|
||||
"8Z6HTDhkOtYqPXzzG4RsnvaKITn9BtN4VIAmkZ//xILltaleJKTboMwThSg5DY8UEF/JzrRVvpe8jTea",
|
||||
"7qWYRQ1QbBTk4Jf466HImWSXB6boWudTvl94taudPFmYHETvIH4gB/FGCLYkh2lTVR8hefVAersqqjR7",
|
||||
"+oUs2wEcPObx5PDRr4IHhFgVA/tcBQfllwCtFFmerzTfK1N7rmk3MS69RHh0CL/cpmTnzYCaLfoN7wpK",
|
||||
"gHkhvBff898ewmCzvRg0rOylFL+vAP/PFbInwZ4shLeMbz0cDovuQZ7JuAnnvIQ2QXUZ4TMoUtv2OO9x",
|
||||
"Xpx1mkFhQDvLr4sHv9i/h8jZxRI8b50GuM+08ZYybTCsWCC1891vm78FPgxAZ7VnPN/M4X176fJzplaD",
|
||||
"zN+p20WEVYeOXoK73iV3kF5UXLfZiW9xP2eS3/L7Ti8vwHXI2Qt9p0q/v7gj6GcIh087y26fxLij7JaE",
|
||||
"pi687GkO2gAXo+qWJfca4Y9UDEAaDp7+YPMn2qq9HD6d8Gc22R2T52TslM1zIkoMUokR72QoBFIg6Vtb",
|
||||
"QCKaAIouEi0U6qmxAfn8v5PMHR55qWusFt1m3eYSRitdixXXa3N7WpY9F/e5or3cxt/cb/4/AAD//19G",
|
||||
"o/vY4wAA",
|
||||
}
|
||||
|
||||
// GetSwagger returns the content of the embedded swagger specification file
|
||||
|
@ -1,6 +1,6 @@
|
||||
// Package artifact provides primitives to interact with the openapi HTTP API.
|
||||
//
|
||||
// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.4.1 DO NOT EDIT.
|
||||
// Code generated by github.com/deepmap/oapi-codegen/v2 version v2.1.0 DO NOT EDIT.
|
||||
package artifact
|
||||
|
||||
import (
|
||||
@ -301,8 +301,8 @@ type Error struct {
|
||||
|
||||
// ExtraHeader Webhook Extra Header
|
||||
type ExtraHeader struct {
|
||||
Key *string `json:"key,omitempty"`
|
||||
Value *string `json:"value,omitempty"`
|
||||
Key string `json:"key"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
// FileDetail File Detail
|
||||
|
@ -22,6 +22,7 @@ import (
|
||||
"github.com/harness/gitness/app/auth/authn"
|
||||
"github.com/harness/gitness/app/auth/authz"
|
||||
"github.com/harness/gitness/app/services/refcache"
|
||||
corestore "github.com/harness/gitness/app/store"
|
||||
urlprovider "github.com/harness/gitness/app/url"
|
||||
"github.com/harness/gitness/audit"
|
||||
"github.com/harness/gitness/registry/app/api/controller/metadata"
|
||||
@ -30,6 +31,7 @@ import (
|
||||
storagedriver "github.com/harness/gitness/registry/app/driver"
|
||||
"github.com/harness/gitness/registry/app/pkg/filemanager"
|
||||
"github.com/harness/gitness/registry/app/store"
|
||||
registrywebhook "github.com/harness/gitness/registry/services/webhook"
|
||||
"github.com/harness/gitness/store/database/dbtx"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
@ -69,11 +71,15 @@ func NewAPIHandler(
|
||||
auditService audit.Service,
|
||||
artifactStore store.ArtifactRepository,
|
||||
webhooksRepository store.WebhooksRepository,
|
||||
webhooksExecutionRepository store.WebhooksExecutionRepository,
|
||||
webhookService registrywebhook.Service,
|
||||
spacePathStore corestore.SpacePathStore,
|
||||
) APIHandler {
|
||||
r := chi.NewRouter()
|
||||
r.Use(audit.Middleware())
|
||||
r.Use(middlewareauthn.Attempt(authenticator))
|
||||
r.Use(middleware.CheckAuth())
|
||||
registryMetadataHelper := metadata.NewRegistryMetadataHelper(spacePathStore, spaceFinder, repoDao)
|
||||
apiController := metadata.NewAPIController(
|
||||
repoDao,
|
||||
fileManager,
|
||||
@ -92,7 +98,11 @@ func NewAPIHandler(
|
||||
auditService,
|
||||
artifactStore,
|
||||
webhooksRepository,
|
||||
webhooksExecutionRepository,
|
||||
*registryMetadataHelper,
|
||||
webhookService,
|
||||
)
|
||||
|
||||
handler := artifact.NewStrictHandler(apiController, []artifact.StrictMiddlewareFunc{})
|
||||
muxHandler := artifact.HandlerFromMuxWithBaseURL(handler, r, baseURL)
|
||||
return encode.TerminatedPathBefore(
|
||||
|
@ -19,6 +19,7 @@ import (
|
||||
"github.com/harness/gitness/app/auth/authz"
|
||||
"github.com/harness/gitness/app/config"
|
||||
"github.com/harness/gitness/app/services/refcache"
|
||||
corestore "github.com/harness/gitness/app/store"
|
||||
urlprovider "github.com/harness/gitness/app/url"
|
||||
"github.com/harness/gitness/audit"
|
||||
"github.com/harness/gitness/registry/app/api/handler/generic"
|
||||
@ -34,6 +35,7 @@ import (
|
||||
storagedriver "github.com/harness/gitness/registry/app/driver"
|
||||
"github.com/harness/gitness/registry/app/pkg/filemanager"
|
||||
"github.com/harness/gitness/registry/app/store"
|
||||
registrywebhook "github.com/harness/gitness/registry/services/webhook"
|
||||
"github.com/harness/gitness/store/database/dbtx"
|
||||
|
||||
"github.com/google/wire"
|
||||
@ -66,6 +68,9 @@ func APIHandlerProvider(
|
||||
auditService audit.Service,
|
||||
artifactStore store.ArtifactRepository,
|
||||
webhooksRepository store.WebhooksRepository,
|
||||
webhooksExecutionRepository store.WebhooksExecutionRepository,
|
||||
webhookService *registrywebhook.Service,
|
||||
spacePathStore corestore.SpacePathStore,
|
||||
) harness.APIHandler {
|
||||
return harness.NewAPIHandler(
|
||||
repoDao,
|
||||
@ -85,6 +90,9 @@ func APIHandlerProvider(
|
||||
auditService,
|
||||
artifactStore,
|
||||
webhooksRepository,
|
||||
webhooksExecutionRepository,
|
||||
*webhookService,
|
||||
spacePathStore,
|
||||
)
|
||||
}
|
||||
|
||||
|
161
registry/app/events/artifacts.go
Normal file
161
registry/app/events/artifacts.go
Normal file
@ -0,0 +1,161 @@
|
||||
// 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 events
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/harness/gitness/events"
|
||||
"github.com/harness/gitness/registry/app/api/openapi/contracts/artifact"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
const ArtifactsCategory = "artifacts"
|
||||
|
||||
const ArtifactCreatedEvent events.EventType = "artifact-created"
|
||||
const ArtifactUpdatedEvent events.EventType = "artifact-updated"
|
||||
const ArtifactDeletedEvent events.EventType = "artifact-deleted"
|
||||
|
||||
type ArtifactCreatedPayload struct {
|
||||
RegistryID int64 `json:"registry_id"`
|
||||
PrincipalID int64 `json:"principal_id"`
|
||||
ArtifactType artifact.PackageType `json:"artifact_type"`
|
||||
Artifact Artifact `json:"artifact"`
|
||||
}
|
||||
|
||||
type Artifact interface {
|
||||
GetInfo() string
|
||||
}
|
||||
|
||||
type BaseArtifact struct {
|
||||
Name string `json:"name"`
|
||||
Ref string `json:"ref"`
|
||||
}
|
||||
|
||||
type DockerArtifact struct {
|
||||
BaseArtifact
|
||||
URL string `json:"url"`
|
||||
Tag string `json:"tag"`
|
||||
Digest string `json:"digest"`
|
||||
}
|
||||
|
||||
func (a *DockerArtifact) GetInfo() string {
|
||||
return a.Ref
|
||||
}
|
||||
|
||||
type HelmArtifact struct {
|
||||
BaseArtifact
|
||||
URL string `json:"url"`
|
||||
Tag string `json:"tag"`
|
||||
Digest string `json:"digest"`
|
||||
}
|
||||
|
||||
func (a *HelmArtifact) GetInfo() string {
|
||||
return a.Ref
|
||||
}
|
||||
|
||||
type ArtifactInfo struct {
|
||||
Type artifact.PackageType `json:"type"`
|
||||
Name string `json:"name"`
|
||||
Version string `json:"version"`
|
||||
Artifact interface{} `json:"artifact"`
|
||||
}
|
||||
|
||||
type ArtifactChangeInfo struct {
|
||||
Type artifact.PackageType `json:"type"`
|
||||
Name string `json:"name"`
|
||||
ArtifactChange interface{} `json:"artifact_change"`
|
||||
}
|
||||
|
||||
func (r *Reporter) ArtifactCreated(ctx context.Context, payload *ArtifactCreatedPayload) {
|
||||
eventID, err := events.ReporterSendEvent(r.innerReporter, ctx, ArtifactCreatedEvent, payload)
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Err(err).Msgf("failed to send artifact-created created event")
|
||||
return
|
||||
}
|
||||
|
||||
log.Ctx(ctx).Debug().Msgf("reported artifact-created event with id '%s'", eventID)
|
||||
}
|
||||
|
||||
func (r *Reader) RegisterArtifactCreated(
|
||||
fn events.HandlerFunc[*ArtifactCreatedPayload],
|
||||
opts ...events.HandlerOption,
|
||||
) error {
|
||||
return events.ReaderRegisterEvent(r.innerReader, ArtifactCreatedEvent, fn, opts...)
|
||||
}
|
||||
|
||||
type ArtifactUpdatedPayload struct {
|
||||
RegistryID int64 `json:"registry_id"`
|
||||
PrincipalID int64 `json:"principal_id"`
|
||||
ArtifactType artifact.PackageType `json:"artifact_type"`
|
||||
ArtifactChange ArtifactChange `json:"artifact_change"`
|
||||
}
|
||||
|
||||
type ArtifactChange struct {
|
||||
Old Artifact
|
||||
New Artifact
|
||||
}
|
||||
|
||||
type DockerArtifactChange struct {
|
||||
Old DockerArtifact
|
||||
New DockerArtifact
|
||||
}
|
||||
|
||||
type HelmArtifactChange struct {
|
||||
Old HelmArtifact
|
||||
New HelmArtifact
|
||||
}
|
||||
|
||||
func (r *Reporter) ArtifactUpdated(ctx context.Context, payload *ArtifactUpdatedPayload) {
|
||||
eventID, err := events.ReporterSendEvent(r.innerReporter, ctx, ArtifactUpdatedEvent, payload)
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Err(err).Msgf("failed to send artifact updated event")
|
||||
return
|
||||
}
|
||||
|
||||
log.Ctx(ctx).Debug().Msgf("reported artifact updated event with id '%s'", eventID)
|
||||
}
|
||||
|
||||
func (r *Reader) RegisterArtifactUpdated(
|
||||
fn events.HandlerFunc[*ArtifactUpdatedPayload],
|
||||
opts ...events.HandlerOption,
|
||||
) error {
|
||||
return events.ReaderRegisterEvent(r.innerReader, ArtifactUpdatedEvent, fn, opts...)
|
||||
}
|
||||
|
||||
type ArtifactDeletedPayload struct {
|
||||
RegistryID int64 `json:"registry_id"`
|
||||
PrincipalID int64 `json:"principal_id"`
|
||||
ArtifactType artifact.PackageType `json:"artifact_type"`
|
||||
Artifact Artifact `json:"artifact"`
|
||||
}
|
||||
|
||||
func (r *Reporter) ArtifactDeleted(ctx context.Context, payload *ArtifactDeletedPayload) {
|
||||
eventID, err := events.ReporterSendEvent(r.innerReporter, ctx, ArtifactDeletedEvent, payload)
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Err(err).Msgf("failed to send artifact deleted event")
|
||||
return
|
||||
}
|
||||
|
||||
log.Ctx(ctx).Debug().Msgf("reported artifact deleted event with id '%s'", eventID)
|
||||
}
|
||||
|
||||
func (r *Reader) RegisterArtifactDeleted(
|
||||
fn events.HandlerFunc[*ArtifactDeletedPayload],
|
||||
opts ...events.HandlerOption,
|
||||
) error {
|
||||
return events.ReaderRegisterEvent(r.innerReader, ArtifactDeletedEvent, fn, opts...)
|
||||
}
|
40
registry/app/events/reader.go
Normal file
40
registry/app/events/reader.go
Normal file
@ -0,0 +1,40 @@
|
||||
// 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 events
|
||||
|
||||
import (
|
||||
"github.com/harness/gitness/events"
|
||||
)
|
||||
|
||||
func NewReaderFactory(eventsSystem *events.System) (*events.ReaderFactory[*Reader], error) {
|
||||
readerFactoryFunc := func(innerReader *events.GenericReader) (*Reader, error) {
|
||||
return &Reader{
|
||||
innerReader: innerReader,
|
||||
}, nil
|
||||
}
|
||||
|
||||
return events.NewReaderFactory(eventsSystem, ArtifactsCategory, readerFactoryFunc)
|
||||
}
|
||||
|
||||
// Reader is the event reader for this package.
|
||||
// It exposes typesafe event registration methods for all events by this package.
|
||||
// NOTE: Event registration methods are in the event's dedicated file.
|
||||
type Reader struct {
|
||||
innerReader *events.GenericReader
|
||||
}
|
||||
|
||||
func (r *Reader) Configure(opts ...events.ReaderOption) {
|
||||
r.innerReader.Configure(opts...)
|
||||
}
|
39
registry/app/events/reporter.go
Normal file
39
registry/app/events/reporter.go
Normal file
@ -0,0 +1,39 @@
|
||||
// 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 events
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/harness/gitness/events"
|
||||
)
|
||||
|
||||
// Reporter is the event reporter for this package.
|
||||
// It exposes typesafe send methods for all events of this package.
|
||||
// NOTE: Event send methods are in the event's dedicated file.
|
||||
type Reporter struct {
|
||||
innerReporter *events.GenericReporter
|
||||
}
|
||||
|
||||
func NewReporter(eventsSystem *events.System) (*Reporter, error) {
|
||||
innerReporter, err := events.NewReporter(eventsSystem, ArtifactsCategory)
|
||||
if err != nil {
|
||||
return nil, errors.New("failed to create new GenericReporter from event system")
|
||||
}
|
||||
|
||||
return &Reporter{
|
||||
innerReporter: innerReporter,
|
||||
}, nil
|
||||
}
|
42
registry/app/events/wire.go
Normal file
42
registry/app/events/wire.go
Normal file
@ -0,0 +1,42 @@
|
||||
// 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 events
|
||||
|
||||
import (
|
||||
"encoding/gob"
|
||||
|
||||
"github.com/harness/gitness/events"
|
||||
|
||||
"github.com/google/wire"
|
||||
)
|
||||
|
||||
func ProvideReaderFactory(eventsSystem *events.System) (*events.ReaderFactory[*Reader], error) {
|
||||
return NewReaderFactory(eventsSystem)
|
||||
}
|
||||
|
||||
func ProvideArtifactReporter(eventsSystem *events.System) (*Reporter, error) {
|
||||
reporter, err := NewReporter(eventsSystem)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
gob.Register(&DockerArtifact{})
|
||||
gob.Register(&HelmArtifact{})
|
||||
return reporter, nil
|
||||
}
|
||||
|
||||
var WireSet = wire.NewSet(
|
||||
ProvideReaderFactory,
|
||||
ProvideArtifactReporter,
|
||||
)
|
@ -38,11 +38,12 @@ type ArtifactInfo struct {
|
||||
|
||||
type RegistryInfo struct {
|
||||
*ArtifactInfo
|
||||
Reference string
|
||||
Digest string
|
||||
Tag string
|
||||
URLBuilder *v2.URLBuilder
|
||||
Path string
|
||||
Reference string
|
||||
Digest string
|
||||
Tag string
|
||||
URLBuilder *v2.URLBuilder
|
||||
Path string
|
||||
PackageType artifact.PackageType
|
||||
}
|
||||
|
||||
type FileInfo struct {
|
||||
|
@ -21,11 +21,15 @@ import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/harness/gitness/app/api/request"
|
||||
"github.com/harness/gitness/app/services/refcache"
|
||||
urlprovider "github.com/harness/gitness/app/url"
|
||||
"github.com/harness/gitness/registry/app/api/openapi/contracts/artifact"
|
||||
"github.com/harness/gitness/registry/app/event"
|
||||
registryevents "github.com/harness/gitness/registry/app/events"
|
||||
"github.com/harness/gitness/registry/app/manifest"
|
||||
"github.com/harness/gitness/registry/app/manifest/manifestlist"
|
||||
"github.com/harness/gitness/registry/app/manifest/ocischema"
|
||||
@ -47,6 +51,8 @@ import (
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
const ociPrefix = "oci://"
|
||||
|
||||
type manifestService struct {
|
||||
registryDao store.RegistryRepository
|
||||
manifestDao store.ManifestRepository
|
||||
@ -62,6 +68,8 @@ type manifestService struct {
|
||||
gcService gc.Service
|
||||
tx dbtx.Transactor
|
||||
reporter event.Reporter
|
||||
artifactEventReporter registryevents.Reporter
|
||||
urlProvider urlprovider.Provider
|
||||
}
|
||||
|
||||
func NewManifestService(
|
||||
@ -70,7 +78,8 @@ func NewManifestService(
|
||||
imageDao store.ImageRepository, artifactDao store.ArtifactRepository,
|
||||
layerDao store.LayerRepository, manifestRefDao store.ManifestReferenceRepository,
|
||||
tx dbtx.Transactor, gcService gc.Service, reporter event.Reporter, spaceFinder refcache.SpaceFinder,
|
||||
ociImageIndexMappingDao store.OCIImageIndexMappingRepository,
|
||||
ociImageIndexMappingDao store.OCIImageIndexMappingRepository, artifactEventReporter registryevents.Reporter,
|
||||
urlProvider urlprovider.Provider,
|
||||
) ManifestService {
|
||||
return &manifestService{
|
||||
registryDao: registryDao,
|
||||
@ -87,6 +96,8 @@ func NewManifestService(
|
||||
reporter: reporter,
|
||||
spaceFinder: spaceFinder,
|
||||
ociImageIndexMappingDao: ociImageIndexMappingDao,
|
||||
artifactEventReporter: artifactEventReporter,
|
||||
urlProvider: urlProvider,
|
||||
}
|
||||
}
|
||||
|
||||
@ -193,6 +204,7 @@ func (l *manifestService) dbTagManifest(
|
||||
if err != nil {
|
||||
return formatFailedToTagErr(err)
|
||||
}
|
||||
existingDigest := l.getTagDigest(ctx, dbRegistry.ID, imageName, tagName)
|
||||
|
||||
err = l.tx.WithTx(ctx, func(ctx context.Context) error {
|
||||
// Prevent long running transactions by setting an upper limit of manifestTagGCLockTimeout. If the GC is holding
|
||||
@ -228,6 +240,16 @@ func (l *manifestService) dbTagManifest(
|
||||
return err
|
||||
}
|
||||
l.reportEventAsync(ctx, reg.ID, info.RegIdentifier, imageName, tagName, packageType, spacePath)
|
||||
session, _ := request.AuthSessionFrom(ctx)
|
||||
createPayload := l.getArtifactCreatedPayload(ctx, info, session.Principal.ID,
|
||||
reg.ID, reg.Name, tagName, dgst.String())
|
||||
l.artifactEventReporter.ArtifactCreated(ctx, &createPayload)
|
||||
|
||||
if existingDigest != "" && existingDigest != dgst {
|
||||
updatePayload := l.getArtifactUpdatedPayload(ctx, info, session.Principal.ID,
|
||||
reg.ID, reg.Name, tagName, existingDigest.String(), dgst.String())
|
||||
l.artifactEventReporter.ArtifactUpdated(ctx, &updatePayload)
|
||||
}
|
||||
} else {
|
||||
log.Ctx(ctx).Err(err).Msg("Failed to find spacePath, not publishing event")
|
||||
}
|
||||
@ -235,6 +257,139 @@ func (l *manifestService) dbTagManifest(
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *manifestService) getArtifactCreatedPayload(
|
||||
ctx context.Context,
|
||||
info pkg.RegistryInfo,
|
||||
principalID int64,
|
||||
registryID int64,
|
||||
regIdentifier string,
|
||||
tag string,
|
||||
digest string,
|
||||
) registryevents.ArtifactCreatedPayload {
|
||||
payload := registryevents.ArtifactCreatedPayload{
|
||||
RegistryID: registryID,
|
||||
PrincipalID: principalID,
|
||||
ArtifactType: info.PackageType,
|
||||
}
|
||||
artifactURL := l.urlProvider.RegistryURL(ctx, info.RootIdentifier, regIdentifier) + "/" + info.Image + ":" + tag
|
||||
urlWithoutProtocol := GetRepoURLWithoutProtocol(artifactURL)
|
||||
baseArtifact := registryevents.BaseArtifact{
|
||||
Name: info.Image,
|
||||
Ref: fmt.Sprintf("%s:%s", info.Image, tag),
|
||||
}
|
||||
if info.PackageType == artifact.PackageTypeDOCKER {
|
||||
payload.Artifact = ®istryevents.DockerArtifact{
|
||||
BaseArtifact: baseArtifact,
|
||||
Tag: tag,
|
||||
URL: urlWithoutProtocol,
|
||||
Digest: digest,
|
||||
}
|
||||
} else if info.PackageType == artifact.PackageTypeHELM {
|
||||
payload.Artifact = ®istryevents.HelmArtifact{
|
||||
BaseArtifact: baseArtifact,
|
||||
Tag: tag,
|
||||
URL: ociPrefix + urlWithoutProtocol,
|
||||
Digest: digest,
|
||||
}
|
||||
}
|
||||
return payload
|
||||
}
|
||||
|
||||
func (l *manifestService) getArtifactDeletedPayload(
|
||||
ctx context.Context,
|
||||
info pkg.RegistryInfo,
|
||||
principalID int64,
|
||||
registryID int64,
|
||||
regIdentifier string,
|
||||
tag string,
|
||||
digest string,
|
||||
) registryevents.ArtifactDeletedPayload {
|
||||
payload := registryevents.ArtifactDeletedPayload{
|
||||
RegistryID: registryID,
|
||||
PrincipalID: principalID,
|
||||
ArtifactType: info.PackageType,
|
||||
}
|
||||
artifactURL := l.urlProvider.RegistryURL(ctx, info.RootIdentifier, regIdentifier) + "/" + info.Image + ":" + tag
|
||||
urlWithoutProtocol := GetRepoURLWithoutProtocol(artifactURL)
|
||||
|
||||
baseArtifact := registryevents.BaseArtifact{
|
||||
Name: info.Image,
|
||||
Ref: fmt.Sprintf("%s:%s", info.Image, tag),
|
||||
}
|
||||
if info.PackageType == artifact.PackageTypeDOCKER {
|
||||
payload.Artifact = ®istryevents.DockerArtifact{
|
||||
BaseArtifact: baseArtifact,
|
||||
Tag: tag,
|
||||
Digest: digest,
|
||||
URL: urlWithoutProtocol,
|
||||
}
|
||||
} else if info.PackageType == artifact.PackageTypeHELM {
|
||||
payload.Artifact = ®istryevents.HelmArtifact{
|
||||
BaseArtifact: baseArtifact,
|
||||
Tag: tag,
|
||||
Digest: digest,
|
||||
URL: ociPrefix + urlWithoutProtocol,
|
||||
}
|
||||
}
|
||||
return payload
|
||||
}
|
||||
|
||||
func (l *manifestService) getArtifactUpdatedPayload(
|
||||
ctx context.Context,
|
||||
info pkg.RegistryInfo,
|
||||
principalID int64,
|
||||
registryID int64,
|
||||
regIdentifier string,
|
||||
tag string,
|
||||
oldDigest string,
|
||||
newDigest string,
|
||||
) registryevents.ArtifactUpdatedPayload {
|
||||
payload := registryevents.ArtifactUpdatedPayload{
|
||||
RegistryID: registryID,
|
||||
PrincipalID: principalID,
|
||||
ArtifactType: info.PackageType,
|
||||
}
|
||||
artifactURL := l.urlProvider.RegistryURL(ctx, info.RootIdentifier, regIdentifier) + "/" + info.Image + ":" + tag
|
||||
urlWithoutProtocol := GetRepoURLWithoutProtocol(artifactURL)
|
||||
|
||||
baseArtifact := registryevents.BaseArtifact{
|
||||
Name: info.Image,
|
||||
Ref: fmt.Sprintf("%s:%s", info.Image, tag),
|
||||
}
|
||||
if info.PackageType == artifact.PackageTypeDOCKER {
|
||||
payload.ArtifactChange = registryevents.ArtifactChange{
|
||||
Old: ®istryevents.DockerArtifact{
|
||||
BaseArtifact: baseArtifact,
|
||||
Tag: tag,
|
||||
URL: urlWithoutProtocol,
|
||||
Digest: oldDigest,
|
||||
},
|
||||
New: ®istryevents.DockerArtifact{
|
||||
BaseArtifact: baseArtifact,
|
||||
Tag: tag,
|
||||
URL: urlWithoutProtocol,
|
||||
Digest: newDigest,
|
||||
},
|
||||
}
|
||||
} else if info.PackageType == artifact.PackageTypeHELM {
|
||||
payload.ArtifactChange = registryevents.ArtifactChange{
|
||||
Old: ®istryevents.HelmArtifact{
|
||||
BaseArtifact: baseArtifact,
|
||||
Tag: tag,
|
||||
URL: ociPrefix + urlWithoutProtocol,
|
||||
Digest: oldDigest,
|
||||
},
|
||||
New: ®istryevents.HelmArtifact{
|
||||
BaseArtifact: baseArtifact,
|
||||
Tag: tag,
|
||||
URL: ociPrefix + urlWithoutProtocol,
|
||||
Digest: newDigest,
|
||||
},
|
||||
}
|
||||
}
|
||||
return payload
|
||||
}
|
||||
|
||||
func formatFailedToTagErr(err error) error {
|
||||
return fmt.Errorf("failed to tag manifest: %w", err)
|
||||
}
|
||||
@ -366,7 +521,8 @@ func (l *manifestService) upsertImageAndArtifact(
|
||||
ctx context.Context,
|
||||
d digest.Digest,
|
||||
repoKey string,
|
||||
info pkg.RegistryInfo) error {
|
||||
info pkg.RegistryInfo,
|
||||
) error {
|
||||
dbRepo, err := l.registryDao.GetByParentIDAndName(ctx, info.ParentID, repoKey)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -399,7 +555,8 @@ func (l *manifestService) upsertImageAndArtifact(
|
||||
func (l *manifestService) UpsertImage(
|
||||
ctx context.Context,
|
||||
repoKey string,
|
||||
info pkg.RegistryInfo) error {
|
||||
info pkg.RegistryInfo,
|
||||
) error {
|
||||
dbRepo, err := l.registryDao.GetByParentIDAndName(ctx, info.ParentID, repoKey)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -1068,17 +1225,39 @@ func (l *manifestService) DeleteTag(
|
||||
return false, err
|
||||
}
|
||||
|
||||
found, err := l.tagDao.DeleteTagByName(ctx, registry.ID, tag)
|
||||
existingDigest := l.getTagDigest(ctx, registry.ID, info.Image, tag)
|
||||
deleted, err := l.tagDao.DeleteTagByName(ctx, registry.ID, tag)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("failed to delete tag in database: %w", err)
|
||||
}
|
||||
if !found {
|
||||
if !deleted {
|
||||
return false, distribution.ErrTagUnknown{Tag: tag}
|
||||
}
|
||||
|
||||
session, _ := request.AuthSessionFrom(ctx)
|
||||
payload := l.getArtifactDeletedPayload(ctx, info, session.Principal.ID, registry.ID,
|
||||
registry.Name, tag, existingDigest.String())
|
||||
l.artifactEventReporter.ArtifactDeleted(ctx, &payload)
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (l *manifestService) getTagDigest(
|
||||
ctx context.Context,
|
||||
registryID int64,
|
||||
imageName string,
|
||||
tag string,
|
||||
) digest.Digest {
|
||||
existingTag, findTagErr := l.tagDao.FindTag(ctx, registryID, imageName, tag)
|
||||
if findTagErr == nil && existingTag != nil {
|
||||
existingTaggedManifest, getManifestErr := l.manifestDao.Get(ctx, existingTag.ManifestID)
|
||||
if getManifestErr == nil {
|
||||
return existingTaggedManifest.Digest
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (l *manifestService) DeleteTagsByManifestID(
|
||||
ctx context.Context,
|
||||
repoKey string,
|
||||
@ -1179,3 +1358,14 @@ func (l *manifestService) DeleteManifest(
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func GetRepoURLWithoutProtocol(registryURL string) string {
|
||||
repoURL := registryURL
|
||||
parsedURL, err := url.Parse(repoURL)
|
||||
if err != nil {
|
||||
log.Error().Stack().Err(err).Msg("Error parsing URL: ")
|
||||
return ""
|
||||
}
|
||||
|
||||
return parsedURL.Host + parsedURL.Path
|
||||
}
|
||||
|
@ -18,8 +18,10 @@ import (
|
||||
"github.com/harness/gitness/app/auth/authz"
|
||||
"github.com/harness/gitness/app/services/refcache"
|
||||
gitnessstore "github.com/harness/gitness/app/store"
|
||||
"github.com/harness/gitness/app/url"
|
||||
storagedriver "github.com/harness/gitness/registry/app/driver"
|
||||
"github.com/harness/gitness/registry/app/event"
|
||||
registryevents "github.com/harness/gitness/registry/app/events"
|
||||
"github.com/harness/gitness/registry/app/manifest/manifestlist"
|
||||
"github.com/harness/gitness/registry/app/manifest/schema2"
|
||||
"github.com/harness/gitness/registry/app/pkg"
|
||||
@ -61,11 +63,13 @@ func ManifestServiceProvider(
|
||||
artifactDao store.ArtifactRepository, layerDao store.LayerRepository,
|
||||
gcService gc.Service, tx dbtx.Transactor, reporter event.Reporter, spaceFinder refcache.SpaceFinder,
|
||||
ociImageIndexMappingDao store.OCIImageIndexMappingRepository,
|
||||
artifactEventReporter *registryevents.Reporter,
|
||||
urlProvider url.Provider,
|
||||
) ManifestService {
|
||||
return NewManifestService(
|
||||
registryDao, manifestDao, blobRepo, mtRepository, tagDao, imageDao,
|
||||
artifactDao, layerDao, manifestRefDao, tx, gcService, reporter, spaceFinder,
|
||||
ociImageIndexMappingDao,
|
||||
ociImageIndexMappingDao, *artifactEventReporter, urlProvider,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,7 @@ import (
|
||||
|
||||
"github.com/harness/gitness/registry/app/api/openapi/contracts/artifact"
|
||||
"github.com/harness/gitness/registry/types"
|
||||
gitnesstypes "github.com/harness/gitness/types"
|
||||
|
||||
"github.com/lib/pq"
|
||||
"github.com/opencontainers/go-digest"
|
||||
@ -579,8 +580,13 @@ type GenericBlobRepository interface {
|
||||
}
|
||||
|
||||
type WebhooksRepository interface {
|
||||
Create(ctx context.Context, webhook *types.Webhook) error
|
||||
GetByRegistryAndIdentifier(ctx context.Context, registryID int64, webhookIdentifier string) (*types.Webhook, error)
|
||||
Create(ctx context.Context, webhook *gitnesstypes.WebhookCore) error
|
||||
GetByRegistryAndIdentifier(
|
||||
ctx context.Context,
|
||||
registryID int64,
|
||||
webhookIdentifier string,
|
||||
) (*gitnesstypes.WebhookCore, error)
|
||||
Find(ctx context.Context, webhookID int64) (*gitnesstypes.WebhookCore, error)
|
||||
ListByRegistry(
|
||||
ctx context.Context,
|
||||
sortByField string,
|
||||
@ -589,13 +595,42 @@ type WebhooksRepository interface {
|
||||
offset int,
|
||||
search string,
|
||||
registryID int64,
|
||||
) (*[]types.Webhook, error)
|
||||
) ([]*gitnesstypes.WebhookCore, error)
|
||||
ListAllByRegistry(
|
||||
ctx context.Context,
|
||||
parents []gitnesstypes.WebhookParentInfo,
|
||||
) ([]*gitnesstypes.WebhookCore, error)
|
||||
CountAllByRegistry(
|
||||
ctx context.Context,
|
||||
registryID int64,
|
||||
search string,
|
||||
) (int64, error)
|
||||
|
||||
Update(ctx context.Context, webhook *types.Webhook) error
|
||||
Update(ctx context.Context, webhook *gitnesstypes.WebhookCore) error
|
||||
DeleteByRegistryAndIdentifier(ctx context.Context, registryID int64, webhookIdentifier string) error
|
||||
UpdateOptLock(
|
||||
ctx context.Context, hook *gitnesstypes.WebhookCore,
|
||||
mutateFn func(hook *gitnesstypes.WebhookCore) error,
|
||||
) (*gitnesstypes.WebhookCore, error)
|
||||
}
|
||||
|
||||
type WebhooksExecutionRepository interface {
|
||||
Find(ctx context.Context, id int64) (*gitnesstypes.WebhookExecutionCore, error)
|
||||
|
||||
// Create creates a new webhook execution entry.
|
||||
Create(ctx context.Context, hook *gitnesstypes.WebhookExecutionCore) error
|
||||
|
||||
// ListForWebhook lists the webhook executions for a given webhook id.
|
||||
ListForWebhook(
|
||||
ctx context.Context,
|
||||
webhookID int64,
|
||||
limit int,
|
||||
page int,
|
||||
size int,
|
||||
) ([]*gitnesstypes.WebhookExecutionCore, error)
|
||||
|
||||
CountForWebhook(ctx context.Context, webhookID int64) (int64, error)
|
||||
|
||||
// ListForTrigger lists the webhook executions for a given trigger id.
|
||||
ListForTrigger(ctx context.Context, triggerID string) ([]*gitnesstypes.WebhookExecutionCore, error)
|
||||
}
|
||||
|
@ -261,6 +261,9 @@ func (r registryDao) GetAll(
|
||||
repoType string,
|
||||
recursive bool,
|
||||
) (repos *[]store.RegistryMetadata, err error) {
|
||||
if limit < 0 || offset < 0 {
|
||||
return nil, fmt.Errorf("limit and offset must be non-negative")
|
||||
}
|
||||
selectFields := `
|
||||
r.registry_id AS registry_id,
|
||||
r.registry_name AS reg_identifier,
|
||||
|
@ -22,16 +22,16 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/harness/gitness/registry/app/api/openapi/contracts/artifact"
|
||||
"github.com/harness/gitness/registry/app/pkg/commons"
|
||||
"github.com/harness/gitness/registry/app/store"
|
||||
"github.com/harness/gitness/registry/app/store/database/util"
|
||||
"github.com/harness/gitness/registry/types"
|
||||
"github.com/harness/gitness/registry/types/enum"
|
||||
gitnessstore "github.com/harness/gitness/store"
|
||||
"github.com/harness/gitness/store/database"
|
||||
"github.com/harness/gitness/store/database/dbtx"
|
||||
gitnesstypes "github.com/harness/gitness/types"
|
||||
gitnessenum "github.com/harness/gitness/types/enum"
|
||||
|
||||
"github.com/Masterminds/squirrel"
|
||||
"github.com/guregu/null"
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/pkg/errors"
|
||||
@ -95,7 +95,7 @@ type WebhookDao struct {
|
||||
db *sqlx.DB
|
||||
}
|
||||
|
||||
func (w WebhookDao) Create(ctx context.Context, webhook *types.Webhook) error {
|
||||
func (w WebhookDao) Create(ctx context.Context, webhook *gitnesstypes.WebhookCore) error {
|
||||
const sqlQuery = `
|
||||
INSERT INTO registry_webhooks (
|
||||
registry_webhook_registry_id
|
||||
@ -140,8 +140,8 @@ func (w WebhookDao) Create(ctx context.Context, webhook *types.Webhook) error {
|
||||
db := dbtx.GetAccessor(ctx, w.db)
|
||||
|
||||
dbwebhook, err := mapToWebhookDB(webhook)
|
||||
dbwebhook.Created = webhook.CreatedAt.UnixMilli()
|
||||
dbwebhook.Updated = webhook.UpdatedAt.UnixMilli()
|
||||
dbwebhook.Created = webhook.Created
|
||||
dbwebhook.Updated = webhook.Updated
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to map registry webhook to internal db type: %w", err)
|
||||
}
|
||||
@ -162,7 +162,7 @@ func (w WebhookDao) GetByRegistryAndIdentifier(
|
||||
ctx context.Context,
|
||||
registryID int64,
|
||||
webhookIdentifier string,
|
||||
) (*types.Webhook, error) {
|
||||
) (*gitnesstypes.WebhookCore, error) {
|
||||
query := database.Builder.Select(registryWebhooksFields...).
|
||||
From("registry_webhooks").
|
||||
Where("registry_webhook_registry_id = ? AND registry_webhook_identifier = ?", registryID, webhookIdentifier)
|
||||
@ -182,6 +182,28 @@ func (w WebhookDao) GetByRegistryAndIdentifier(
|
||||
return mapToWebhook(dst)
|
||||
}
|
||||
|
||||
func (w WebhookDao) Find(
|
||||
ctx context.Context, id int64,
|
||||
) (*gitnesstypes.WebhookCore, error) {
|
||||
query := database.Builder.Select(registryWebhooksFields...).
|
||||
From("registry_webhooks").
|
||||
Where("registry_webhook_id = ?", id)
|
||||
|
||||
sqlQuery, args, err := query.ToSql()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Failed to convert query to sql")
|
||||
}
|
||||
|
||||
db := dbtx.GetAccessor(ctx, w.db)
|
||||
|
||||
dst := new(webhookDB)
|
||||
if err = db.GetContext(ctx, dst, sqlQuery, args...); err != nil {
|
||||
return nil, database.ProcessSQLErrorf(ctx, err, "Failed to get webhook detail")
|
||||
}
|
||||
|
||||
return mapToWebhook(dst)
|
||||
}
|
||||
|
||||
func (w WebhookDao) ListByRegistry(
|
||||
ctx context.Context,
|
||||
sortByField string,
|
||||
@ -190,7 +212,7 @@ func (w WebhookDao) ListByRegistry(
|
||||
offset int,
|
||||
search string,
|
||||
registryID int64,
|
||||
) (*[]types.Webhook, error) {
|
||||
) ([]*gitnesstypes.WebhookCore, error) {
|
||||
query := database.Builder.Select(registryWebhooksFields...).
|
||||
From("registry_webhooks").
|
||||
Where("registry_webhook_registry_id = ?", registryID)
|
||||
@ -223,6 +245,31 @@ func (w WebhookDao) ListByRegistry(
|
||||
return mapToWebhooksList(dst)
|
||||
}
|
||||
|
||||
func (w WebhookDao) ListAllByRegistry(
|
||||
ctx context.Context,
|
||||
parents []gitnesstypes.WebhookParentInfo,
|
||||
) ([]*gitnesstypes.WebhookCore, error) {
|
||||
query := database.Builder.Select(registryWebhooksFields...).
|
||||
From("registry_webhooks")
|
||||
err := selectWebhookParents(parents, &query)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to select webhook parents: %w", err)
|
||||
}
|
||||
sqlQuery, args, err := query.ToSql()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Failed to convert query to sql")
|
||||
}
|
||||
|
||||
db := dbtx.GetAccessor(ctx, w.db)
|
||||
|
||||
var dst []*webhookDB
|
||||
if err = db.SelectContext(ctx, &dst, sqlQuery, args...); err != nil {
|
||||
return nil, database.ProcessSQLErrorf(ctx, err, "Failed to list webhooks details")
|
||||
}
|
||||
|
||||
return mapToWebhooksList(dst)
|
||||
}
|
||||
|
||||
func (w WebhookDao) CountAllByRegistry(
|
||||
ctx context.Context,
|
||||
registryID int64,
|
||||
@ -251,9 +298,10 @@ func (w WebhookDao) CountAllByRegistry(
|
||||
return count, nil
|
||||
}
|
||||
|
||||
func (w WebhookDao) Update(ctx context.Context, webhook *types.Webhook) error {
|
||||
func (w WebhookDao) Update(ctx context.Context, webhook *gitnesstypes.WebhookCore) error {
|
||||
var sqlQuery = " UPDATE registry_webhooks SET " +
|
||||
util.GetSetDBKeys(webhookDB{},
|
||||
"registry_webhook_id",
|
||||
"registry_webhook_identifier",
|
||||
"registry_webhook_registry_id",
|
||||
"registry_webhook_created",
|
||||
@ -265,7 +313,7 @@ func (w WebhookDao) Update(ctx context.Context, webhook *types.Webhook) error {
|
||||
" AND registry_webhook_registry_id = :registry_webhook_registry_id"
|
||||
|
||||
dbWebhook, err := mapToWebhookDB(webhook)
|
||||
dbWebhook.Updated = webhook.UpdatedAt.UnixMilli()
|
||||
dbWebhook.Updated = webhook.Updated
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -318,59 +366,89 @@ func (w WebhookDao) DeleteByRegistryAndIdentifier(
|
||||
return nil
|
||||
}
|
||||
|
||||
func mapToWebhookDB(webhook *types.Webhook) (*webhookDB, error) {
|
||||
if webhook.CreatedAt.IsZero() {
|
||||
webhook.CreatedAt = time.Now()
|
||||
// UpdateOptLock updates the webhook using the optimistic locking mechanism.
|
||||
func (w *WebhookDao) UpdateOptLock(
|
||||
ctx context.Context, hook *gitnesstypes.WebhookCore,
|
||||
mutateFn func(hook *gitnesstypes.WebhookCore) error,
|
||||
) (*gitnesstypes.WebhookCore, error) {
|
||||
for {
|
||||
dup := *hook
|
||||
|
||||
err := mutateFn(&dup)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to mutate the webhook: %w", err)
|
||||
}
|
||||
|
||||
err = w.Update(ctx, &dup)
|
||||
if err == nil {
|
||||
return &dup, nil
|
||||
}
|
||||
if !errors.Is(err, gitnessstore.ErrVersionConflict) {
|
||||
return nil, fmt.Errorf("failed to update the webhook: %w", err)
|
||||
}
|
||||
|
||||
hook, err = w.Find(ctx, hook.ID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to find the latst version of the webhook: %w", err)
|
||||
}
|
||||
}
|
||||
webhook.UpdatedAt = time.Now()
|
||||
dBwebhook := &webhookDB{
|
||||
}
|
||||
|
||||
func mapToWebhookDB(webhook *gitnesstypes.WebhookCore) (*webhookDB, error) {
|
||||
if webhook.Created < 0 {
|
||||
webhook.Created = time.Now().UnixMilli()
|
||||
}
|
||||
webhook.Updated = time.Now().UnixMilli()
|
||||
dBWebhook := &webhookDB{
|
||||
ID: webhook.ID,
|
||||
Version: webhook.Version,
|
||||
CreatedBy: webhook.CreatedBy,
|
||||
Identifier: webhook.Identifier,
|
||||
Scope: webhook.Scope,
|
||||
Name: webhook.Name,
|
||||
Name: webhook.DisplayName,
|
||||
Description: webhook.Description,
|
||||
URL: webhook.URL,
|
||||
SecretIdentifier: util.GetEmptySQLString(webhook.SecretIdentifier),
|
||||
SecretSpaceID: util.GetEmptySQLInt64(webhook.SecretSpaceID),
|
||||
Enabled: webhook.Enabled,
|
||||
Insecure: webhook.Insecure,
|
||||
Internal: webhook.Internal,
|
||||
Triggers: triggersToString(webhook.Triggers),
|
||||
ExtraHeaders: null.StringFrom(structListToString(webhook.ExtraHeaders)),
|
||||
LatestExecutionResult: null.StringFromPtr((*string)(webhook.LatestExecutionResult)),
|
||||
}
|
||||
|
||||
if webhook.Type == gitnessenum.WebhookTypeInternal {
|
||||
dBWebhook.Internal = true
|
||||
}
|
||||
|
||||
switch webhook.ParentType {
|
||||
case enum.WebhookParentRegistry:
|
||||
dBwebhook.RegistryID = null.IntFrom(webhook.ParentID)
|
||||
case enum.WebhookParentSpace:
|
||||
dBwebhook.SpaceID = null.IntFrom(webhook.ParentID)
|
||||
case gitnessenum.WebhookParentRegistry:
|
||||
dBWebhook.RegistryID = null.IntFrom(webhook.ParentID)
|
||||
case gitnessenum.WebhookParentSpace:
|
||||
dBWebhook.SpaceID = null.IntFrom(webhook.ParentID)
|
||||
default:
|
||||
return nil, fmt.Errorf("webhook parent type %q is not supported", webhook.ParentType)
|
||||
}
|
||||
return dBwebhook, nil
|
||||
return dBWebhook, nil
|
||||
}
|
||||
|
||||
func mapToWebhook(webhookDB *webhookDB) (*types.Webhook, error) {
|
||||
webhook := &types.Webhook{
|
||||
func mapToWebhook(webhookDB *webhookDB) (*gitnesstypes.WebhookCore, error) {
|
||||
webhook := &gitnesstypes.WebhookCore{
|
||||
ID: webhookDB.ID,
|
||||
Version: webhookDB.Version,
|
||||
CreatedBy: webhookDB.CreatedBy,
|
||||
CreatedAt: time.UnixMilli(webhookDB.Created),
|
||||
UpdatedAt: time.UnixMilli(webhookDB.Updated),
|
||||
Created: webhookDB.Created,
|
||||
Updated: webhookDB.Updated,
|
||||
Scope: webhookDB.Scope,
|
||||
Identifier: webhookDB.Identifier,
|
||||
Name: webhookDB.Name,
|
||||
DisplayName: webhookDB.Name,
|
||||
Description: webhookDB.Description,
|
||||
URL: webhookDB.URL,
|
||||
Enabled: webhookDB.Enabled,
|
||||
Internal: webhookDB.Internal,
|
||||
Insecure: webhookDB.Insecure,
|
||||
Triggers: triggersFromString(webhookDB.Triggers),
|
||||
ExtraHeaders: stringToStructList(webhookDB.ExtraHeaders.String),
|
||||
LatestExecutionResult: (*artifact.WebhookExecResult)(webhookDB.LatestExecutionResult.Ptr()),
|
||||
LatestExecutionResult: (*gitnessenum.WebhookExecutionResult)(webhookDB.LatestExecutionResult.Ptr()),
|
||||
}
|
||||
|
||||
if webhookDB.SecretIdentifier.Valid {
|
||||
@ -380,14 +458,20 @@ func mapToWebhook(webhookDB *webhookDB) (*types.Webhook, error) {
|
||||
webhook.SecretSpaceID = int(webhookDB.SecretSpaceID.Int64)
|
||||
}
|
||||
|
||||
if webhookDB.Internal {
|
||||
webhook.Type = gitnessenum.WebhookTypeInternal
|
||||
} else {
|
||||
webhook.Type = gitnessenum.WebhookTypeExternal
|
||||
}
|
||||
|
||||
switch {
|
||||
case webhookDB.RegistryID.Valid && webhookDB.SpaceID.Valid:
|
||||
return nil, fmt.Errorf("both registryID and spaceID are set for hook %d", webhookDB.ID)
|
||||
case webhookDB.RegistryID.Valid:
|
||||
webhook.ParentType = enum.WebhookParentRegistry
|
||||
webhook.ParentType = gitnessenum.WebhookParentRegistry
|
||||
webhook.ParentID = webhookDB.RegistryID.Int64
|
||||
case webhookDB.SpaceID.Valid:
|
||||
webhook.ParentType = enum.WebhookParentSpace
|
||||
webhook.ParentType = gitnessenum.WebhookParentSpace
|
||||
webhook.ParentID = webhookDB.SpaceID.Int64
|
||||
default:
|
||||
return nil, fmt.Errorf("neither registryID nor spaceID are set for hook %d", webhookDB.ID)
|
||||
@ -396,7 +480,32 @@ func mapToWebhook(webhookDB *webhookDB) (*types.Webhook, error) {
|
||||
return webhook, nil
|
||||
}
|
||||
|
||||
func triggersToString(triggers []artifact.Trigger) string {
|
||||
func selectWebhookParents(
|
||||
parents []gitnesstypes.WebhookParentInfo,
|
||||
stmt *squirrel.SelectBuilder,
|
||||
) error {
|
||||
var parentSelector squirrel.Or
|
||||
for _, parent := range parents {
|
||||
switch parent.Type {
|
||||
case gitnessenum.WebhookParentRegistry:
|
||||
parentSelector = append(parentSelector, squirrel.Eq{
|
||||
"registry_webhook_registry_id": parent.ID,
|
||||
})
|
||||
case gitnessenum.WebhookParentSpace:
|
||||
parentSelector = append(parentSelector, squirrel.Eq{
|
||||
"registry_webhook_space_id": parent.ID,
|
||||
})
|
||||
default:
|
||||
return fmt.Errorf("webhook parent type '%s' is not supported", parent.Type)
|
||||
}
|
||||
}
|
||||
|
||||
*stmt = stmt.Where(parentSelector)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func triggersToString(triggers []gitnessenum.WebhookTrigger) string {
|
||||
rawTriggers := make([]string, len(triggers))
|
||||
for i := range triggers {
|
||||
rawTriggers[i] = string(triggers[i])
|
||||
@ -405,22 +514,22 @@ func triggersToString(triggers []artifact.Trigger) string {
|
||||
return strings.Join(rawTriggers, triggersSeparator)
|
||||
}
|
||||
|
||||
func triggersFromString(triggersString string) []artifact.Trigger {
|
||||
func triggersFromString(triggersString string) []gitnessenum.WebhookTrigger {
|
||||
if triggersString == "" {
|
||||
return []artifact.Trigger{}
|
||||
return []gitnessenum.WebhookTrigger{}
|
||||
}
|
||||
|
||||
rawTriggers := strings.Split(triggersString, triggersSeparator)
|
||||
triggers := make([]artifact.Trigger, len(rawTriggers))
|
||||
triggers := make([]gitnessenum.WebhookTrigger, len(rawTriggers))
|
||||
for i, rawTrigger := range rawTriggers {
|
||||
triggers[i] = artifact.Trigger(rawTrigger)
|
||||
triggers[i] = gitnessenum.WebhookTrigger(rawTrigger)
|
||||
}
|
||||
|
||||
return triggers
|
||||
}
|
||||
|
||||
// Convert a list of ExtraHeaders structs to a JSON string.
|
||||
func structListToString(headers []artifact.ExtraHeader) string {
|
||||
func structListToString(headers []gitnesstypes.ExtraHeader) string {
|
||||
jsonData, err := json.Marshal(headers)
|
||||
if err != nil {
|
||||
return ""
|
||||
@ -429,8 +538,8 @@ func structListToString(headers []artifact.ExtraHeader) string {
|
||||
}
|
||||
|
||||
// Convert a JSON string back to a list of ExtraHeaders structs.
|
||||
func stringToStructList(jsonStr string) []artifact.ExtraHeader {
|
||||
var headers []artifact.ExtraHeader
|
||||
func stringToStructList(jsonStr string) []gitnesstypes.ExtraHeader {
|
||||
var headers []gitnesstypes.ExtraHeader
|
||||
err := json.Unmarshal([]byte(jsonStr), &headers)
|
||||
if err != nil {
|
||||
return nil
|
||||
@ -440,14 +549,14 @@ func stringToStructList(jsonStr string) []artifact.ExtraHeader {
|
||||
|
||||
func mapToWebhooksList(
|
||||
dst []*webhookDB,
|
||||
) (*[]types.Webhook, error) {
|
||||
webhooks := make([]types.Webhook, 0, len(dst))
|
||||
) ([]*gitnesstypes.WebhookCore, error) {
|
||||
webhooks := make([]*gitnesstypes.WebhookCore, 0, len(dst))
|
||||
for _, d := range dst {
|
||||
webhook, err := mapToWebhook(d)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
webhooks = append(webhooks, *webhook)
|
||||
webhooks = append(webhooks, webhook)
|
||||
}
|
||||
return &webhooks, nil
|
||||
return webhooks, nil
|
||||
}
|
||||
|
281
registry/app/store/database/webhookexecution.go
Normal file
281
registry/app/store/database/webhookexecution.go
Normal file
@ -0,0 +1,281 @@
|
||||
// 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 database
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/harness/gitness/registry/app/store"
|
||||
"github.com/harness/gitness/store/database"
|
||||
"github.com/harness/gitness/store/database/dbtx"
|
||||
gitnesstypes "github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
|
||||
"github.com/guregu/null"
|
||||
"github.com/jmoiron/sqlx"
|
||||
)
|
||||
|
||||
type WebhookExecutionDao struct {
|
||||
db *sqlx.DB
|
||||
}
|
||||
|
||||
const (
|
||||
webhookExecutionColumns = `
|
||||
registry_webhook_execution_id
|
||||
,registry_webhook_execution_retrigger_of
|
||||
,registry_webhook_execution_retriggerable
|
||||
,registry_webhook_execution_webhook_id
|
||||
,registry_webhook_execution_trigger_type
|
||||
,registry_webhook_execution_trigger_id
|
||||
,registry_webhook_execution_result
|
||||
,registry_webhook_execution_created
|
||||
,registry_webhook_execution_duration
|
||||
,registry_webhook_execution_error
|
||||
,registry_webhook_execution_request_url
|
||||
,registry_webhook_execution_request_headers
|
||||
,registry_webhook_execution_request_body
|
||||
,registry_webhook_execution_response_status_code
|
||||
,registry_webhook_execution_response_status
|
||||
,registry_webhook_execution_response_headers
|
||||
,registry_webhook_execution_response_body`
|
||||
|
||||
webhookExecutionSelectBase = `
|
||||
SELECT` + webhookExecutionColumns + `
|
||||
FROM registry_webhook_executions`
|
||||
)
|
||||
|
||||
func (w WebhookExecutionDao) Find(ctx context.Context, id int64) (*gitnesstypes.WebhookExecutionCore, error) {
|
||||
const sqlQuery = webhookExecutionSelectBase + `
|
||||
WHERE registry_webhook_execution_id = $1`
|
||||
|
||||
db := dbtx.GetAccessor(ctx, w.db)
|
||||
|
||||
dst := &webhookExecutionDB{}
|
||||
if err := db.GetContext(ctx, dst, sqlQuery, id); err != nil {
|
||||
return nil, database.ProcessSQLErrorf(ctx, err, "Select query failed")
|
||||
}
|
||||
|
||||
return mapToWebhookExecution(dst), nil
|
||||
}
|
||||
|
||||
func (w WebhookExecutionDao) Create(ctx context.Context, webhookExecution *gitnesstypes.WebhookExecutionCore) error {
|
||||
const sqlQuery = `
|
||||
INSERT INTO registry_webhook_executions (
|
||||
registry_webhook_execution_retrigger_of
|
||||
,registry_webhook_execution_retriggerable
|
||||
,registry_webhook_execution_webhook_id
|
||||
,registry_webhook_execution_trigger_type
|
||||
,registry_webhook_execution_trigger_id
|
||||
,registry_webhook_execution_result
|
||||
,registry_webhook_execution_created
|
||||
,registry_webhook_execution_duration
|
||||
,registry_webhook_execution_error
|
||||
,registry_webhook_execution_request_url
|
||||
,registry_webhook_execution_request_headers
|
||||
,registry_webhook_execution_request_body
|
||||
,registry_webhook_execution_response_status_code
|
||||
,registry_webhook_execution_response_status
|
||||
,registry_webhook_execution_response_headers
|
||||
,registry_webhook_execution_response_body
|
||||
) values (
|
||||
:registry_webhook_execution_retrigger_of
|
||||
,:registry_webhook_execution_retriggerable
|
||||
,:registry_webhook_execution_webhook_id
|
||||
,:registry_webhook_execution_trigger_type
|
||||
,:registry_webhook_execution_trigger_id
|
||||
,:registry_webhook_execution_result
|
||||
,:registry_webhook_execution_created
|
||||
,:registry_webhook_execution_duration
|
||||
,:registry_webhook_execution_error
|
||||
,:registry_webhook_execution_request_url
|
||||
,:registry_webhook_execution_request_headers
|
||||
,:registry_webhook_execution_request_body
|
||||
,:registry_webhook_execution_response_status_code
|
||||
,:registry_webhook_execution_response_status
|
||||
,:registry_webhook_execution_response_headers
|
||||
,:registry_webhook_execution_response_body
|
||||
) RETURNING registry_webhook_execution_id`
|
||||
|
||||
db := dbtx.GetAccessor(ctx, w.db)
|
||||
|
||||
dbwebhookExecution := mapToWebhookExecutionDB(webhookExecution)
|
||||
|
||||
query, arg, err := db.BindNamed(sqlQuery, dbwebhookExecution)
|
||||
if err != nil {
|
||||
return database.ProcessSQLErrorf(ctx, err, "Failed to registry bind webhook object")
|
||||
}
|
||||
|
||||
if err = db.QueryRowContext(ctx, query, arg...).Scan(&dbwebhookExecution.ID); err != nil {
|
||||
return database.ProcessSQLErrorf(ctx, err, "Insert query failed")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w WebhookExecutionDao) ListForWebhook(
|
||||
ctx context.Context,
|
||||
webhookID int64,
|
||||
limit int,
|
||||
page int,
|
||||
size int,
|
||||
) ([]*gitnesstypes.WebhookExecutionCore, error) {
|
||||
stmt := database.Builder.
|
||||
Select(webhookExecutionColumns).
|
||||
From("registry_webhook_executions").
|
||||
Where("registry_webhook_execution_webhook_id = ?", webhookID)
|
||||
|
||||
stmt = stmt.Limit(database.Limit(limit))
|
||||
stmt = stmt.Offset(database.Offset(page, size))
|
||||
|
||||
// fixed ordering by desc id (new ones first) - add customized ordering if deemed necessary.
|
||||
stmt = stmt.OrderBy("registry_webhook_execution_id DESC")
|
||||
|
||||
sql, args, err := stmt.ToSql()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to convert query to sql: %w", err)
|
||||
}
|
||||
|
||||
db := dbtx.GetAccessor(ctx, w.db)
|
||||
|
||||
dst := []*webhookExecutionDB{}
|
||||
if err = db.SelectContext(ctx, &dst, sql, args...); err != nil {
|
||||
return nil, database.ProcessSQLErrorf(ctx, err, "Select query failed")
|
||||
}
|
||||
|
||||
return mapToWebhookExecutions(dst), nil
|
||||
}
|
||||
|
||||
func (w WebhookExecutionDao) CountForWebhook(ctx context.Context, webhookID int64) (int64, error) {
|
||||
stmt := database.Builder.
|
||||
Select("COUNT(*)").
|
||||
From("registry_webhook_executions").
|
||||
Where("registry_webhook_execution_webhook_id = ?", webhookID)
|
||||
|
||||
sql, args, err := stmt.ToSql()
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to convert query to sql: %w", err)
|
||||
}
|
||||
|
||||
db := dbtx.GetAccessor(ctx, w.db)
|
||||
|
||||
var count int64
|
||||
if err = db.GetContext(ctx, &count, sql, args...); err != nil {
|
||||
return 0, database.ProcessSQLErrorf(ctx, err, "Count query failed")
|
||||
}
|
||||
|
||||
return count, nil
|
||||
}
|
||||
|
||||
func (w WebhookExecutionDao) ListForTrigger(
|
||||
ctx context.Context,
|
||||
triggerID string,
|
||||
) ([]*gitnesstypes.WebhookExecutionCore, error) {
|
||||
const sqlQuery = webhookExecutionSelectBase + `
|
||||
WHERE registry_webhook_execution_trigger_id = $1`
|
||||
|
||||
db := dbtx.GetAccessor(ctx, w.db)
|
||||
|
||||
dst := []*webhookExecutionDB{}
|
||||
if err := db.SelectContext(ctx, &dst, sqlQuery, triggerID); err != nil {
|
||||
return nil, database.ProcessSQLErrorf(ctx, err, "Select query failed")
|
||||
}
|
||||
|
||||
return mapToWebhookExecutions(dst), nil
|
||||
}
|
||||
|
||||
func NewWebhookExecutionDao(db *sqlx.DB) store.WebhooksExecutionRepository {
|
||||
return &WebhookExecutionDao{
|
||||
db: db,
|
||||
}
|
||||
}
|
||||
|
||||
type webhookExecutionDB struct {
|
||||
ID int64 `db:"registry_webhook_execution_id"`
|
||||
RetriggerOf null.Int `db:"registry_webhook_execution_retrigger_of"`
|
||||
Retriggerable bool `db:"registry_webhook_execution_retriggerable"`
|
||||
WebhookID int64 `db:"registry_webhook_execution_webhook_id"`
|
||||
TriggerType enum.WebhookTrigger `db:"registry_webhook_execution_trigger_type"`
|
||||
TriggerID string `db:"registry_webhook_execution_trigger_id"`
|
||||
Result enum.WebhookExecutionResult `db:"registry_webhook_execution_result"`
|
||||
Created int64 `db:"registry_webhook_execution_created"`
|
||||
Duration int64 `db:"registry_webhook_execution_duration"`
|
||||
Error string `db:"registry_webhook_execution_error"`
|
||||
RequestURL string `db:"registry_webhook_execution_request_url"`
|
||||
RequestHeaders string `db:"registry_webhook_execution_request_headers"`
|
||||
RequestBody string `db:"registry_webhook_execution_request_body"`
|
||||
ResponseStatusCode int `db:"registry_webhook_execution_response_status_code"`
|
||||
ResponseStatus string `db:"registry_webhook_execution_response_status"`
|
||||
ResponseHeaders string `db:"registry_webhook_execution_response_headers"`
|
||||
ResponseBody string `db:"registry_webhook_execution_response_body"`
|
||||
}
|
||||
|
||||
func mapToWebhookExecution(webhookExecutionDB *webhookExecutionDB) *gitnesstypes.WebhookExecutionCore {
|
||||
webhookExecution := &gitnesstypes.WebhookExecutionCore{
|
||||
ID: webhookExecutionDB.ID,
|
||||
RetriggerOf: webhookExecutionDB.RetriggerOf.Ptr(),
|
||||
Retriggerable: webhookExecutionDB.Retriggerable,
|
||||
WebhookID: webhookExecutionDB.WebhookID,
|
||||
TriggerType: webhookExecutionDB.TriggerType,
|
||||
TriggerID: webhookExecutionDB.TriggerID,
|
||||
Result: webhookExecutionDB.Result,
|
||||
Created: webhookExecutionDB.Created,
|
||||
Duration: webhookExecutionDB.Duration,
|
||||
Error: webhookExecutionDB.Error,
|
||||
Request: gitnesstypes.WebhookExecutionRequest{
|
||||
URL: webhookExecutionDB.RequestURL,
|
||||
Headers: webhookExecutionDB.RequestHeaders,
|
||||
Body: webhookExecutionDB.RequestBody,
|
||||
},
|
||||
Response: gitnesstypes.WebhookExecutionResponse{
|
||||
StatusCode: webhookExecutionDB.ResponseStatusCode,
|
||||
Status: webhookExecutionDB.ResponseStatus,
|
||||
Headers: webhookExecutionDB.ResponseHeaders,
|
||||
Body: webhookExecutionDB.ResponseBody,
|
||||
},
|
||||
}
|
||||
return webhookExecution
|
||||
}
|
||||
|
||||
func mapToWebhookExecutionDB(webhookExecution *gitnesstypes.WebhookExecutionCore) *webhookExecutionDB {
|
||||
webhookExecutionDD := &webhookExecutionDB{
|
||||
ID: webhookExecution.ID,
|
||||
RetriggerOf: null.IntFromPtr(webhookExecution.RetriggerOf),
|
||||
Retriggerable: webhookExecution.Retriggerable,
|
||||
WebhookID: webhookExecution.WebhookID,
|
||||
TriggerType: webhookExecution.TriggerType,
|
||||
TriggerID: webhookExecution.TriggerID,
|
||||
Result: webhookExecution.Result,
|
||||
Created: webhookExecution.Created,
|
||||
Duration: webhookExecution.Duration,
|
||||
Error: webhookExecution.Error,
|
||||
RequestURL: webhookExecution.Request.URL,
|
||||
RequestHeaders: webhookExecution.Request.Headers,
|
||||
RequestBody: webhookExecution.Request.Body,
|
||||
ResponseStatusCode: webhookExecution.Response.StatusCode,
|
||||
ResponseStatus: webhookExecution.Response.Status,
|
||||
ResponseHeaders: webhookExecution.Response.Headers,
|
||||
ResponseBody: webhookExecution.Response.Body,
|
||||
}
|
||||
return webhookExecutionDD
|
||||
}
|
||||
|
||||
func mapToWebhookExecutions(executions []*webhookExecutionDB) []*gitnesstypes.WebhookExecutionCore {
|
||||
m := make([]*gitnesstypes.WebhookExecutionCore, len(executions))
|
||||
for i, hook := range executions {
|
||||
m[i] = mapToWebhookExecution(hook)
|
||||
}
|
||||
return m
|
||||
}
|
@ -75,6 +75,10 @@ func ProvideWebhookDao(sqlDB *sqlx.DB) store.WebhooksRepository {
|
||||
return NewWebhookDao(sqlDB)
|
||||
}
|
||||
|
||||
func ProvideWebhookExecutionDao(sqlDB *sqlx.DB) store.WebhooksExecutionRepository {
|
||||
return NewWebhookExecutionDao(sqlDB)
|
||||
}
|
||||
|
||||
func ProvideManifestRefDao(db *sqlx.DB) store.ManifestReferenceRepository {
|
||||
return NewManifestReferenceDao(db)
|
||||
}
|
||||
@ -118,4 +122,5 @@ var WireSet = wire.NewSet(
|
||||
ProvideNodeDao,
|
||||
ProvideGenericBlobDao,
|
||||
ProvideWebhookDao,
|
||||
ProvideWebhookExecutionDao,
|
||||
)
|
||||
|
257
registry/services/webhook/handler_artifact.go
Normal file
257
registry/services/webhook/handler_artifact.go
Normal file
@ -0,0 +1,257 @@
|
||||
// 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
|
||||
}
|
56
registry/services/webhook/repository.go
Normal file
56
registry/services/webhook/repository.go
Normal file
@ -0,0 +1,56 @@
|
||||
package webhook
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
registrystore "github.com/harness/gitness/registry/app/store"
|
||||
"github.com/harness/gitness/types"
|
||||
)
|
||||
|
||||
type RegistryWebhookExecutorStore struct {
|
||||
webhookStore registrystore.WebhooksRepository
|
||||
webhookExecutionStore registrystore.WebhooksExecutionRepository
|
||||
}
|
||||
|
||||
func (s *RegistryWebhookExecutorStore) Find(ctx context.Context, id int64) (*types.WebhookExecutionCore, error) {
|
||||
return s.webhookExecutionStore.Find(ctx, id)
|
||||
}
|
||||
|
||||
func (s *RegistryWebhookExecutorStore) ListWebhooks(
|
||||
ctx context.Context,
|
||||
parents []types.WebhookParentInfo,
|
||||
) ([]*types.WebhookCore, error) {
|
||||
return s.webhookStore.ListAllByRegistry(ctx, parents)
|
||||
}
|
||||
|
||||
func (s *RegistryWebhookExecutorStore) ListForTrigger(
|
||||
ctx context.Context,
|
||||
triggerID string,
|
||||
) ([]*types.WebhookExecutionCore, error) {
|
||||
return s.webhookExecutionStore.ListForTrigger(ctx, triggerID)
|
||||
}
|
||||
|
||||
func (s *RegistryWebhookExecutorStore) CreateWebhookExecution(
|
||||
ctx context.Context,
|
||||
hook *types.WebhookExecutionCore,
|
||||
) error {
|
||||
return s.webhookExecutionStore.Create(ctx, hook)
|
||||
}
|
||||
|
||||
func (s *RegistryWebhookExecutorStore) UpdateOptLock(
|
||||
ctx context.Context, hook *types.WebhookCore,
|
||||
execution *types.WebhookExecutionCore,
|
||||
) (*types.WebhookCore, error) {
|
||||
fn := func(hook *types.WebhookCore) error {
|
||||
hook.LatestExecutionResult = &execution.Result
|
||||
return nil
|
||||
}
|
||||
return s.webhookStore.UpdateOptLock(ctx, hook, fn)
|
||||
}
|
||||
|
||||
func (s *RegistryWebhookExecutorStore) FindWebhook(
|
||||
ctx context.Context,
|
||||
id int64,
|
||||
) (*types.WebhookCore, error) {
|
||||
return s.webhookStore.Find(ctx, id)
|
||||
}
|
109
registry/services/webhook/service.go
Normal file
109
registry/services/webhook/service.go
Normal file
@ -0,0 +1,109 @@
|
||||
// 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"
|
||||
"time"
|
||||
|
||||
gitnesswebhook "github.com/harness/gitness/app/services/webhook"
|
||||
"github.com/harness/gitness/app/store"
|
||||
"github.com/harness/gitness/app/url"
|
||||
"github.com/harness/gitness/encrypt"
|
||||
"github.com/harness/gitness/events"
|
||||
events2 "github.com/harness/gitness/registry/app/events"
|
||||
registrystore "github.com/harness/gitness/registry/app/store"
|
||||
"github.com/harness/gitness/secret"
|
||||
"github.com/harness/gitness/store/database/dbtx"
|
||||
"github.com/harness/gitness/stream"
|
||||
)
|
||||
|
||||
const (
|
||||
eventsReaderGroupName = "gitness:webhook"
|
||||
)
|
||||
|
||||
// Service is responsible for processing webhook events.
|
||||
type Service struct {
|
||||
WebhookExecutor *gitnesswebhook.WebhookExecutor
|
||||
tx dbtx.Transactor
|
||||
urlProvider url.Provider
|
||||
spaceStore store.SpaceStore
|
||||
principalStore store.PrincipalStore
|
||||
config gitnesswebhook.Config
|
||||
spacePathStore store.SpacePathStore
|
||||
registryRepository registrystore.RegistryRepository
|
||||
}
|
||||
|
||||
func NewService(
|
||||
ctx context.Context,
|
||||
config gitnesswebhook.Config,
|
||||
tx dbtx.Transactor,
|
||||
artifactsReaderFactory *events.ReaderFactory[*events2.Reader],
|
||||
webhookStore registrystore.WebhooksRepository,
|
||||
webhookExecutionStore registrystore.WebhooksExecutionRepository,
|
||||
spaceStore store.SpaceStore,
|
||||
urlProvider url.Provider,
|
||||
principalStore store.PrincipalStore,
|
||||
webhookURLProvider gitnesswebhook.URLProvider,
|
||||
spacePathStore store.SpacePathStore,
|
||||
secretService secret.Service,
|
||||
registryRepository registrystore.RegistryRepository,
|
||||
encrypter encrypt.Encrypter,
|
||||
) (*Service, error) {
|
||||
if err := config.Prepare(); err != nil {
|
||||
return nil, fmt.Errorf("provided webhook service config is invalid: %w", err)
|
||||
}
|
||||
webhookExecutorStore := &RegistryWebhookExecutorStore{
|
||||
webhookStore: webhookStore,
|
||||
webhookExecutionStore: webhookExecutionStore,
|
||||
}
|
||||
executor := gitnesswebhook.NewWebhookExecutor(config, webhookURLProvider, encrypter, spacePathStore,
|
||||
secretService, principalStore, webhookExecutorStore, gitnesswebhook.ArtifactRegistryTrigger)
|
||||
|
||||
service := &Service{
|
||||
WebhookExecutor: executor,
|
||||
tx: tx,
|
||||
spaceStore: spaceStore,
|
||||
urlProvider: urlProvider,
|
||||
principalStore: principalStore,
|
||||
config: config,
|
||||
spacePathStore: spacePathStore,
|
||||
registryRepository: registryRepository,
|
||||
}
|
||||
|
||||
_, err := artifactsReaderFactory.Launch(ctx, eventsReaderGroupName, config.EventReaderName,
|
||||
func(r *events2.Reader) error {
|
||||
const idleTimeout = 1 * time.Minute
|
||||
r.Configure(
|
||||
stream.WithConcurrency(config.Concurrency),
|
||||
stream.WithHandlerOptions(
|
||||
stream.WithIdleTimeout(idleTimeout),
|
||||
stream.WithMaxRetries(config.MaxRetries),
|
||||
))
|
||||
|
||||
// register events
|
||||
_ = r.RegisterArtifactCreated(service.handleEventArtifactCreated)
|
||||
_ = r.RegisterArtifactUpdated(service.handleEventArtifactUpdated)
|
||||
_ = r.RegisterArtifactDeleted(service.handleEventArtifactDeleted)
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to launch git event reader for webhooks: %w", err)
|
||||
}
|
||||
|
||||
return service, nil
|
||||
}
|
73
registry/services/webhook/wire.go
Normal file
73
registry/services/webhook/wire.go
Normal file
@ -0,0 +1,73 @@
|
||||
// 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"
|
||||
"encoding/gob"
|
||||
|
||||
gitnesswebhook "github.com/harness/gitness/app/services/webhook"
|
||||
"github.com/harness/gitness/app/store"
|
||||
"github.com/harness/gitness/app/url"
|
||||
"github.com/harness/gitness/encrypt"
|
||||
"github.com/harness/gitness/events"
|
||||
registryevents "github.com/harness/gitness/registry/app/events"
|
||||
registrystore "github.com/harness/gitness/registry/app/store"
|
||||
"github.com/harness/gitness/secret"
|
||||
"github.com/harness/gitness/store/database/dbtx"
|
||||
|
||||
"github.com/google/wire"
|
||||
)
|
||||
|
||||
// WireSet provides a wire set for this package.
|
||||
var WireSet = wire.NewSet(
|
||||
ProvideService,
|
||||
)
|
||||
|
||||
func ProvideService(
|
||||
ctx context.Context,
|
||||
config gitnesswebhook.Config,
|
||||
tx dbtx.Transactor,
|
||||
artifactsReaderFactory *events.ReaderFactory[*registryevents.Reader],
|
||||
webhookStore registrystore.WebhooksRepository,
|
||||
webhookExecutionStore registrystore.WebhooksExecutionRepository,
|
||||
spaceStore store.SpaceStore,
|
||||
urlProvider url.Provider,
|
||||
principalStore store.PrincipalStore,
|
||||
webhookURLProvider gitnesswebhook.URLProvider,
|
||||
spacePathStore store.SpacePathStore,
|
||||
secretService secret.Service,
|
||||
registryRepository registrystore.RegistryRepository,
|
||||
encrypter encrypt.Encrypter,
|
||||
) (*Service, error) {
|
||||
gob.Register(®istryevents.DockerArtifact{})
|
||||
gob.Register(®istryevents.HelmArtifact{})
|
||||
return NewService(
|
||||
ctx,
|
||||
config,
|
||||
tx,
|
||||
artifactsReaderFactory,
|
||||
webhookStore,
|
||||
webhookExecutionStore,
|
||||
spaceStore,
|
||||
urlProvider,
|
||||
principalStore,
|
||||
webhookURLProvider,
|
||||
spacePathStore,
|
||||
secretService,
|
||||
registryRepository,
|
||||
encrypter,
|
||||
)
|
||||
}
|
@ -31,3 +31,16 @@ func sortEnum[T constraints.Ordered](slice []T) []T {
|
||||
slices.Sort(slice)
|
||||
return slice
|
||||
}
|
||||
|
||||
func Sanitize[E constraints.Ordered](element E, all func() ([]E, E)) (E, bool) {
|
||||
allValues, defValue := all()
|
||||
var empty E
|
||||
if element == empty && defValue != empty {
|
||||
return defValue, true
|
||||
}
|
||||
idx, exists := slices.BinarySearch(allValues, element)
|
||||
if exists {
|
||||
return allValues[idx], true
|
||||
}
|
||||
return defValue, false
|
||||
}
|
||||
|
@ -1,33 +0,0 @@
|
||||
// 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 enum
|
||||
|
||||
// RegistryWebhookParent defines different types of parents of a webhook.
|
||||
type RegistryWebhookParent string
|
||||
|
||||
func (RegistryWebhookParent) Enum() []interface{} { return toInterfaceSlice(webhookParents) }
|
||||
|
||||
const (
|
||||
// WebhookParentRegistry describes a registry as webhook owner.
|
||||
WebhookParentRegistry RegistryWebhookParent = "registry"
|
||||
|
||||
// WebhookParentSpace describes a space as webhook owner.
|
||||
WebhookParentSpace RegistryWebhookParent = "space"
|
||||
)
|
||||
|
||||
var webhookParents = sortEnum([]RegistryWebhookParent{
|
||||
WebhookParentRegistry,
|
||||
WebhookParentSpace,
|
||||
})
|
@ -1,46 +0,0 @@
|
||||
// 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 types
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/harness/gitness/registry/app/api/openapi/contracts/artifact"
|
||||
"github.com/harness/gitness/registry/types/enum"
|
||||
)
|
||||
|
||||
// Webhook DTO object.
|
||||
type Webhook struct {
|
||||
ID int64
|
||||
Version int64
|
||||
ParentType enum.RegistryWebhookParent
|
||||
ParentID int64
|
||||
CreatedBy int64
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
Scope int64
|
||||
Identifier string
|
||||
Name string
|
||||
Description string
|
||||
URL string
|
||||
SecretIdentifier string
|
||||
SecretSpaceID int
|
||||
Enabled bool
|
||||
Insecure bool
|
||||
Internal bool
|
||||
ExtraHeaders []artifact.ExtraHeader
|
||||
Triggers []artifact.Trigger
|
||||
LatestExecutionResult *artifact.WebhookExecResult
|
||||
}
|
@ -92,11 +92,15 @@ const (
|
||||
|
||||
// WebhookParentSpace describes a space as webhook owner.
|
||||
WebhookParentSpace WebhookParent = "space"
|
||||
|
||||
// WebhookParentRegistry describes a registry as webhook owner.
|
||||
WebhookParentRegistry WebhookParent = "registry"
|
||||
)
|
||||
|
||||
var webhookParents = sortEnum([]WebhookParent{
|
||||
WebhookParentRepo,
|
||||
WebhookParentSpace,
|
||||
WebhookParentRegistry,
|
||||
})
|
||||
|
||||
// WebhookExecutionResult defines the different results of a webhook execution.
|
||||
@ -130,7 +134,7 @@ const (
|
||||
// WebhookTypeExternal describes a webhook url pointing to external source.
|
||||
WebhookTypeExternal WebhookType = iota
|
||||
|
||||
// WebhookTypeInternal describes a webhook url pointing to internal url.
|
||||
// WebhookTypeInternal describes a repo webhook url pointing to internal url.
|
||||
WebhookTypeInternal
|
||||
|
||||
// WebhookTypeJira describes a webhook url pointing to jira.
|
||||
@ -190,6 +194,13 @@ const (
|
||||
WebhookTriggerPullReqLabelAssigned WebhookTrigger = "pullreq_label_assigned"
|
||||
// WebhookTriggerPullReqReviewSubmitted gets triggered when a pull request review is submitted.
|
||||
WebhookTriggerPullReqReviewSubmitted = "pullreq_review_submitted"
|
||||
|
||||
// WebhookTriggerArtifactCreated gets triggered when an artifact gets created.
|
||||
WebhookTriggerArtifactCreated WebhookTrigger = "artifact_created"
|
||||
// WebhookTriggerArtifactUpdated gets triggered when an artifact gets updated.
|
||||
WebhookTriggerArtifactUpdated WebhookTrigger = "artifact_updated"
|
||||
// WebhookTriggerArtifactDeleted gets triggered when an artifact gets deleted.
|
||||
WebhookTriggerArtifactDeleted WebhookTrigger = "artifact_deleted"
|
||||
)
|
||||
|
||||
var webhookTriggers = sortEnum([]WebhookTrigger{
|
||||
@ -210,4 +221,7 @@ var webhookTriggers = sortEnum([]WebhookTrigger{
|
||||
WebhookTriggerPullReqMerged,
|
||||
WebhookTriggerPullReqLabelAssigned,
|
||||
WebhookTriggerPullReqReviewSubmitted,
|
||||
WebhookTriggerArtifactCreated,
|
||||
WebhookTriggerArtifactUpdated,
|
||||
WebhookTriggerArtifactDeleted,
|
||||
})
|
||||
|
@ -153,3 +153,49 @@ type WebhookParentInfo struct {
|
||||
Type enum.WebhookParent
|
||||
ID int64
|
||||
}
|
||||
|
||||
// WebhookCore represents a webhook DTO object.
|
||||
type WebhookCore struct {
|
||||
ID int64
|
||||
Version int64
|
||||
ParentID int64
|
||||
ParentType enum.WebhookParent
|
||||
CreatedBy int64
|
||||
Created int64
|
||||
Updated int64
|
||||
Type enum.WebhookType
|
||||
Scope int64
|
||||
Identifier string
|
||||
DisplayName string
|
||||
Description string
|
||||
URL string
|
||||
Secret string
|
||||
Enabled bool
|
||||
Insecure bool
|
||||
Triggers []enum.WebhookTrigger
|
||||
LatestExecutionResult *enum.WebhookExecutionResult
|
||||
SecretIdentifier string
|
||||
SecretSpaceID int
|
||||
ExtraHeaders []ExtraHeader
|
||||
}
|
||||
|
||||
// WebhookExecutionCore represents a webhook execution DTO object.
|
||||
type WebhookExecutionCore struct {
|
||||
ID int64
|
||||
RetriggerOf *int64
|
||||
Retriggerable bool
|
||||
Created int64
|
||||
WebhookID int64
|
||||
TriggerType enum.WebhookTrigger
|
||||
TriggerID string
|
||||
Result enum.WebhookExecutionResult
|
||||
Duration int64
|
||||
Error string
|
||||
Request WebhookExecutionRequest
|
||||
Response WebhookExecutionResponse
|
||||
}
|
||||
|
||||
type ExtraHeader struct {
|
||||
Key string `json:"key,omitempty"`
|
||||
Value string `json:"value,omitempty"`
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user