...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package approval
16
17 import (
18 "context"
19 "fmt"
20
21 "github.com/rs/zerolog"
22
23 "edge-infra.dev/pkg/f8n/devinfra/repo/owners/policybot/pull"
24
25 "edge-infra.dev/pkg/f8n/devinfra/repo/owners/policybot/policy/common"
26 )
27
28 type evaluator struct {
29 root common.Evaluator
30 }
31
32 func (eval *evaluator) Trigger() common.Trigger {
33 if eval.root != nil {
34 return eval.root.Trigger()
35 }
36 return common.TriggerStatic
37 }
38
39 func (eval *evaluator) Evaluate(ctx context.Context, prctx pull.Context) (res common.Result) {
40 if eval.root != nil {
41 res = eval.root.Evaluate(ctx, prctx)
42 } else {
43 zerolog.Ctx(ctx).Debug().Msg("No approval policy defined; skipping")
44
45 res.Status = common.StatusApproved
46 res.StatusDescription = "No approval policy defined"
47 }
48
49 res.Name = "approval"
50 return
51 }
52
53 type RuleRequirement struct {
54 rule *Rule
55 }
56
57 func (r *RuleRequirement) Trigger() common.Trigger {
58 return r.rule.Trigger()
59 }
60
61 func (r *RuleRequirement) Evaluate(ctx context.Context, prctx pull.Context) common.Result {
62 log := zerolog.Ctx(ctx).With().Str("rule", r.rule.Name).Logger()
63 ctx = log.WithContext(ctx)
64
65 result := r.rule.Evaluate(ctx, prctx)
66 if result.Error == nil {
67 log.Debug().Msgf("rule evaluation resulted in %s:\"%s\"", result.Status, result.StatusDescription)
68 }
69
70 return result
71 }
72
73 type OrRequirement struct {
74 requirements []common.Evaluator
75 }
76
77 func (r *OrRequirement) Trigger() common.Trigger {
78 var t common.Trigger
79 for _, child := range r.requirements {
80 t |= child.Trigger()
81 }
82 return t
83 }
84
85 func (r *OrRequirement) Evaluate(ctx context.Context, prctx pull.Context) common.Result {
86 var children []*common.Result
87 for _, req := range r.requirements {
88 res := req.Evaluate(ctx, prctx)
89 children = append(children, &res)
90 }
91
92 var err error
93 var pending, approved, skipped int
94 for _, c := range children {
95 if c.Error != nil {
96 err = c.Error
97 continue
98 }
99
100 switch c.Status {
101 case common.StatusApproved:
102 approved++
103 case common.StatusPending:
104 pending++
105 case common.StatusSkipped:
106 skipped++
107 }
108 }
109
110 var status common.EvaluationStatus
111 description := "All of the rules are skipped"
112
113 switch {
114 case approved > 0:
115 status = common.StatusApproved
116 description = "One or more rules approved"
117 err = nil
118 case pending > 0:
119 status = common.StatusPending
120 description = "None of the rules are satisfied"
121 err = nil
122 }
123
124 return common.Result{
125 Name: "or",
126 Status: status,
127 StatusDescription: description,
128 Error: err,
129 Children: children,
130 }
131 }
132
133 type AndRequirement struct {
134 requirements []common.Evaluator
135 }
136
137 func (r *AndRequirement) Trigger() common.Trigger {
138 var t common.Trigger
139 for _, child := range r.requirements {
140 t |= child.Trigger()
141 }
142 return t
143 }
144
145 func (r *AndRequirement) Evaluate(ctx context.Context, prctx pull.Context) common.Result {
146 var children []*common.Result
147 for _, req := range r.requirements {
148 res := req.Evaluate(ctx, prctx)
149 children = append(children, &res)
150 }
151
152 var err error
153 var pending, approved, skipped int
154 for _, c := range children {
155 if c.Error != nil {
156 err = c.Error
157 continue
158 }
159
160 switch c.Status {
161 case common.StatusApproved:
162 approved++
163 case common.StatusPending:
164 pending++
165 case common.StatusSkipped:
166 skipped++
167 }
168 }
169
170 var status common.EvaluationStatus
171 description := "All of the rules are skipped"
172
173 switch {
174 case approved > 0 && pending == 0:
175 status = common.StatusApproved
176 description = fmt.Sprintf("All rules are approved")
177 case pending > 0:
178 status = common.StatusPending
179 description = fmt.Sprintf("%d/%d rules approved", approved, approved+pending)
180 }
181
182 return common.Result{
183 Name: "and",
184 Status: status,
185 StatusDescription: description,
186 Error: err,
187 Children: children,
188 }
189 }
190
View as plain text