mirror of
https://github.com/harness/drone.git
synced 2025-05-30 19:23:07 +00:00
feat: [CODE-580]: code comment webhook (#706)
This commit is contained in:
parent
1dab5384c0
commit
3b2ed1de50
@ -22,6 +22,7 @@ import (
|
||||
|
||||
"github.com/harness/gitness/app/api/usererror"
|
||||
"github.com/harness/gitness/app/auth"
|
||||
events "github.com/harness/gitness/app/events/pullreq"
|
||||
"github.com/harness/gitness/gitrpc"
|
||||
"github.com/harness/gitness/store"
|
||||
"github.com/harness/gitness/types"
|
||||
@ -192,7 +193,19 @@ func (c *Controller) CommentCreate(
|
||||
if err = c.sseStreamer.Publish(ctx, repo.ParentID, enum.SSETypePullrequesUpdated, pr); err != nil {
|
||||
log.Ctx(ctx).Warn().Msg("failed to publish PR changed event")
|
||||
}
|
||||
|
||||
// if it's a regular comment publish a comment create event
|
||||
if !act.IsReply() && act.Type == enum.PullReqActivityTypeComment && act.Kind == enum.PullReqActivityKindComment {
|
||||
c.eventReporter.CommentCreated(ctx, &events.CommentCreatedPayload{
|
||||
Base: events.Base{
|
||||
PullReqID: pr.ID,
|
||||
SourceRepoID: pr.SourceRepoID,
|
||||
TargetRepoID: pr.TargetRepoID,
|
||||
PrincipalID: session.Principal.ID,
|
||||
Number: pr.Number,
|
||||
},
|
||||
ActivityID: act.ID,
|
||||
})
|
||||
}
|
||||
return act, nil
|
||||
}
|
||||
|
||||
|
54
app/events/pullreq/events_comment.go
Normal file
54
app/events/pullreq/events_comment.go
Normal file
@ -0,0 +1,54 @@
|
||||
// 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/rs/zerolog/log"
|
||||
)
|
||||
|
||||
const CommentCreatedEvent events.EventType = "comment-created"
|
||||
|
||||
type CommentCreatedPayload struct {
|
||||
Base
|
||||
ActivityID int64 `json:"activity_id"`
|
||||
}
|
||||
|
||||
func (r *Reporter) CommentCreated(
|
||||
ctx context.Context,
|
||||
payload *CommentCreatedPayload,
|
||||
) {
|
||||
if payload == nil {
|
||||
return
|
||||
}
|
||||
|
||||
eventID, err := events.ReporterSendEvent(r.innerReporter, ctx, CommentCreatedEvent, payload)
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Err(err).Msgf("failed to send pull request comment created event")
|
||||
return
|
||||
}
|
||||
|
||||
log.Ctx(ctx).Debug().Msgf("reported pull request comment created event with id '%s'", eventID)
|
||||
}
|
||||
|
||||
func (r *Reader) RegisterCommentCreated(
|
||||
fn events.HandlerFunc[*CommentCreatedPayload],
|
||||
opts ...events.HandlerOption,
|
||||
) error {
|
||||
return events.ReaderRegisterEvent(r.innerReader, CommentCreatedEvent, fn, opts...)
|
||||
}
|
@ -16,6 +16,7 @@ package webhook
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
pullreqevents "github.com/harness/gitness/app/events/pullreq"
|
||||
"github.com/harness/gitness/events"
|
||||
@ -235,3 +236,55 @@ func (s *Service) handleEventPullReqClosed(ctx context.Context,
|
||||
}, nil
|
||||
})
|
||||
}
|
||||
|
||||
// PullReqCommentPayload describes the body of the pullreq comment create trigger.
|
||||
type PullReqCommentPayload struct {
|
||||
BaseSegment
|
||||
PullReqSegment
|
||||
PullReqTargetReferenceSegment
|
||||
ReferenceSegment
|
||||
PullReqCommentSegment
|
||||
}
|
||||
|
||||
func (s *Service) handleEventPullReqComment(
|
||||
ctx context.Context,
|
||||
event *events.Event[*pullreqevents.CommentCreatedPayload],
|
||||
) error {
|
||||
return s.triggerForEventWithPullReq(ctx, enum.WebhookTriggerPullReqCommentCreated,
|
||||
event.ID, event.Payload.PrincipalID, event.Payload.PullReqID,
|
||||
func(principal *types.Principal, pr *types.PullReq, targetRepo, sourceRepo *types.Repository) (any, error) {
|
||||
targetRepoInfo := repositoryInfoFrom(targetRepo, s.urlProvider)
|
||||
sourceRepoInfo := repositoryInfoFrom(sourceRepo, s.urlProvider)
|
||||
activity, err := s.activityStore.Find(ctx, event.Payload.ActivityID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get activity by id for acitivity id %d: %w", event.Payload.ActivityID, err)
|
||||
}
|
||||
return &PullReqCommentPayload{
|
||||
BaseSegment: BaseSegment{
|
||||
Trigger: enum.WebhookTriggerPullReqCommentCreated,
|
||||
Repo: targetRepoInfo,
|
||||
Principal: principalInfoFrom(principal),
|
||||
},
|
||||
PullReqSegment: PullReqSegment{
|
||||
PullReq: pullReqInfoFrom(pr),
|
||||
},
|
||||
PullReqTargetReferenceSegment: PullReqTargetReferenceSegment{
|
||||
TargetRef: ReferenceInfo{
|
||||
Name: gitReferenceNamePrefixBranch + pr.TargetBranch,
|
||||
Repo: targetRepoInfo,
|
||||
},
|
||||
},
|
||||
ReferenceSegment: ReferenceSegment{
|
||||
Ref: ReferenceInfo{
|
||||
Name: gitReferenceNamePrefixBranch + pr.SourceBranch,
|
||||
Repo: sourceRepoInfo,
|
||||
},
|
||||
},
|
||||
PullReqCommentSegment: PullReqCommentSegment{
|
||||
CommentInfo: CommentInfo{
|
||||
Text: activity.Text,
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
})
|
||||
}
|
||||
|
@ -83,6 +83,7 @@ type Service struct {
|
||||
pullreqStore store.PullReqStore
|
||||
principalStore store.PrincipalStore
|
||||
gitRPCClient gitrpc.Interface
|
||||
activityStore store.PullReqActivityStore
|
||||
encrypter encrypt.Encrypter
|
||||
|
||||
secureHTTPClient *http.Client
|
||||
@ -94,12 +95,20 @@ type Service struct {
|
||||
config Config
|
||||
}
|
||||
|
||||
func NewService(ctx context.Context, config Config,
|
||||
func NewService(
|
||||
ctx context.Context,
|
||||
config Config,
|
||||
gitReaderFactory *events.ReaderFactory[*gitevents.Reader],
|
||||
prReaderFactory *events.ReaderFactory[*pullreqevents.Reader],
|
||||
webhookStore store.WebhookStore, webhookExecutionStore store.WebhookExecutionStore,
|
||||
repoStore store.RepoStore, pullreqStore store.PullReqStore, urlProvider url.Provider,
|
||||
principalStore store.PrincipalStore, gitRPCClient gitrpc.Interface, encrypter encrypt.Encrypter,
|
||||
webhookStore store.WebhookStore,
|
||||
webhookExecutionStore store.WebhookExecutionStore,
|
||||
repoStore store.RepoStore,
|
||||
pullreqStore store.PullReqStore,
|
||||
activityStore store.PullReqActivityStore,
|
||||
urlProvider url.Provider,
|
||||
principalStore store.PrincipalStore,
|
||||
gitRPCClient gitrpc.Interface,
|
||||
encrypter encrypt.Encrypter,
|
||||
) (*Service, error) {
|
||||
if err := config.Prepare(); err != nil {
|
||||
return nil, fmt.Errorf("provided webhook service config is invalid: %w", err)
|
||||
@ -109,6 +118,7 @@ func NewService(ctx context.Context, config Config,
|
||||
webhookExecutionStore: webhookExecutionStore,
|
||||
repoStore: repoStore,
|
||||
pullreqStore: pullreqStore,
|
||||
activityStore: activityStore,
|
||||
urlProvider: urlProvider,
|
||||
principalStore: principalStore,
|
||||
gitRPCClient: gitRPCClient,
|
||||
@ -163,6 +173,7 @@ func NewService(ctx context.Context, config Config,
|
||||
_ = r.RegisterReopened(service.handleEventPullReqReopened)
|
||||
_ = r.RegisterBranchUpdated(service.handleEventPullReqBranchUpdated)
|
||||
_ = r.RegisterClosed(service.handleEventPullReqClosed)
|
||||
_ = r.RegisterCommentCreated(service.handleEventPullReqComment)
|
||||
|
||||
return nil
|
||||
})
|
||||
|
@ -63,6 +63,11 @@ type PullReqSegment struct {
|
||||
PullReq PullReqInfo `json:"pull_req"`
|
||||
}
|
||||
|
||||
// PullReqCommentSegment contains details for all pull req comment related payloads for webhooks.
|
||||
type PullReqCommentSegment struct {
|
||||
CommentInfo CommentInfo `json:"comment"`
|
||||
}
|
||||
|
||||
// RepositoryInfo describes the repo related info for a webhook payload.
|
||||
// NOTE: don't use types package as we want webhook payload to be independent from API calls.
|
||||
type RepositoryInfo struct {
|
||||
@ -193,3 +198,7 @@ type ReferenceInfo struct {
|
||||
Name string `json:"name"`
|
||||
Repo RepositoryInfo `json:"repo"`
|
||||
}
|
||||
|
||||
type CommentInfo struct {
|
||||
Text string `json:"text"`
|
||||
}
|
||||
|
@ -33,13 +33,21 @@ var WireSet = wire.NewSet(
|
||||
ProvideService,
|
||||
)
|
||||
|
||||
func ProvideService(ctx context.Context, config Config,
|
||||
func ProvideService(ctx context.Context,
|
||||
config Config,
|
||||
gitReaderFactory *events.ReaderFactory[*gitevents.Reader],
|
||||
prReaderFactory *events.ReaderFactory[*pullreqevents.Reader],
|
||||
webhookStore store.WebhookStore, webhookExecutionStore store.WebhookExecutionStore,
|
||||
repoStore store.RepoStore, pullreqStore store.PullReqStore, urlProvider url.Provider,
|
||||
principalStore store.PrincipalStore, gitRPCClient gitrpc.Interface, encrypter encrypt.Encrypter) (*Service, error) {
|
||||
webhookStore store.WebhookStore,
|
||||
webhookExecutionStore store.WebhookExecutionStore,
|
||||
repoStore store.RepoStore,
|
||||
pullreqStore store.PullReqStore,
|
||||
activityStore store.PullReqActivityStore,
|
||||
urlProvider url.Provider,
|
||||
principalStore store.PrincipalStore,
|
||||
gitRPCClient gitrpc.Interface,
|
||||
encrypter encrypt.Encrypter,
|
||||
) (*Service, error) {
|
||||
return NewService(ctx, config, gitReaderFactory, prReaderFactory,
|
||||
webhookStore, webhookExecutionStore, repoStore, pullreqStore,
|
||||
webhookStore, webhookExecutionStore, repoStore, pullreqStore, activityStore,
|
||||
urlProvider, principalStore, gitRPCClient, encrypter)
|
||||
}
|
||||
|
@ -223,7 +223,7 @@ func initSystem(ctx context.Context, config *types.Config) (*server.System, erro
|
||||
webhookConfig := server.ProvideWebhookConfig(config)
|
||||
webhookStore := database.ProvideWebhookStore(db)
|
||||
webhookExecutionStore := database.ProvideWebhookExecutionStore(db)
|
||||
webhookService, err := webhook.ProvideService(ctx, webhookConfig, readerFactory, eventsReaderFactory, webhookStore, webhookExecutionStore, repoStore, pullReqStore, provider, principalStore, gitrpcInterface, encrypter)
|
||||
webhookService, err := webhook.ProvideService(ctx, webhookConfig, readerFactory, eventsReaderFactory, webhookStore, webhookExecutionStore, repoStore, pullReqStore, pullReqActivityStore, provider, principalStore, gitrpcInterface, encrypter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -135,6 +135,8 @@ const (
|
||||
WebhookTriggerPullReqBranchUpdated WebhookTrigger = "pullreq_branch_updated"
|
||||
// WebhookTriggerPullReqClosed gets triggered when a pull request is closed.
|
||||
WebhookTriggerPullReqClosed WebhookTrigger = "pullreq_closed"
|
||||
// WebhookTriggerPullReqCommentCreated gets triggered when a pull request comment gets created.
|
||||
WebhookTriggerPullReqCommentCreated WebhookTrigger = "pullreq_comment_created"
|
||||
)
|
||||
|
||||
var webhookTriggers = sortEnum([]WebhookTrigger{
|
||||
@ -148,4 +150,5 @@ var webhookTriggers = sortEnum([]WebhookTrigger{
|
||||
WebhookTriggerPullReqReopened,
|
||||
WebhookTriggerPullReqBranchUpdated,
|
||||
WebhookTriggerPullReqClosed,
|
||||
WebhookTriggerPullReqCommentCreated,
|
||||
})
|
||||
|
@ -753,6 +753,7 @@ export interface StringsMap {
|
||||
webhookListingContent: string
|
||||
webhookPRBranchUpdated: string
|
||||
webhookPRClosed: string
|
||||
webhookPRCommentCreated: string
|
||||
webhookPRCreated: string
|
||||
webhookPRReopened: string
|
||||
webhookSelectAllEvents: string
|
||||
|
@ -364,6 +364,7 @@ webhookPRBranchUpdated: PR branch updated
|
||||
webhookPRCreated: PR created
|
||||
webhookPRReopened: PR reopened
|
||||
webhookPRClosed: PR closed
|
||||
webhookPRCommentCreated: PR comment created
|
||||
nameYourWebhook: Name your webhook
|
||||
submitReview: Submit Review
|
||||
approve: Approve
|
||||
|
@ -55,7 +55,8 @@ enum WebhookIndividualEvent {
|
||||
PR_CREATED = 'pullreq_created',
|
||||
PR_REOPENED = 'pullreq_reopened',
|
||||
PR_BRANCH_UPDATED = 'pullreq_branch_updated',
|
||||
PR_CLOSED = 'pullreq_closed'
|
||||
PR_CLOSED = 'pullreq_closed',
|
||||
PR_COMMENT_CREATED = 'pullreq_comment_created'
|
||||
}
|
||||
|
||||
const SECRET_MASK = '********'
|
||||
@ -78,6 +79,7 @@ interface FormData {
|
||||
prReopened: boolean
|
||||
prBranchUpdated: boolean
|
||||
prClosed: boolean
|
||||
prCommentCreated: boolean
|
||||
}
|
||||
|
||||
interface WebHookFormProps extends Pick<GitInfoProps, 'repoMetadata'> {
|
||||
@ -116,6 +118,7 @@ export function WehookForm({ repoMetadata, isEdit, webhook }: WebHookFormProps)
|
||||
prReopened: webhook?.triggers?.includes(WebhookIndividualEvent.PR_REOPENED) || false,
|
||||
prBranchUpdated: webhook?.triggers?.includes(WebhookIndividualEvent.PR_BRANCH_UPDATED) || false,
|
||||
prClosed: webhook?.triggers?.includes(WebhookIndividualEvent.PR_CLOSED) || false,
|
||||
prCommentCreated: webhook?.triggers?.includes(WebhookIndividualEvent.PR_COMMENT_CREATED) || false,
|
||||
events: (webhook?.triggers?.length || 0) > 0 ? WebhookEventType.INDIVIDUAL : WebhookEventType.ALL
|
||||
}}
|
||||
formName="create-webhook-form"
|
||||
@ -162,6 +165,9 @@ export function WehookForm({ repoMetadata, isEdit, webhook }: WebHookFormProps)
|
||||
if (formData.prClosed) {
|
||||
triggers.push(WebhookIndividualEvent.PR_CLOSED)
|
||||
}
|
||||
if (formData.prCommentCreated) {
|
||||
triggers.push(WebhookIndividualEvent.PR_COMMENT_CREATED)
|
||||
}
|
||||
if (!triggers.length) {
|
||||
return showError(getString('oneMustBeSelected'))
|
||||
}
|
||||
@ -295,6 +301,11 @@ export function WehookForm({ repoMetadata, isEdit, webhook }: WebHookFormProps)
|
||||
name="prClosed"
|
||||
className={css.checkbox}
|
||||
/>
|
||||
<FormInput.CheckBox
|
||||
label={getString('webhookPRCommentCreated')}
|
||||
name="prCommentCreated"
|
||||
className={css.checkbox}
|
||||
/>
|
||||
</section>
|
||||
</article>
|
||||
) : null}
|
||||
|
@ -84,6 +84,7 @@ export type EnumWebhookTrigger =
|
||||
| 'pullreq_branch_updated'
|
||||
| 'pullreq_closed'
|
||||
| 'pullreq_created'
|
||||
| 'pullreq_comment_created'
|
||||
| 'pullreq_reopened'
|
||||
| 'tag_created'
|
||||
| 'tag_deleted'
|
||||
|
@ -6381,6 +6381,7 @@ components:
|
||||
- pullreq_branch_updated
|
||||
- pullreq_closed
|
||||
- pullreq_created
|
||||
- pullreq_comment_created
|
||||
- pullreq_reopened
|
||||
- tag_created
|
||||
- tag_deleted
|
||||
|
Loading…
x
Reference in New Issue
Block a user