// 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 protection import ( "context" "fmt" "github.com/harness/gitness/types" ) const TypeBranch types.RuleType = "branch" // Branch implements protection rules for the rule type TypeBranch. type Branch struct { Bypass DefBypass `json:"bypass"` PullReq DefPullReq `json:"pullreq"` Lifecycle DefLifecycle `json:"lifecycle"` } var ( // ensures that the Branch type implements Definition interface. _ Definition = (*Branch)(nil) ) func (v *Branch) MergeVerify( ctx context.Context, in MergeVerifyInput, ) (out MergeVerifyOutput, violations []types.RuleViolations, err error) { out, violations, err = v.PullReq.MergeVerify(ctx, in) if err != nil { return out, violations, fmt.Errorf("merge verify error: %w", err) } bypassable := v.Bypass.matches(ctx, in.Actor, in.IsRepoOwner, in.ResolveUserGroupID) bypassed := in.AllowBypass && bypassable for i := range violations { violations[i].Bypassable = bypassable violations[i].Bypassed = bypassed } return } func (v *Branch) RequiredChecks( ctx context.Context, in RequiredChecksInput, ) (RequiredChecksOutput, error) { out, err := v.PullReq.RequiredChecks(ctx, in) if err != nil { return RequiredChecksOutput{}, err } ids := out.RequiredIdentifiers if len(ids) == 0 { return RequiredChecksOutput{}, nil } var ( requiredIDs map[string]struct{} bypassableIDs map[string]struct{} ) if bypassable := v.Bypass.matches(ctx, in.Actor, in.IsRepoOwner, in.ResolveUserGroupID); bypassable { bypassableIDs = ids } else { requiredIDs = ids } return RequiredChecksOutput{ RequiredIdentifiers: requiredIDs, BypassableIdentifiers: bypassableIDs, }, nil } func (v *Branch) RefChangeVerify( ctx context.Context, in RefChangeVerifyInput, ) (violations []types.RuleViolations, err error) { if in.RefType != RefTypeBranch || len(in.RefNames) == 0 { return []types.RuleViolations{}, nil } violations, err = v.Lifecycle.RefChangeVerify(ctx, in) if err != nil { return nil, fmt.Errorf("lifecycle error: %w", err) } bypassable := v.Bypass.matches(ctx, in.Actor, in.IsRepoOwner, in.ResolveUserGroupID) bypassed := in.AllowBypass && bypassable for i := range violations { violations[i].Bypassable = bypassable violations[i].Bypassed = bypassed } return } func (v *Branch) UserIDs() ([]int64, error) { return v.Bypass.UserIDs, nil } func (v *Branch) UserGroupIDs() ([]int64, error) { return v.Bypass.UserGroupIDs, nil } func (v *Branch) Sanitize() error { if err := v.Bypass.Sanitize(); err != nil { return fmt.Errorf("bypass: %w", err) } if err := v.PullReq.Sanitize(); err != nil { return fmt.Errorf("pull request: %w", err) } if err := v.Lifecycle.Sanitize(); err != nil { return fmt.Errorf("lifecycle: %w", err) } return nil }