-
Notifications
You must be signed in to change notification settings - Fork 124
/
status_diff.go
147 lines (127 loc) · 4.44 KB
/
status_diff.go
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
package model
import (
"path"
"strings"
"github.com/evergreen-ci/evergreen"
"github.com/evergreen-ci/evergreen/apimodels"
"github.com/evergreen-ci/evergreen/db"
"github.com/evergreen-ci/evergreen/model/build"
"github.com/evergreen-ci/evergreen/model/task"
"github.com/evergreen-ci/evergreen/model/testresult"
"github.com/pkg/errors"
)
// StatusDiff stores a pairing of status strings
// for easy visualization/aggregation later.
type StatusDiff struct {
Original string `json:"original"`
Patch string `json:"patch"`
}
// StatusDetailsDiff stores a pairing of status details
// for easy visualization/aggregation later.
type StatusDetailsDiff struct {
Original apimodels.TaskEndDetail `json:"original"`
Patch apimodels.TaskEndDetail `json:"patch"`
}
// BuildStatusDiff stores a diff of two build statuses.
type BuildStatusDiff struct {
Name string `json:"name"`
Diff StatusDiff `json:"diff"`
Tasks []TaskStatusDiff `json:"tasks"`
}
// TaskStatusDiff stores a diff of two task statuses.
type TaskStatusDiff struct {
Name string `json:"name"`
Diff StatusDetailsDiff `json:"diff"`
Tests []TestStatusDiff `json:"tests"`
Original string `json:"original"`
Patch string `json:"patch"`
BuildVariant string `json:"build_variant"`
}
// TestStatusDiff stores a diff of two test results.
type TestStatusDiff struct {
Name string `json:"name"`
Diff StatusDiff `json:"diff"`
Original string `json:"original"`
Patch string `json:"patch"`
}
var (
TestLogPath = "/test_log/"
)
// StatusDiffBuilds takes two builds and returns a diff of their results
// for easy comparison and analysis.
func StatusDiffBuilds(original, patch *build.Build) (BuildStatusDiff, error) {
// return an empty diff if one of builds is nonexistant
// this is likely to occur after adding a new buildvariant or task
if original == nil || patch == nil {
return BuildStatusDiff{}, nil
}
diff := BuildStatusDiff{
Name: original.DisplayName,
Diff: StatusDiff{original.Status, patch.Status},
}
query := db.Query(task.ByBuildIds([]string{original.Id, patch.Id})).WithFields(task.BuildIdKey, task.StatusKey, task.DetailsKey, task.DisplayNameKey)
tasks, err := task.FindAll(query)
if err != nil {
return BuildStatusDiff{}, errors.Wrap(err, "finding tasks")
}
// build maps of tasks, for matching
originalTaskMap := make(map[string]task.Task)
patchTaskMap := make(map[string]task.Task)
for _, t := range tasks {
if t.BuildId == patch.Id {
patchTaskMap[t.Id] = t
} else {
originalTaskMap[t.DisplayName] = t
}
}
// iterate through all patch tasks and create diffs
// NOTE: this implicitly skips all tasks not present in the patch
for _, task := range patch.Tasks {
patchTask, ok := patchTaskMap[task.Id]
if !ok {
return BuildStatusDiff{}, errors.Errorf("patch task '%s' doesn't exist", task.Id)
}
baseTask := originalTaskMap[patchTask.DisplayName]
newDiff := TaskStatusDiff{
Name: patchTask.DisplayName,
Diff: StatusDetailsDiff{Original: baseTask.Details, Patch: patchTask.Details},
Original: baseTask.Id,
Patch: patchTask.Id,
BuildVariant: diff.Name,
}
// handle if the status details do not contain a status, such as in display tasks
if newDiff.Diff.Original.Status == "" {
newDiff.Diff.Original.Status = baseTask.Status
}
if newDiff.Diff.Patch.Status == "" {
newDiff.Diff.Patch.Status = patchTask.Status
}
diff.Tasks = append(diff.Tasks, newDiff)
}
return diff, nil
}
// StatusDiffTests takes two sets of tests and returns a diff of their results
// for easy comparison and analysis.
func StatusDiffTests(original, patch []testresult.TestResult) []TestStatusDiff {
env := evergreen.GetEnvironment()
diff := []TestStatusDiff{}
if len(original) == 0 || len(patch) == 0 {
return diff
}
originalMap := make(map[string]testresult.TestResult)
for _, test := range original {
originalMap[test.GetDisplayTestName()] = test
}
for _, test := range patch {
baseTest := originalMap[test.GetDisplayTestName()]
// Get the base name for windows/non-windows paths.
testName := path.Base(strings.Replace(test.GetDisplayTestName(), "\\", "/", -1))
diff = append(diff, TestStatusDiff{
Name: testName,
Diff: StatusDiff{baseTest.Status, test.Status},
Original: baseTest.GetLogURL(env, evergreen.LogViewerHTML),
Patch: test.GetLogURL(env, evergreen.LogViewerHTML),
})
}
return diff
}