Skip to content

Commit d5f05c7

Browse files
committed
Make the already existing predicates not use regex
1 parent 54028b6 commit d5f05c7

File tree

7 files changed

+118
-64
lines changed

7 files changed

+118
-64
lines changed

policy/common/regexp.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,21 @@ func NewRegexp(pattern string) (Regexp, error) {
3333
return Regexp{r: r}, nil
3434
}
3535

36+
func NewMustCompileRegexp(pattern string) Regexp {
37+
return Regexp{r: regexp.MustCompile(pattern)}
38+
}
39+
3640
func NewCompiledRegexp(r *regexp.Regexp) Regexp {
3741
return Regexp{r: r}
3842
}
3943

44+
// UnquoteMeta reverses the effect of QuoteMeta
45+
func UnquoteMeta(s string) string {
46+
re := regexp.MustCompile(`\\([\\.?])`) // Match escaped characters \\, \., and \?
47+
literalString := re.ReplaceAllString(s, "$1")
48+
return literalString
49+
}
50+
4051
func (r Regexp) Matches(s string) bool {
4152
if r.r == nil {
4253
return false

policy/predicate/status.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,15 @@ func NewHasStatus(statuses []string, conclusions []string) *HasStatus {
4444
var _ Predicate = HasStatus{}
4545

4646
func (pred HasStatus) Evaluate(ctx context.Context, prctx pull.Context) (*common.PredicateResult, error) {
47-
return HasStatusCheck{Checks: pred.Statuses, Conclusions: pred.Conclusions}.Evaluate(ctx, prctx)
47+
// Convert strings into a regex object to comply with function signature
48+
var checks []common.Regexp
49+
for _, status := range pred.Statuses {
50+
check, err := common.NewRegexp(status)
51+
if err == nil {
52+
checks = append(checks, check)
53+
}
54+
}
55+
return HasStatusCheck{Checks: checks, Conclusions: pred.Conclusions, noRegex: true}.Evaluate(ctx, prctx)
4856
}
4957

5058
func (pred HasStatus) Trigger() common.Trigger {
@@ -61,7 +69,7 @@ type HasSuccessfulStatus []string
6169
var _ Predicate = HasSuccessfulStatus{}
6270

6371
func (pred HasSuccessfulStatus) Evaluate(ctx context.Context, prctx pull.Context) (*common.PredicateResult, error) {
64-
return HasStatusCheck{Checks: pred}.Evaluate(ctx, prctx)
72+
return HasStatus{Statuses: pred}.Evaluate(ctx, prctx)
6573
}
6674

6775
func (pred HasSuccessfulStatus) Trigger() common.Trigger {

policy/predicate/status_check.go

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ package predicate
1717
import (
1818
"context"
1919
"fmt"
20+
"regexp"
2021
"slices"
2122
"strings"
2223

@@ -28,14 +29,16 @@ import (
2829
type HasStatusCheck struct {
2930
Conclusions AllowedConclusions `yaml:"conclusions"`
3031
Statuses AllowedStatuses `yaml:"statuses"`
31-
Checks []string `yaml:"checks,omitempty"`
32+
Checks []common.Regexp `yaml:"checks,omitempty"`
33+
noRegex bool
3234
}
3335

34-
func NewHasStatusCheck(checks []string, statuses []string, conclusions []string) *HasStatusCheck {
36+
func NewHasStatusCheck(checks []common.Regexp, statuses []string, conclusions []string) *HasStatusCheck {
3537
return &HasStatusCheck{
3638
Conclusions: conclusions,
3739
Statuses: statuses,
3840
Checks: checks,
41+
noRegex: false,
3942
}
4043
}
4144

@@ -76,21 +79,38 @@ func (pred HasStatusCheck) Evaluate(ctx context.Context, prctx pull.Context) (*c
7679

7780
var missingResults []string
7881
var failingStatuses []string
82+
var allChecks []string
7983
for _, check := range pred.Checks {
80-
if checkResult, ok := checkStatuses[check]; ok {
81-
isInvalidConclusion := !slices.Contains(allowedConclusions, *checkResult.Conclusion)
82-
if (checkResult.Status == nil || !slices.Contains(allowedStatuses, *checkResult.Status)) ||
83-
(slices.Contains(allowedStatuses, "completed") && checkResult.Conclusion != nil && isInvalidConclusion) {
84-
failingStatuses = append(failingStatuses, check)
84+
matched := false
85+
check_to_use := check
86+
if pred.noRegex {
87+
check_to_use, err = common.NewRegexp(fmt.Sprintf("^%s$", regexp.QuoteMeta(check.String())))
88+
if err != nil {
89+
return nil, errors.Wrapf(err, "failed to create regexp for workflow %s", check.String())
8590
}
86-
} else if repoStatusResult, ok := repoStatuses[check]; ok {
87-
if repoStatusResult == nil {
88-
missingResults = append(missingResults, check)
89-
} else if repoStatusResult.State == nil || !slices.Contains(allowedStatuses, *repoStatusResult.State) {
90-
failingStatuses = append(failingStatuses, check)
91+
}
92+
for checkResultName, checkResult := range checkStatuses {
93+
if check_to_use.Matches(checkResultName) {
94+
matched = true
95+
allChecks = append(allChecks, checkResultName)
96+
isInvalidConclusion := !slices.Contains(allowedConclusions, *checkResult.Conclusion)
97+
if (checkResult.Status == nil || !slices.Contains(allowedStatuses, *checkResult.Status)) ||
98+
(slices.Contains(allowedStatuses, "completed") && checkResult.Conclusion != nil && isInvalidConclusion) {
99+
failingStatuses = append(failingStatuses, checkResultName)
100+
}
101+
}
102+
}
103+
for repoStatusName, repoStatusResult := range repoStatuses {
104+
if check_to_use.Matches(repoStatusName) {
105+
matched = true
106+
allChecks = append(allChecks, repoStatusName)
107+
if repoStatusResult == nil || repoStatusResult.State == nil || !slices.Contains(allowedStatuses, *repoStatusResult.State) {
108+
failingStatuses = append(failingStatuses, repoStatusName)
109+
}
91110
}
92-
} else {
93-
missingResults = append(missingResults, check)
111+
}
112+
if !matched {
113+
missingResults = append(missingResults, check.String())
94114
}
95115
}
96116

@@ -108,7 +128,7 @@ func (pred HasStatusCheck) Evaluate(ctx context.Context, prctx pull.Context) (*c
108128
return &predicateResult, nil
109129
}
110130

111-
predicateResult.Values = pred.Checks
131+
predicateResult.Values = allChecks
112132
predicateResult.Satisfied = true
113133
return &predicateResult, nil
114134
}

policy/predicate/status_check_test.go

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -106,12 +106,17 @@ func mockRepoStatus(state string) *github.RepoStatus {
106106
}
107107

108108
func TestHasSuccessfulStatusCheck(t *testing.T) {
109-
hasStatusCheck := HasStatusCheck{Checks: []string{"status-name", "status-name-2"}}
109+
hasStatusCheck := HasStatusCheck{Checks: []common.Regexp{
110+
common.NewMustCompileRegexp("status-name"),
111+
common.NewMustCompileRegexp("status-name-2"),
112+
}}
110113
hasStatusCheckSkippedOk := HasStatusCheck{
111-
Checks: []string{"status-name", "status-name-2"},
114+
Checks: []common.Regexp{
115+
common.NewMustCompileRegexp("status-name"),
116+
common.NewMustCompileRegexp("status-name-2"),
117+
},
112118
Conclusions: AllowedConclusions{"success", "skipped"},
113119
}
114-
hasSuccessfulStatusCheck := HasSuccessfulStatus{"status-name", "status-name-2"}
115120

116121
commonTestCases := []StatusTestCase{
117122
{
@@ -218,8 +223,6 @@ func TestHasSuccessfulStatusCheck(t *testing.T) {
218223
testSuites := []StatusTestSuite{
219224
{predicate: hasStatusCheck, testCases: commonTestCases},
220225
{predicate: hasStatusCheck, testCases: okOnlyIfSkippedAllowed},
221-
{predicate: hasSuccessfulStatusCheck, testCases: commonTestCases},
222-
{predicate: hasSuccessfulStatusCheck, testCases: okOnlyIfSkippedAllowed},
223226
{
224227
nameSuffix: "skipped allowed",
225228
predicate: hasStatusCheckSkippedOk,

policy/predicate/workflow.go

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ package predicate
1717
import (
1818
"context"
1919
"fmt"
20+
"regexp"
2021
"slices"
2122
"strings"
2223

@@ -29,13 +30,15 @@ type HasWorkflow struct {
2930
Statuses AllowedStatuses `yaml:"statuses,omitempty"`
3031
Conclusions AllowedConclusions `yaml:"conclusions,omitempty"`
3132
Workflows []common.Regexp `yaml:"workflows,omitempty"`
33+
noRegex bool
3234
}
3335

3436
func NewHasWorkflow(workflows []common.Regexp, conclusions AllowedConclusions, statuses AllowedStatuses) *HasWorkflow {
3537
return &HasWorkflow{
3638
Statuses: statuses,
3739
Conclusions: conclusions,
3840
Workflows: workflows,
41+
noRegex: false,
3942
}
4043
}
4144

@@ -68,12 +71,21 @@ func (pred HasWorkflow) Evaluate(ctx context.Context, prctx pull.Context) (*comm
6871

6972
var missingResults []string
7073
var failingWorkflows []string
74+
var allWorkflows []string
7175
for _, workflow := range pred.Workflows {
7276
matched := false
73-
for name, workflowSteps := range workflowRuns {
74-
if workflow.Matches(name) {
77+
workflow_to_use := workflow
78+
if pred.noRegex {
79+
workflow_to_use, err = common.NewRegexp(fmt.Sprintf("^%s$", regexp.QuoteMeta(workflow.String())))
80+
if err != nil {
81+
return nil, errors.Wrapf(err, "failed to create regexp for workflow %s", workflow.String())
82+
}
83+
}
84+
for name, workflowRun := range workflowRuns {
85+
if workflow_to_use.Matches(name) {
7586
matched = true
76-
for _, workflowResult := range workflowSteps {
87+
allWorkflows = append(allWorkflows, name)
88+
for _, workflowResult := range workflowRun {
7789
isStatusAllowed := workflowResult.Status != nil && slices.Contains(allowedStatuses, *workflowResult.Status)
7890
isStatusCompletedAllowed := workflowResult.Status != nil && slices.Contains(allowedStatuses, "completed")
7991
isConclusionAllowed := workflowResult.Conclusion != nil && slices.Contains(allowedConclusions, *workflowResult.Conclusion)
@@ -102,11 +114,7 @@ func (pred HasWorkflow) Evaluate(ctx context.Context, prctx pull.Context) (*comm
102114
return &predicateResult, nil
103115
}
104116

105-
workflows := make([]string, len(pred.Workflows))
106-
for i, workflow := range pred.Workflows {
107-
workflows[i] = workflow.String()
108-
}
109-
predicateResult.Values = workflows
117+
predicateResult.Values = allWorkflows
110118
predicateResult.Satisfied = true
111119

112120
return &predicateResult, nil

policy/predicate/workflow_test.go

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ func TestHasSuccessfulWorkflowRun(t *testing.T) {
3131
latestWorkflowRunsValue: map[string][]*github.WorkflowRun{
3232
".github/workflows/test.yml": {mockWorkflowRun("completed", "success")},
3333
},
34-
predicate: HasWorkflowResult{
35-
Workflows: []string{".github/workflows/test.yml"},
34+
predicate: HasWorkflow{
35+
Workflows: []common.Regexp{common.NewMustCompileRegexp(".github/workflows/test.yml")},
3636
},
3737
ExpectedPredicateResult: &common.PredicateResult{
3838
Satisfied: true,
@@ -45,8 +45,8 @@ func TestHasSuccessfulWorkflowRun(t *testing.T) {
4545
".github/workflows/test.yml": {mockWorkflowRun("completed", "success")},
4646
".github/workflows/test2.yml": {mockWorkflowRun("completed", "success")},
4747
},
48-
predicate: HasWorkflowResult{
49-
Workflows: []string{".github/workflows/test.yml", ".github/workflows/test2.yml"},
48+
predicate: HasWorkflow{
49+
Workflows: []common.Regexp{common.NewMustCompileRegexp(".github/workflows/test.yml"), common.NewMustCompileRegexp(".github/workflows/test2.yml")},
5050
},
5151
ExpectedPredicateResult: &common.PredicateResult{
5252
Satisfied: true,
@@ -58,8 +58,8 @@ func TestHasSuccessfulWorkflowRun(t *testing.T) {
5858
latestWorkflowRunsValue: map[string][]*github.WorkflowRun{
5959
".github/workflows/test.yml": {mockWorkflowRun("completed", "failure")},
6060
},
61-
predicate: HasWorkflowResult{
62-
Workflows: []string{".github/workflows/test.yml"},
61+
predicate: HasWorkflow{
62+
Workflows: []common.Regexp{common.NewMustCompileRegexp(".github/workflows/test.yml")},
6363
},
6464
ExpectedPredicateResult: &common.PredicateResult{
6565
Satisfied: false,
@@ -71,8 +71,8 @@ func TestHasSuccessfulWorkflowRun(t *testing.T) {
7171
latestWorkflowRunsValue: map[string][]*github.WorkflowRun{
7272
".github/workflows/test.yml": {mockWorkflowRun("completed", "failure"), mockWorkflowRun("completed", "success")},
7373
},
74-
predicate: HasWorkflowResult{
75-
Workflows: []string{".github/workflows/test.yml"},
74+
predicate: HasWorkflow{
75+
Workflows: []common.Regexp{common.NewMustCompileRegexp(".github/workflows/test.yml")},
7676
},
7777
ExpectedPredicateResult: &common.PredicateResult{
7878
Satisfied: false,
@@ -85,8 +85,8 @@ func TestHasSuccessfulWorkflowRun(t *testing.T) {
8585
".github/workflows/test.yml": {mockWorkflowRun("completed", "failure")},
8686
".github/workflows/test2.yml": {mockWorkflowRun("completed", "failure")},
8787
},
88-
predicate: HasWorkflowResult{
89-
Workflows: []string{".github/workflows/test.yml", ".github/workflows/test2.yml"},
88+
predicate: HasWorkflow{
89+
Workflows: []common.Regexp{common.NewMustCompileRegexp(".github/workflows/test.yml"), common.NewMustCompileRegexp(".github/workflows/test2.yml")},
9090
},
9191
ExpectedPredicateResult: &common.PredicateResult{
9292
Satisfied: false,
@@ -99,8 +99,8 @@ func TestHasSuccessfulWorkflowRun(t *testing.T) {
9999
".github/workflows/test.yml": {mockWorkflowRun("completed", "success")},
100100
".github/workflows/test2.yml": {mockWorkflowRun("completed", "failure")},
101101
},
102-
predicate: HasWorkflowResult{
103-
Workflows: []string{".github/workflows/test.yml", ".github/workflows/test2.yml"},
102+
predicate: HasWorkflow{
103+
Workflows: []common.Regexp{common.NewMustCompileRegexp(".github/workflows/test.yml"), common.NewMustCompileRegexp(".github/workflows/test2.yml")},
104104
},
105105
ExpectedPredicateResult: &common.PredicateResult{
106106
Satisfied: false,
@@ -110,8 +110,8 @@ func TestHasSuccessfulWorkflowRun(t *testing.T) {
110110
{
111111
name: "a workflow is missing",
112112
latestWorkflowRunsValue: map[string][]*github.WorkflowRun{},
113-
predicate: HasWorkflowResult{
114-
Workflows: []string{".github/workflows/test.yml"},
113+
predicate: HasWorkflow{
114+
Workflows: []common.Regexp{common.NewMustCompileRegexp(".github/workflows/test.yml")},
115115
},
116116
ExpectedPredicateResult: &common.PredicateResult{
117117
Satisfied: false,
@@ -121,8 +121,8 @@ func TestHasSuccessfulWorkflowRun(t *testing.T) {
121121
{
122122
name: "multiple workflow are missing",
123123
latestWorkflowRunsValue: map[string][]*github.WorkflowRun{},
124-
predicate: HasWorkflowResult{
125-
Workflows: []string{".github/workflows/test.yml", ".github/workflows/test2.yml"},
124+
predicate: HasWorkflow{
125+
Workflows: []common.Regexp{common.NewMustCompileRegexp(".github/workflows/test.yml"), common.NewMustCompileRegexp(".github/workflows/test2.yml")},
126126
},
127127
ExpectedPredicateResult: &common.PredicateResult{
128128
Satisfied: false,
@@ -134,8 +134,8 @@ func TestHasSuccessfulWorkflowRun(t *testing.T) {
134134
latestWorkflowRunsValue: map[string][]*github.WorkflowRun{
135135
".github/workflows/test2.yml": {mockWorkflowRun("completed", "skipped")},
136136
},
137-
predicate: HasWorkflowResult{
138-
Workflows: []string{".github/workflows/test.yml", ".github/workflows/test2.yml"},
137+
predicate: HasWorkflow{
138+
Workflows: []common.Regexp{common.NewMustCompileRegexp(".github/workflows/test.yml"), common.NewMustCompileRegexp(".github/workflows/test2.yml")},
139139
},
140140
ExpectedPredicateResult: &common.PredicateResult{
141141
Satisfied: false,
@@ -147,8 +147,8 @@ func TestHasSuccessfulWorkflowRun(t *testing.T) {
147147
latestWorkflowRunsValue: map[string][]*github.WorkflowRun{
148148
".github/workflows/test.yml": {mockWorkflowRun("completed", "skipped")},
149149
},
150-
predicate: HasWorkflowResult{
151-
Workflows: []string{".github/workflows/test.yml"},
150+
predicate: HasWorkflow{
151+
Workflows: []common.Regexp{common.NewMustCompileRegexp(".github/workflows/test.yml")},
152152
Conclusions: AllowedConclusions{"skipped"},
153153
},
154154
ExpectedPredicateResult: &common.PredicateResult{
@@ -162,8 +162,8 @@ func TestHasSuccessfulWorkflowRun(t *testing.T) {
162162
".github/workflows/test.yml": {mockWorkflowRun("completed", "success")},
163163
".github/workflows/test2.yml": {mockWorkflowRun("completed", "skipped")},
164164
},
165-
predicate: HasWorkflowResult{
166-
Workflows: []string{".github/workflows/test.yml", ".github/workflows/test2.yml"},
165+
predicate: HasWorkflow{
166+
Workflows: []common.Regexp{common.NewMustCompileRegexp(".github/workflows/test.yml"), common.NewMustCompileRegexp(".github/workflows/test2.yml")},
167167
Conclusions: AllowedConclusions{"skipped", "success"},
168168
},
169169
ExpectedPredicateResult: &common.PredicateResult{
@@ -176,8 +176,8 @@ func TestHasSuccessfulWorkflowRun(t *testing.T) {
176176
latestWorkflowRunsValue: map[string][]*github.WorkflowRun{
177177
".github/workflows/test.yml": {mockWorkflowRun("completed", "success"), mockWorkflowRun("completed", "skipped")},
178178
},
179-
predicate: HasWorkflowResult{
180-
Workflows: []string{".github/workflows/test.yml"},
179+
predicate: HasWorkflow{
180+
Workflows: []common.Regexp{common.NewMustCompileRegexp(".github/workflows/test.yml")},
181181
Conclusions: AllowedConclusions{"skipped", "success"},
182182
},
183183
ExpectedPredicateResult: &common.PredicateResult{
@@ -191,8 +191,8 @@ func TestHasSuccessfulWorkflowRun(t *testing.T) {
191191
".github/workflows/test.yml": {mockWorkflowRun("completed", "failure")},
192192
".github/workflows/test2.yml": {mockWorkflowRun("completed", "skipped")},
193193
},
194-
predicate: HasWorkflowResult{
195-
Workflows: []string{".github/workflows/test.yml", ".github/workflows/test2.yml"},
194+
predicate: HasWorkflow{
195+
Workflows: []common.Regexp{common.NewMustCompileRegexp(".github/workflows/test.yml"), common.NewMustCompileRegexp(".github/workflows/test2.yml")},
196196
Conclusions: AllowedConclusions{"skipped", "success"},
197197
},
198198
ExpectedPredicateResult: &common.PredicateResult{
@@ -206,8 +206,8 @@ func TestHasSuccessfulWorkflowRun(t *testing.T) {
206206
".github/workflows/test.yml": {mockWorkflowRun("completed", "success")},
207207
".github/workflows/test2.yml": {mockWorkflowRun("completed", "skipped")},
208208
},
209-
predicate: HasWorkflowResult{
210-
Workflows: []string{".github/workflows/test.yml", ".github/workflows/test2.yml"},
209+
predicate: HasWorkflow{
210+
Workflows: []common.Regexp{common.NewMustCompileRegexp(".github/workflows/test.yml"), common.NewMustCompileRegexp(".github/workflows/test2.yml")},
211211
Conclusions: AllowedConclusions{"skipped"},
212212
},
213213
ExpectedPredicateResult: &common.PredicateResult{
@@ -220,8 +220,8 @@ func TestHasSuccessfulWorkflowRun(t *testing.T) {
220220
latestWorkflowRunsValue: map[string][]*github.WorkflowRun{
221221
".github/workflows/test.yml": {mockWorkflowRun("completed", "success"), mockWorkflowRun("completed", "skipped")},
222222
},
223-
predicate: HasWorkflowResult{
224-
Workflows: []string{".github/workflows/test.yml"},
223+
predicate: HasWorkflow{
224+
Workflows: []common.Regexp{common.NewMustCompileRegexp(".github/workflows/test.yml")},
225225
Conclusions: AllowedConclusions{"skipped"},
226226
},
227227
ExpectedPredicateResult: &common.PredicateResult{

0 commit comments

Comments
 (0)