github.com/billybanfield/evergreen@v0.0.0-20170525200750-eeee692790f7/plugin/builtin/attach/results_command.go (about) 1 package attach 2 3 import ( 4 "os" 5 "path/filepath" 6 7 "github.com/evergreen-ci/evergreen/model" 8 "github.com/evergreen-ci/evergreen/model/task" 9 "github.com/evergreen-ci/evergreen/plugin" 10 "github.com/evergreen-ci/evergreen/util" 11 "github.com/mitchellh/mapstructure" 12 "github.com/mongodb/grip/slogger" 13 "github.com/pkg/errors" 14 ) 15 16 // AttachResultsCommand is used to attach MCI test results in json 17 // format to the task page. 18 type AttachResultsCommand struct { 19 // FileLoc describes the relative path of the file to be sent. 20 // Note that this can also be described via expansions. 21 FileLoc string `mapstructure:"file_location" plugin:"expand"` 22 } 23 24 func (self *AttachResultsCommand) Name() string { 25 return AttachResultsCmd 26 } 27 28 func (self *AttachResultsCommand) Plugin() string { 29 return AttachPluginName 30 } 31 32 // ParseParams decodes the S3 push command parameters that are 33 // specified as part of an AttachPlugin command; this is required 34 // to satisfy the 'Command' interface 35 func (self *AttachResultsCommand) ParseParams(params map[string]interface{}) error { 36 if err := mapstructure.Decode(params, self); err != nil { 37 return errors.Wrapf(err, "error decoding '%v' params", self.Name()) 38 } 39 40 if err := self.validateAttachResultsParams(); err != nil { 41 return errors.Wrapf(err, "error validating '%v' params", self.Name()) 42 } 43 return nil 44 } 45 46 // validateAttachResultsParams is a helper function that ensures all 47 // the fields necessary for attaching a results are present 48 func (self *AttachResultsCommand) validateAttachResultsParams() (err error) { 49 if self.FileLoc == "" { 50 return errors.New("file_location cannot be blank") 51 } 52 return nil 53 } 54 55 func (self *AttachResultsCommand) expandAttachResultsParams( 56 taskConfig *model.TaskConfig) (err error) { 57 self.FileLoc, err = taskConfig.Expansions.ExpandString(self.FileLoc) 58 if err != nil { 59 return errors.Wrap(err, "error expanding file_location") 60 } 61 return nil 62 } 63 64 // Execute carries out the AttachResultsCommand command - this is required 65 // to satisfy the 'Command' interface 66 func (self *AttachResultsCommand) Execute(pluginLogger plugin.Logger, 67 pluginCom plugin.PluginCommunicator, 68 taskConfig *model.TaskConfig, 69 stop chan bool) error { 70 71 if err := self.expandAttachResultsParams(taskConfig); err != nil { 72 return errors.WithStack(err) 73 } 74 75 errChan := make(chan error) 76 go func() { 77 reportFileLoc := self.FileLoc 78 if !filepath.IsAbs(self.FileLoc) { 79 reportFileLoc = filepath.Join(taskConfig.WorkDir, self.FileLoc) 80 } 81 82 // attempt to open the file 83 reportFile, err := os.Open(reportFileLoc) 84 if err != nil { 85 errChan <- errors.Wrapf(err, "Couldn't open report file '%s'", reportFileLoc) 86 return 87 } 88 89 results := &task.TestResults{} 90 if err = util.ReadJSONInto(reportFile, results); err != nil { 91 errChan <- errors.Wrapf(err, "Couldn't read report file '%s'", reportFileLoc) 92 return 93 } 94 if err := reportFile.Close(); err != nil { 95 pluginLogger.LogExecution(slogger.INFO, "Error closing file: %v", err) 96 } 97 errChan <- errors.WithStack(SendJSONResults(taskConfig, pluginLogger, pluginCom, results)) 98 }() 99 100 select { 101 case err := <-errChan: 102 return errors.WithStack(err) 103 case <-stop: 104 pluginLogger.LogExecution(slogger.INFO, "Received signal to terminate"+ 105 " execution of attach results command") 106 return nil 107 } 108 } 109 110 // SendJSONResults is responsible for sending the 111 // specified file to the API Server 112 func SendJSONResults(taskConfig *model.TaskConfig, 113 pluginLogger plugin.Logger, pluginCom plugin.PluginCommunicator, 114 results *task.TestResults) error { 115 for i, res := range results.Results { 116 117 if res.LogRaw != "" { 118 pluginLogger.LogExecution(slogger.INFO, "Attaching raw test logs") 119 testLogs := &model.TestLog{ 120 Name: res.TestFile, 121 Task: taskConfig.Task.Id, 122 TaskExecution: taskConfig.Task.Execution, 123 Lines: []string{res.LogRaw}, 124 } 125 126 id, err := pluginCom.TaskPostTestLog(testLogs) 127 if err != nil { 128 pluginLogger.LogExecution(slogger.ERROR, "Error posting raw logs from results: %v", err) 129 } else { 130 results.Results[i].LogId = id 131 } 132 133 // clear the logs from the TestResult struct after it has been saved in the test logs. Since they are 134 // being saved in the test_logs collection, we can clear them to prevent them from being saved in the task 135 // collection. 136 results.Results[i].LogRaw = "" 137 138 } 139 } 140 141 pluginLogger.LogExecution(slogger.INFO, "Attaching test results") 142 err := pluginCom.TaskPostResults(results) 143 if err != nil { 144 return errors.WithStack(err) 145 } 146 147 pluginLogger.LogTask(slogger.INFO, "Attach test results succeeded") 148 return nil 149 }