github.com/billybanfield/evergreen@v0.0.0-20170525200750-eeee692790f7/notify/build_handler.go (about) 1 package notify 2 3 import ( 4 "fmt" 5 "time" 6 7 "github.com/evergreen-ci/evergreen/model/build" 8 "github.com/evergreen-ci/evergreen/model/version" 9 "github.com/evergreen-ci/evergreen/web" 10 "github.com/mongodb/grip" 11 "github.com/pkg/errors" 12 ) 13 14 // "Base class" for all build_*_handler.go structs. Contains code that's common 15 // to all the build_*_handlers. Note that this struct does NOT implement 16 // NotificationHandler 17 type BuildNotificationHandler struct { 18 Type string 19 } 20 21 type BuildNotificationForTemplate struct { 22 Notification *TriggeredBuildNotification 23 FailedTasks []build.TaskCache 24 Subject string 25 } 26 27 // convenience wrapper about everything we want to know about a build 28 // notification before it goes off for templating. 29 type TriggeredBuildNotification struct { 30 Current *build.Build 31 Previous *build.Build 32 Info []ChangeInfo 33 Key NotificationKey 34 Preface string 35 Transition string 36 } 37 38 func (self *BuildNotificationHandler) getRecentlyFinishedBuildsWithStatus(key *NotificationKey, 39 status string, preface string, transition string) ([]TriggeredBuildNotification, error) { 40 buildNotifications := []TriggeredBuildNotification{} 41 builds, err := getRecentlyFinishedBuilds(key) 42 if err != nil { 43 return nil, err 44 } 45 46 for _, currentBuild := range builds { 47 // Copy by value to make pointer safe 48 curr := currentBuild 49 if status == "" || curr.Status == status { 50 grip.Debugf("Adding '%s' on %s %s notification", curr.Id, key.Project, 51 key.NotificationName) 52 53 // get the build's project to add to the notification subject line 54 branchName := UnknownProjectBranch 55 if projectRef, err := getProjectRef(curr.Project); err != nil { 56 grip.Warningf("Unable to find project ref for build '%s': %+v", 57 curr.Id, err) 58 } else if projectRef != nil { 59 branchName = projectRef.Branch 60 } 61 62 notification := TriggeredBuildNotification{ 63 Current: &curr, 64 Previous: nil, 65 Key: *key, 66 Preface: fmt.Sprintf(preface, branchName), 67 Transition: transition, 68 } 69 buildNotifications = append(buildNotifications, notification) 70 } 71 } 72 return buildNotifications, nil 73 } 74 75 func (self *BuildNotificationHandler) templateNotification(ae *web.App, 76 notification *TriggeredBuildNotification, changeInfo []ChangeInfo) (email Email, err error) { 77 current := notification.Current 78 79 // add change information to notification 80 notification.Info = changeInfo 81 82 // get the failed tasks (if any) 83 failedTasks := getFailedTasks(current, notification.Key.NotificationName) 84 85 subject := fmt.Sprintf("%v Build #%v %v on %v", notification.Preface, 86 current.BuildNumber, notification.Transition, current.DisplayName) 87 88 buildNotification := BuildNotificationForTemplate{notification, failedTasks, subject} 89 90 body, err := TemplateEmailBody(ae, "build_notification.html", buildNotification) 91 if err != nil { 92 return 93 } 94 95 // for notifications requiring comparisons 96 // include what it was compared against here 97 if notification.Previous != nil { 98 previous := notification.Previous 99 body += fmt.Sprintf(`(compared with this <a href="%v/build/%v">previous build</a>)`, 100 ae.TemplateFuncs["Global"].(func(string) interface{})("UIRoot"), // FIXME 101 previous.Id) 102 } 103 104 email = &BuildEmail{EmailBase{body, subject, notification.Info}, *notification} 105 return 106 } 107 108 func (self *BuildNotificationHandler) constructChangeInfo(allBuilds []build.Build, 109 key *NotificationKey) ([]ChangeInfo, error) { 110 changeInfoSlice := make([]ChangeInfo, 0) 111 112 for _, build := range allBuilds { 113 // add blamelist information for each build 114 v, err := version.FindOne(version.ById(build.Version)) 115 if err != nil { 116 return changeInfoSlice, err 117 } 118 119 if v == nil { 120 return changeInfoSlice, errors.Errorf( 121 "No version found for build %s with version id %s", 122 build.Id, build.Version) 123 } 124 changeInfo := constructChangeInfo(v, key) 125 changeInfo.Pushtime = build.PushTime.Format(time.RFC850) 126 changeInfoSlice = append(changeInfoSlice, *changeInfo) 127 } 128 return changeInfoSlice, nil 129 }