feat: [CODE-3278]: Add PR activity for reviewers that were added on PR creation (#3499)

* Reuse PullRequestActivityPayloadReviewerAdd and amend it with PrinciaplIDs
* Remove unused and redundant activity (sub)type
* Merge remote-tracking branch 'origin/main' into dd/pr-reviewer-creation-activity
* Replace store individual activity per reviewer added with store batch
* Add PR activity for reviewers that were added on PR creation
try-new-ui
Darko Draskovic 2025-03-03 16:07:01 +00:00 committed by Harness
parent 50caca099f
commit bb82438965
3 changed files with 64 additions and 32 deletions

View File

@ -149,9 +149,7 @@ func (c *Controller) Create(
targetRepoID := targetRepo.ID
// Prepare create reviewers input
var reviewers []*types.PullReqReviewer
var activitySeq int64
// Payload based reviewers
@ -160,6 +158,12 @@ func (c *Controller) Create(
return nil, fmt.Errorf("failed to prepare reviewers: %w", err)
}
payloadReviewerIDs := maps.Keys(reviewerInputMap)
if len(reviewerInputMap) > 0 {
activitySeq++
}
// Rules based reviewers
codeownerReviewers, defaultReviewers, err := c.prepareRuleReviewers(
@ -169,6 +173,13 @@ func (c *Controller) Create(
return nil, fmt.Errorf("failed to prepare codeowners: %w", err)
}
if len(codeownerReviewers) > 0 {
activitySeq++
}
if len(defaultReviewers) > 0 {
activitySeq++
}
for _, codeownerReviewer := range codeownerReviewers {
if _, ok := reviewerInputMap[codeownerReviewer.ID]; !ok {
reviewerInputMap[codeownerReviewer.ID] = codeownerReviewer
@ -196,6 +207,8 @@ func (c *Controller) Create(
return nil, fmt.Errorf("failed to prepare labels: %w", err)
}
activitySeq += int64(len(labelAssignInputMap))
err = controller.TxOptLock(ctx, c.tx, func(ctx context.Context) error {
// Always re-fetch at the start of the transaction because the repo we have is from a cache.
@ -223,8 +236,7 @@ func (c *Controller) Create(
targetRepo = targetRepoFull.Core()
// Calculate the activity sequence
pr.ActivitySeq = int64(len(in.Labels) + len(in.ReviewerIDs))
pr.ActivitySeq = activitySeq
err = c.pullreqStore.Create(ctx, pr)
if err != nil {
@ -236,13 +248,12 @@ func (c *Controller) Create(
// Create reviewers and assign labels
reviewers, err = c.createReviewers(ctx, session, reviewerInputMap, targetRepo, pr)
if err != nil {
return err
if err = c.createReviewers(ctx, session, reviewerInputMap, targetRepo, pr); err != nil {
return fmt.Errorf("failed to create reviewers: %w", err)
}
if labelAssignOuts, err = c.assignLabels(ctx, pr, session.Principal.ID, labelAssignInputMap); err != nil {
return err
return fmt.Errorf("failed to assign labels: %w", err)
}
// Create PR head reference in the git repository
@ -264,9 +275,17 @@ func (c *Controller) Create(
return nil, fmt.Errorf("failed to create pullreq: %w", err)
}
backfillWithLabelAssignInfo(pr, labelAssignOuts)
c.storeCreateReviewerActivity(
ctx, pr, session.Principal.ID, payloadReviewerIDs, enum.PullReqReviewerTypeRequested,
)
c.storeCreateReviewerActivity(
ctx, pr, session.Principal.ID, maps.Keys(codeownerReviewers), enum.PullReqReviewerTypeCodeOwners,
)
c.storeCreateReviewerActivity(
ctx, pr, session.Principal.ID, maps.Keys(defaultReviewers), enum.PullReqReviewerTypeDefault,
)
c.storeCreateReviewerActivity(ctx, pr, session.Principal.ID, reviewers)
backfillWithLabelAssignInfo(pr, labelAssignOuts)
c.storeLabelAssignActivity(ctx, pr, session.Principal.ID, labelAssignOuts)
c.eventReporter.Created(ctx, &pullreqevents.CreatedPayload{
@ -447,9 +466,9 @@ func (c *Controller) createReviewers(
principalInfos map[int64]*types.PrincipalInfo,
repo *types.RepositoryCore,
pr *types.PullReq,
) ([]*types.PullReqReviewer, error) {
) error {
if len(principalInfos) == 0 {
return []*types.PullReqReviewer{}, nil
return nil
}
reviewers := make([]*types.PullReqReviewer, len(principalInfos))
@ -467,39 +486,44 @@ func (c *Controller) createReviewers(
)
if err := c.reviewerStore.Create(ctx, reviewer); err != nil {
return nil, fmt.Errorf("failed to create pull request reviewer: %w", err)
return fmt.Errorf("failed to create pull request reviewer: %w", err)
}
reviewers[i] = reviewer
i++
}
return reviewers, nil
return nil
}
func (c *Controller) storeCreateReviewerActivity(
ctx context.Context,
pr *types.PullReq,
principalID int64,
reviewers []*types.PullReqReviewer,
authorID int64,
reviewerIDs []int64,
reviewerType enum.PullReqReviewerType,
) {
for _, reviewer := range reviewers {
pr.ActivitySeq++
if len(reviewerIDs) == 0 {
return
}
payload := &types.PullRequestActivityPayloadReviewerAdd{
PrincipalID: reviewer.PrincipalID,
ReviewerType: enum.PullReqReviewerTypeRequested,
}
pr.ActivitySeq++
metadata := &types.PullReqActivityMetadata{
Mentions: &types.PullReqActivityMentionsMetadata{IDs: []int64{reviewer.PrincipalID}},
}
payload := &types.PullRequestActivityPayloadReviewerAdd{
ReviewerType: reviewerType,
PrinciaplIDs: reviewerIDs,
}
if _, err := c.activityStore.CreateWithPayload(
ctx, pr, principalID, payload, metadata,
); err != nil {
log.Ctx(ctx).Err(err).Msg("failed to write create reviewer pull req activity")
}
metadata := &types.PullReqActivityMetadata{
Mentions: &types.PullReqActivityMentionsMetadata{IDs: reviewerIDs},
}
if _, err := c.activityStore.CreateWithPayload(
ctx, pr, authorID, payload, metadata,
); err != nil {
log.Ctx(ctx).Err(err).Msgf(
"failed to write create %s reviewer pull req activity", reviewerType,
)
}
}

View File

@ -207,12 +207,19 @@ const (
PullReqReviewerTypeRequested PullReqReviewerType = "requested"
PullReqReviewerTypeAssigned PullReqReviewerType = "assigned"
PullReqReviewerTypeSelfAssigned PullReqReviewerType = "self_assigned"
// Used when adding reviewers on PR creation based on CODEOWNERS file or rules.
PullReqReviewerTypeCodeOwners PullReqReviewerType = "code_owners"
PullReqReviewerTypeDefault PullReqReviewerType = "default"
)
var pullReqReviewerTypes = sortEnum([]PullReqReviewerType{
PullReqReviewerTypeRequested,
PullReqReviewerTypeAssigned,
PullReqReviewerTypeSelfAssigned,
PullReqReviewerTypeCodeOwners,
PullReqReviewerTypeDefault,
})
type MergeMethod gitenum.MergeMethod

View File

@ -132,7 +132,8 @@ func (a *PullRequestActivityPayloadReviewSubmit) ActivityType() enum.PullReqActi
}
type PullRequestActivityPayloadReviewerAdd struct {
PrincipalID int64 `json:"principal_id"`
PrincipalID int64 `json:"principal_id,omitempty"`
PrinciaplIDs []int64 `json:"principal_ids,omitempty"`
ReviewerType enum.PullReqReviewerType `json:"reviewer_type"`
}