drone/internal/services/pullreq/handlers_branch.go
2023-01-31 12:34:18 +01:00

137 lines
4.2 KiB
Go

// Copyright 2022 Harness Inc. All rights reserved.
// Use of this source code is governed by the Polyform Free Trial License
// that can be found in the LICENSE.md file for this repository.
package pullreq
import (
"context"
"fmt"
"strings"
"github.com/harness/gitness/events"
gitevents "github.com/harness/gitness/internal/events/git"
pullreqevents "github.com/harness/gitness/internal/events/pullreq"
"github.com/harness/gitness/types"
"github.com/harness/gitness/types/enum"
"github.com/rs/zerolog/log"
)
// triggerPREventOnBranchUpdate handles branch update events. For every open pull request
// it writes an activity entry and triggers the pull request Branch Updated event.
func (s *Service) triggerPREventOnBranchUpdate(ctx context.Context,
event *events.Event[*gitevents.BranchUpdatedPayload],
) error {
s.forEveryOpenPR(ctx, event.Payload.RepoID, event.Payload.Ref, func(pr *types.PullReq) error {
err := func() (err error) {
pr, err = s.pullreqStore.UpdateActivitySeq(ctx, pr)
if err != nil {
return fmt.Errorf("failed to increment activity sequence: %w", err)
}
payload := &types.PullRequestActivityPayloadBranchUpdate{
Old: event.Payload.OldSHA,
New: event.Payload.NewSHA,
}
_, err = s.activityStore.CreateWithPayload(ctx, pr, event.Payload.PrincipalID, payload)
return
}()
if err != nil {
// non-critical error
log.Ctx(ctx).Err(err).Msgf("failed to write pull request activity after branch update")
}
s.pullreqEvReporter.BranchUpdated(ctx, &pullreqevents.BranchUpdatedPayload{
Base: pullreqevents.Base{
PullReqID: pr.ID,
SourceRepoID: pr.SourceRepoID,
TargetRepoID: pr.TargetRepoID,
PrincipalID: event.Payload.PrincipalID,
Number: pr.Number,
},
OldSHA: event.Payload.OldSHA,
NewSHA: event.Payload.NewSHA,
})
return nil
})
return nil
}
// closePullReqOnBranchDelete handles branch delete events.
// It closes every open pull request for the branch and triggers the pull request BranchDeleted event.
func (s *Service) closePullReqOnBranchDelete(ctx context.Context,
event *events.Event[*gitevents.BranchDeletedPayload],
) error {
s.forEveryOpenPR(ctx, event.Payload.RepoID, event.Payload.Ref, func(pr *types.PullReq) error {
pr, err := s.pullreqStore.UpdateOptLock(ctx, pr, func(pr *types.PullReq) error {
pr.State = enum.PullReqStateClosed
pr.ActivitySeq++ // because we need to write the activity
return nil
})
if err != nil {
return fmt.Errorf("failed to close pull request after branch delete: %w", err)
}
_, errAct := s.activityStore.CreateWithPayload(ctx, pr, event.Payload.PrincipalID,
&types.PullRequestActivityPayloadBranchDelete{SHA: event.Payload.SHA})
if errAct != nil {
// non-critical error
log.Ctx(ctx).Err(errAct).Msgf("failed to write pull request activity after branch delete")
}
s.pullreqEvReporter.Closed(ctx, &pullreqevents.ClosedPayload{
Base: pullreqevents.Base{
PullReqID: pr.ID,
SourceRepoID: pr.SourceRepoID,
TargetRepoID: pr.TargetRepoID,
PrincipalID: event.Payload.PrincipalID,
Number: pr.Number,
},
})
return nil
})
return nil
}
// forEveryOpenPR is utility function that executes the provided function
// for every open pull request created with the source branch given as a git ref.
func (s *Service) forEveryOpenPR(ctx context.Context,
repoID int64, ref string,
fn func(pr *types.PullReq) error,
) {
const refPrefix = "refs/heads/"
const largeLimit = 1000000
if !strings.HasPrefix(ref, refPrefix) {
log.Ctx(ctx).Error().Msg("failed to get branch name from branch ref")
return
}
branch := ref[len(refPrefix):]
if len(branch) == 0 {
log.Ctx(ctx).Error().Msg("got an empty branch name from branch ref")
return
}
pullreqList, err := s.pullreqStore.List(ctx, &types.PullReqFilter{
Page: 0,
Size: largeLimit,
SourceRepoID: repoID,
SourceBranch: branch,
States: []enum.PullReqState{enum.PullReqStateOpen},
Sort: enum.PullReqSortNumber,
Order: enum.OrderAsc,
})
if err != nil {
log.Ctx(ctx).Err(err).Msg("failed to get list of open pull requests")
return
}
for _, pr := range pullreqList {
if err = fn(pr); err != nil {
log.Ctx(ctx).Err(err).Msg("failed to process pull req")
}
}
}