1 package owners
2
3 import (
4 "fmt"
5 "path/filepath"
6 "strings"
7
8 "edge-infra.dev/pkg/f8n/devinfra/repo/owners/policybot/policy"
9 "edge-infra.dev/pkg/f8n/devinfra/repo/owners/policybot/policy/approval"
10 "edge-infra.dev/pkg/f8n/devinfra/repo/owners/policybot/policy/common"
11 "edge-infra.dev/pkg/f8n/devinfra/repo/owners/policybot/policy/disapproval"
12 "edge-infra.dev/pkg/f8n/devinfra/repo/owners/policybot/policy/predicate"
13 "edge-infra.dev/pkg/f8n/devinfra/repo/owners/policybot/pull"
14 )
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33 func GeneratePolicyBotConfig(keys []string, ofiles map[string]File, rootOrRules []*approval.Rule) (*policy.Config, error) {
34 ghReview := true
35
36 p := &policy.Config{
37 ApprovalRules: []*approval.Rule{},
38 Policy: policy.Policy{
39 Disapproval: &disapproval.Policy{
40 Options: disapproval.Options{
41 Methods: disapproval.Methods{Disapprove: &common.Methods{
42 GithubReview: &ghReview,
43 }},
44 },
45 Requires: disapproval.Requires{
46 Actors: common.Actors{
47 Permissions: []pull.Permission{pull.PermissionWrite},
48 },
49 },
50 },
51 },
52 }
53
54
55 genApproval := approval.Policy{}
56 for _, key := range keys {
57 v, ok := ofiles[key]
58 if !ok {
59 continue
60 }
61 for _, r := range v.Rules {
62 setCommonOptions(r)
63
64 var err error
65 if r.Predicates.ChangedFiles != nil {
66 r.Predicates.ChangedFiles, err = prefixChangeFilePaths(
67 r.Predicates.ChangedFiles,
68 key,
69 )
70 if err != nil {
71 return nil, err
72 }
73 }
74
75 if r.Predicates.OnlyChangedFiles != nil {
76 r.Predicates.OnlyChangedFiles.Paths, err = prefixRegexp(
77 r.Predicates.OnlyChangedFiles.Paths,
78 key,
79 )
80 if err != nil {
81 return nil, err
82 }
83 }
84 }
85
86 p.ApprovalRules = append(p.ApprovalRules, v.Rules...)
87 genApproval = append(genApproval, v.Approval...)
88 }
89
90
91
92 if len(rootOrRules) == 0 {
93 p.Policy.Approval = genApproval
94 return p, nil
95 }
96
97
98
99 rules := make([]interface{}, len(rootOrRules)+1)
100 for i, r := range rootOrRules {
101 setCommonOptions(r)
102 rules[i] = r.Name
103 }
104 rules[len(rootOrRules)] = map[interface{}]interface{}{"and": genApproval}
105
106 p.Policy.Approval = append(p.Policy.Approval, map[interface{}]interface{}{
107 "or": rules,
108 })
109 p.ApprovalRules = append(p.ApprovalRules, rootOrRules...)
110 return p, nil
111 }
112
113 func prefixChangeFilePaths(files *predicate.ChangedFiles, path string) (*predicate.ChangedFiles, error) {
114 result := &predicate.ChangedFiles{
115 Paths: make([]common.Regexp, len(files.Paths)),
116 }
117
118 var err error
119 result.Paths, err = prefixRegexp(files.Paths, path)
120 if err != nil {
121 return nil, err
122 }
123
124 if len(files.IgnorePaths) == 0 {
125 return result, nil
126 }
127
128 result.IgnorePaths = make([]common.Regexp, len(files.IgnorePaths))
129 result.IgnorePaths, err = prefixRegexp(files.IgnorePaths, path)
130 if err != nil {
131 return nil, err
132 }
133
134 return result, nil
135 }
136
137 func prefixRegexp(rr []common.Regexp, path string) ([]common.Regexp, error) {
138 for i, r := range rr {
139 var (
140 rstr = r.String()
141 pattern string
142 )
143
144 switch {
145 case strings.HasPrefix(rstr, "^"):
146 pattern = fmt.Sprintf(
147 "^%s", filepath.Join(path, strings.TrimPrefix(rstr, "^")),
148 )
149 default:
150 pattern = filepath.Join(path, rstr)
151 }
152
153 re, err := common.NewRegexp(pattern)
154 if err != nil {
155 return nil, err
156 }
157 rr[i] = re
158 }
159 return rr, nil
160 }
161
162 func setCommonOptions(r *approval.Rule) {
163 ghReview := true
164 r.Options.InvalidateOnPush = true
165 r.Options.IgnoreUpdateMerges = true
166 r.Options.IgnoreCommitsBy = common.Actors{
167 Users: []string{"edge-bulldozer[bot]"},
168 }
169 r.Options.Methods = &common.Methods{
170 GithubReview: &ghReview,
171 Comments: []string{},
172 }
173 }
174
View as plain text