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  }