feat: [CODE-3256]: Add merge verify rule info related to minimum required approvals count for default reviewers (#3483)

* Merge remote-tracking branch 'origin/main' into dd/merge-verify-rules
* Replace princiapl ids with infos in merge verify response
* Populate DefaultReviewerApprovalsResponse with principal ids and current count
* Add MergeVerifyRulesResponse type
This commit is contained in:
Darko Draskovic 2025-02-26 17:56:59 +00:00 committed by Harness
parent d226aded79
commit cad0fbdf98
5 changed files with 47 additions and 27 deletions

View File

@ -40,6 +40,7 @@ import (
"github.com/gotidy/ptr"
"github.com/rs/zerolog/log"
"golang.org/x/exp/maps"
)
type MergeInput struct {
@ -230,6 +231,7 @@ func (c *Controller) Merge(
RequiresNoChangeRequests: ruleOut.RequiresNoChangeRequests,
MinimumRequiredApprovalsCount: ruleOut.MinimumRequiredApprovalsCount,
MinimumRequiredApprovalsCountLatest: ruleOut.MinimumRequiredApprovalsCountLatest,
DefaultReviewerApprovals: ruleOut.DefaultReviewerApprovals,
}, nil, nil
}
@ -330,24 +332,31 @@ func (c *Controller) Merge(
conflicts = pr.MergeConflicts
}
for _, approvals := range ruleOut.DefaultReviewerApprovals {
principalInfos, err := c.principalInfoCache.Map(ctx, approvals.PrincipalIDs)
if err != nil {
return nil, nil, fmt.Errorf("failed to fetch principal infos from info cache: %w", err)
}
approvals.PrincipalInfos = maps.Values(principalInfos)
}
// With in.DryRun=true this function never returns types.MergeViolations
out := &types.MergeResponse{
BranchDeleted: ruleOut.DeleteSourceBranch,
RuleViolations: violations,
// values only returned by dry run
DryRun: true,
Mergeable: len(conflicts) == 0,
ConflictFiles: conflicts,
AllowedMethods: ruleOut.AllowedMethods,
RequiresCodeOwnersApproval: ruleOut.RequiresCodeOwnersApproval,
RequiresCodeOwnersApprovalLatest: ruleOut.RequiresCodeOwnersApprovalLatest,
RequiresCommentResolution: ruleOut.RequiresCommentResolution,
RequiresNoChangeRequests: ruleOut.RequiresNoChangeRequests,
MinimumRequiredApprovalsCount: ruleOut.MinimumRequiredApprovalsCount,
MinimumRequiredApprovalsCountLatest: ruleOut.MinimumRequiredApprovalsCountLatest,
MinimumRequiredDefaultReviewerApprovalsCount: ruleOut.MinimumRequiredDefaultReviewerApprovalsCount,
MinimumRequiredDefaultReviewerApprovalsCountLatest: ruleOut.MinimumRequiredDefaultReviewerApprovalsCountLatest,
DryRun: true,
Mergeable: len(conflicts) == 0,
ConflictFiles: conflicts,
AllowedMethods: ruleOut.AllowedMethods,
RequiresCodeOwnersApproval: ruleOut.RequiresCodeOwnersApproval,
RequiresCodeOwnersApprovalLatest: ruleOut.RequiresCodeOwnersApprovalLatest,
RequiresCommentResolution: ruleOut.RequiresCommentResolution,
RequiresNoChangeRequests: ruleOut.RequiresNoChangeRequests,
MinimumRequiredApprovalsCount: ruleOut.MinimumRequiredApprovalsCount,
MinimumRequiredApprovalsCountLatest: ruleOut.MinimumRequiredApprovalsCountLatest,
DefaultReviewerApprovals: ruleOut.DefaultReviewerApprovals,
}
return out, nil, nil

View File

@ -54,24 +54,28 @@ func (s ruleSet) MergeVerify(
out.DeleteSourceBranch = out.DeleteSourceBranch || rOut.DeleteSourceBranch
out.MinimumRequiredApprovalsCount = maxInt(out.MinimumRequiredApprovalsCount, rOut.MinimumRequiredApprovalsCount)
out.MinimumRequiredApprovalsCountLatest = maxInt(out.MinimumRequiredApprovalsCountLatest, rOut.MinimumRequiredApprovalsCountLatest) //nolint:lll
out.MinimumRequiredDefaultReviewerApprovalsCount =
maxInt(out.MinimumRequiredDefaultReviewerApprovalsCount, rOut.MinimumRequiredDefaultReviewerApprovalsCount)
out.MinimumRequiredDefaultReviewerApprovalsCountLatest =
maxInt(out.MinimumRequiredDefaultReviewerApprovalsCountLatest, rOut.MinimumRequiredDefaultReviewerApprovalsCountLatest) //nolint:lll
out.DefaultReviewerIDs = append(out.DefaultReviewerIDs, rOut.DefaultReviewerIDs...)
out.RequiresCodeOwnersApproval = out.RequiresCodeOwnersApproval || rOut.RequiresCodeOwnersApproval
out.RequiresCodeOwnersApprovalLatest = out.RequiresCodeOwnersApprovalLatest || rOut.RequiresCodeOwnersApprovalLatest
out.RequiresCommentResolution = out.RequiresCommentResolution || rOut.RequiresCommentResolution
out.RequiresNoChangeRequests = out.RequiresNoChangeRequests || rOut.RequiresNoChangeRequests
if len(out.DefaultReviewerIDs) > 0 {
out.DefaultReviewerApprovals = append(out.DefaultReviewerApprovals, &types.DefaultReviewerApprovalsResponse{
RuleInfo: r.RuleInfo,
MinimumRequiredCount: rOut.MinimumRequiredDefaultReviewerApprovalsCount,
MinimumRequiredCountLatest: rOut.MinimumRequiredDefaultReviewerApprovalsCountLatest,
PrincipalIDs: rOut.DefaultReviewerIDs,
CurrentCount: rOut.DefaultReviewerApprovalsCount,
})
}
return nil
})
if err != nil {
return out, nil, fmt.Errorf("failed to process each rule in ruleSet: %w", err)
}
out.DefaultReviewerIDs = deduplicateInt64Slice(out.DefaultReviewerIDs)
return out, violations, nil
}

View File

@ -45,7 +45,6 @@ func TestRuleSet_MergeVerify(t *testing.T) {
expOut: MergeVerifyOutput{
DeleteSourceBranch: false,
AllowedMethods: enum.MergeMethods,
DefaultReviewerIDs: []int64{},
},
expViol: nil,
},
@ -60,7 +59,6 @@ func TestRuleSet_MergeVerify(t *testing.T) {
expOut: MergeVerifyOutput{
DeleteSourceBranch: false,
AllowedMethods: enum.MergeMethods,
DefaultReviewerIDs: []int64{},
},
expViol: nil,
},
@ -102,7 +100,6 @@ func TestRuleSet_MergeVerify(t *testing.T) {
DeleteSourceBranch: true,
MinimumRequiredApprovalsCount: 1,
AllowedMethods: []enum.MergeMethod{enum.MergeMethodMerge},
DefaultReviewerIDs: []int64{},
},
expViol: []types.RuleViolations{
{
@ -171,7 +168,6 @@ func TestRuleSet_MergeVerify(t *testing.T) {
expOut: MergeVerifyOutput{
DeleteSourceBranch: false,
AllowedMethods: []enum.MergeMethod{enum.MergeMethodRebase},
DefaultReviewerIDs: []int64{},
},
expViol: []types.RuleViolations{},
},
@ -279,7 +275,6 @@ func TestRuleSet_MergeVerify(t *testing.T) {
RequiresCodeOwnersApprovalLatest: true,
RequiresCommentResolution: true,
RequiresNoChangeRequests: true,
DefaultReviewerIDs: []int64{},
},
expViol: []types.RuleViolations{
{

View File

@ -60,6 +60,8 @@ type (
RequiresCommentResolution bool
RequiresNoChangeRequests bool
DefaultReviewerIDs []int64
DefaultReviewerApprovalsCount int
DefaultReviewerApprovals []*types.DefaultReviewerApprovalsResponse
}
RequiredChecksInput struct {
@ -216,6 +218,7 @@ func (v *DefPullReq) MergeVerify(
}
}
out.DefaultReviewerIDs = v.Reviewers.DefaultReviewerIDs
out.DefaultReviewerApprovalsCount = defaultReviewersCount
if v.Approvals.RequireCodeOwners {
for _, entry := range in.CodeOwners.EvaluationEntries {

View File

@ -251,6 +251,15 @@ type PullReqFileView struct {
Updated int64 `json:"-"`
}
type DefaultReviewerApprovalsResponse struct {
RuleInfo RuleInfo `json:"rule_info"`
MinimumRequiredCount int `json:"minimum_required_count"`
MinimumRequiredCountLatest int `json:"minimum_required_count_latest"`
CurrentCount int `json:"current_count"`
PrincipalIDs []int64 `json:"-"`
PrincipalInfos []*PrincipalInfo `json:"principals"`
}
type MergeResponse struct {
SHA string `json:"sha,omitempty"`
BranchDeleted bool `json:"branch_deleted,omitempty"`
@ -263,10 +272,10 @@ type MergeResponse struct {
ConflictFiles []string `json:"conflict_files,omitempty"`
AllowedMethods []enum.MergeMethod `json:"allowed_methods,omitempty"`
MinimumRequiredApprovalsCount int `json:"minimum_required_approvals_count,omitempty"`
MinimumRequiredApprovalsCountLatest int `json:"minimum_required_approvals_count_latest,omitempty"`
MinimumRequiredDefaultReviewerApprovalsCount int `json:"minimum_required_default_reviewer_approvals_count,omitempty"` //nolint:lll
MinimumRequiredDefaultReviewerApprovalsCountLatest int `json:"minimum_required_default_reviewer_approvals_count_latest,omitempty"` //nolint:lll
MinimumRequiredApprovalsCount int `json:"minimum_required_approvals_count,omitempty"`
MinimumRequiredApprovalsCountLatest int `json:"minimum_required_approvals_count_latest,omitempty"`
DefaultReviewerApprovals []*DefaultReviewerApprovalsResponse `json:"default_reviewer_aprovals,omitempty"`
RequiresCodeOwnersApproval bool `json:"requires_code_owners_approval,omitempty"`
RequiresCodeOwnersApprovalLatest bool `json:"requires_code_owners_approval_latest,omitempty"`