-
Notifications
You must be signed in to change notification settings - Fork 24
Expand file tree
/
Copy pathtestselect.go
More file actions
160 lines (139 loc) · 3.95 KB
/
testselect.go
File metadata and controls
160 lines (139 loc) · 3.95 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
package testselect
import (
"bytes"
"context"
"encoding/json"
"flag"
"log"
"os"
"regexp"
"sort"
"strings"
"github.com/openshift-knative/hack/pkg/prowgen"
"gopkg.in/yaml.v3"
"sigs.k8s.io/prow/pkg/clonerefs"
)
const (
all = "All"
)
// TestSuites holds mapping between file path regular expressions and
// test suites that cover the paths.
type TestSuites struct {
List []TestSuite `yaml:"testsuites"`
}
type TestSuite struct {
Name string `yaml:"name"`
RunIfChanged []string `yaml:"run_if_changed"`
// Tests are arbitrary strings. It is up to the caller to check the strings and decide whether
// some code should be run. For example, they can match specific Bash function names or Make targets.
Tests []string `yaml:"tests"`
}
func Main() {
ctx := context.Background()
ts := flag.String("testsuites", "testsuites.yaml", "Specify yaml file with path-to-testsuite mapping")
// Clonerefs options as defined in https://github.com/kubernetes/test-infra/blob/master/prow/clonerefs/options.go
refs := flag.String("clonerefs", "clonerefs.json", "Specify json file with clonerefs")
outFile := flag.String("output", "tests.txt", "Specify name of output file")
flag.Parse()
log.Println(*ts, *refs, *outFile)
inRefs, err := os.ReadFile(*refs)
if err != nil {
log.Fatalln(err)
}
cloneRefs := new(clonerefs.Options)
if err := json.Unmarshal(inRefs, cloneRefs); err != nil {
log.Fatalln("Unmarshal clone refs options", err)
}
inTs, err := os.ReadFile(*ts)
if err != nil {
log.Fatalln(err)
}
testSuites := new(TestSuites)
dec := yaml.NewDecoder(bytes.NewReader(inTs))
dec.KnownFields(true)
if err := dec.Decode(testSuites); err != nil {
log.Fatalln("Unmarshal test suite mappings", err)
}
var tests, paths []string
if len(cloneRefs.GitRefs) == 0 || len(cloneRefs.GitRefs[0].Pulls) == 0 {
log.Println(`Clone refs do not include required SHAs. Returning "All".`)
tests = []string{all}
} else {
repo := prowgen.Repository{
Org: cloneRefs.GitRefs[0].Org,
Repo: cloneRefs.GitRefs[0].Repo,
}
paths, err = Diff(ctx, repo, cloneRefs.GitRefs[0].BaseSHA, cloneRefs.GitRefs[0].Pulls[0].SHA)
if err != nil {
log.Fatalln("Error reading diff", err)
}
tests, err = filterTests(*testSuites, paths)
if err != nil {
log.Fatal(err)
}
}
var sb strings.Builder
for _, tst := range tests {
sb.WriteString(tst + "\n")
}
if err := os.WriteFile(*outFile, []byte(sb.String()), os.ModePerm); err != nil {
log.Fatal(err)
}
}
func Diff(ctx context.Context, repo prowgen.Repository, baseSha, sha string) ([]string, error) {
if err := prowgen.GitClone(ctx, repo); err != nil {
return nil, err
}
if err := prowgen.GitCheckout(ctx, repo, baseSha); err != nil {
return nil, err
}
if err := prowgen.GitFetch(ctx, repo, sha); err != nil {
return nil, err
}
if err := prowgen.GitMerge(ctx, repo, sha); err != nil {
return nil, err
}
return prowgen.GitDiffNameOnly(ctx, repo, baseSha)
}
func filterTests(testSuites TestSuites, paths []string) ([]string, error) {
testsToRun := make(map[string]bool)
for _, path := range paths {
matchAny := false
for _, suite := range testSuites.List {
for _, pathRegex := range suite.RunIfChanged {
matched, err := regexp.MatchString(pathRegex, path)
if err != nil {
return nil, err
}
if matched {
matchAny = true
for _, test := range suite.Tests {
testsToRun[test] = true
}
}
}
}
// If the path doesn't match any path expressions then it is unknown
// path and all test suites should be run.
if !matchAny {
testsToRun[all] = true
}
}
// Add tests that should always run.
for _, suite := range testSuites.List {
if len(suite.RunIfChanged) == 0 {
for _, test := range suite.Tests {
testsToRun[test] = true
}
}
}
return sortedKeys(testsToRun), nil
}
func sortedKeys(stringMap map[string]bool) []string {
keys := make([]string, 0, len(stringMap))
for k := range stringMap {
keys = append(keys, k)
}
sort.Strings(keys)
return keys
}