github.com/billybanfield/evergreen@v0.0.0-20170525200750-eeee692790f7/model/status_diff.go (about) 1 package model 2 3 import ( 4 "path" 5 "strings" 6 7 "github.com/evergreen-ci/evergreen/apimodels" 8 "github.com/evergreen-ci/evergreen/model/build" 9 "github.com/evergreen-ci/evergreen/model/task" 10 ) 11 12 // StatusDiff stores a pairing of status strings 13 // for easy visualization/aggregation later. 14 type StatusDiff struct { 15 Original string `json:"original"` 16 Patch string `json:"patch"` 17 } 18 19 // StatusDetailsDiff stores a pairing of status details 20 // for easy visualization/aggregation later. 21 type StatusDetailsDiff struct { 22 Original apimodels.TaskEndDetail `json:"original"` 23 Patch apimodels.TaskEndDetail `json:"patch"` 24 } 25 26 // BuildStatusDiff stores a diff of two build statuses. 27 type BuildStatusDiff struct { 28 Name string `json:"name"` 29 Diff StatusDiff `json:"diff"` 30 Tasks []TaskStatusDiff `json:"tasks"` 31 } 32 33 // TaskStatusDiff stores a diff of two task statuses. 34 type TaskStatusDiff struct { 35 Name string `json:"name"` 36 Diff StatusDetailsDiff `json:"diff"` 37 Tests []TestStatusDiff `json:"tests"` 38 Original string `json:"original"` 39 Patch string `json:"patch"` 40 BuildVariant string `json:"build_variant"` 41 } 42 43 // TestStatusDiff stores a diff of two test results. 44 type TestStatusDiff struct { 45 Name string `json:"name"` 46 Diff StatusDiff `json:"diff"` 47 Original string `json:"original"` 48 Patch string `json:"patch"` 49 } 50 51 var ( 52 TestLogPath = "/test_log/" 53 ) 54 55 // StatusDiffBuilds takes two builds and returns a diff of their results 56 // for easy comparison and analysis. 57 func StatusDiffBuilds(original, patch *build.Build) BuildStatusDiff { 58 // return an empty diff if one of builds is nonexistant 59 // this is likely to occur after adding a new buildvariant or task 60 if original == nil || patch == nil { 61 return BuildStatusDiff{} 62 } 63 64 diff := BuildStatusDiff{ 65 Name: original.DisplayName, 66 Diff: StatusDiff{original.Status, patch.Status}, 67 } 68 69 // build maps of task statuses, for matching 70 originalTasks := make(map[string]build.TaskCache) 71 for _, task := range original.Tasks { 72 originalTasks[task.DisplayName] = task 73 } 74 75 // iterate through all patch tasks and create diffs 76 // NOTE: this implicitly skips all tasks not present in the patch 77 for _, task := range patch.Tasks { 78 baseTask := originalTasks[task.DisplayName] 79 diff.Tasks = append(diff.Tasks, 80 TaskStatusDiff{ 81 Name: task.DisplayName, 82 Diff: StatusDetailsDiff{baseTask.StatusDetails, task.StatusDetails}, 83 Original: baseTask.Id, 84 Patch: task.Id, 85 BuildVariant: diff.Name, 86 }) 87 } 88 return diff 89 } 90 91 // getTestUrl returns the correct relative URL to a test log, given a 92 // TestResult structure 93 func getTestUrl(tr *task.TestResult) string { 94 // Return url if it exists. If there is no test, return empty string. 95 if tr.URL != "" || tr.LogId == "" { // If LogId is empty, URL must also be empty 96 return tr.URL 97 } 98 return TestLogPath + tr.LogId 99 } 100 101 // StatusDiffTasks takes two tasks and returns a diff of their results 102 // for easy comparison and analysis. 103 func StatusDiffTasks(original *task.Task, patch *task.Task) TaskStatusDiff { 104 // return an empty diff if one of tasks is nonexistant 105 // this is likely to occur after adding a new buildvariant or task 106 if original == nil || patch == nil { 107 return TaskStatusDiff{} 108 } 109 110 diff := TaskStatusDiff{ 111 Name: original.DisplayName, 112 Original: original.Id, 113 Patch: patch.Id, 114 Diff: StatusDetailsDiff{original.Details, patch.Details}, 115 } 116 117 if original.TestResults == nil || patch.TestResults == nil { 118 return diff 119 } 120 121 // build maps of test statuses, for matching 122 originalTests := make(map[string]task.TestResult) 123 for _, test := range original.TestResults { 124 originalTests[test.TestFile] = test 125 } 126 127 // iterate through all patch tests and create diffs 128 for _, test := range patch.TestResults { 129 baseTest := originalTests[test.TestFile] 130 131 // get the base name for windows/non-windows paths 132 testFile := path.Base(strings.Replace(test.TestFile, "\\", "/", -1)) 133 diff.Tests = append(diff.Tests, 134 TestStatusDiff{ 135 Name: testFile, 136 Diff: StatusDiff{baseTest.Status, test.Status}, 137 Original: getTestUrl(&baseTest), 138 Patch: getTestUrl(&test), 139 }) 140 } 141 return diff 142 }