github.com/justinjmoses/evergreen@v0.0.0-20170530173719-1d50e381ff0d/notify/build_success_to_failure_handler.go (about)

     1  package notify
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/evergreen-ci/evergreen"
     7  	"github.com/evergreen-ci/evergreen/model/build"
     8  	"github.com/evergreen-ci/evergreen/web"
     9  	"github.com/mongodb/grip"
    10  )
    11  
    12  // Handler for notifications generated specifically when a build fails and the
    13  // previous finished build succeeded. Implements NotificationHandler from
    14  // notification_handler.go.
    15  type BuildSuccessToFailureHandler struct {
    16  	BuildNotificationHandler
    17  	Name string
    18  }
    19  
    20  func (self *BuildSuccessToFailureHandler) GetNotifications(ae *web.App, key *NotificationKey) ([]Email, error) {
    21  	var emails []Email
    22  	builds, err := getRecentlyFinishedBuilds(key)
    23  	if err != nil {
    24  		return nil, err
    25  	}
    26  
    27  	preface := mciFailurePreface
    28  	if key.NotificationRequester == evergreen.PatchVersionRequester {
    29  		preface = patchFailurePreface
    30  	}
    31  
    32  	for _, currentBuild := range builds {
    33  		// Copy by value to make pointer safe
    34  		curr := currentBuild
    35  		previousBuild, err := currentBuild.PreviousActivated(key.Project,
    36  			evergreen.RepotrackerVersionRequester)
    37  		if previousBuild == nil {
    38  			grip.Debugf("No previous completed build found for '%v' on %v %v notification",
    39  				currentBuild.Id, key.Project, key.NotificationName)
    40  			continue
    41  		} else if err != nil {
    42  			return nil, err
    43  		}
    44  
    45  		if !previousBuild.IsFinished() {
    46  			grip.Debugf("Build before '%s' (on %s %s notification) isn't finished",
    47  				currentBuild.Id, key.Project, key.NotificationName)
    48  			continue
    49  		}
    50  
    51  		// get the build's project to add to the notification subject line
    52  		branchName := UnknownProjectBranch
    53  		if projectRef, err := getProjectRef(currentBuild.Project); err != nil {
    54  			grip.Warningf("Unable to find project ref for build '%s': %+v",
    55  				currentBuild.Id, err)
    56  		} else if projectRef != nil {
    57  			branchName = projectRef.Branch
    58  		}
    59  
    60  		grip.Debugf("Previous completed build found for '%s on %s %s notification is %s",
    61  			currentBuild.Id, key.Project, key.NotificationName, previousBuild.Id)
    62  
    63  		if previousBuild.Status == evergreen.BuildSucceeded &&
    64  			currentBuild.Status == evergreen.BuildFailed {
    65  			notification := TriggeredBuildNotification{
    66  				Current:    &curr,
    67  				Previous:   previousBuild,
    68  				Key:        *key,
    69  				Preface:    fmt.Sprintf(preface, branchName),
    70  				Transition: transitionSubject,
    71  			}
    72  			email, err := self.TemplateNotification(ae, &notification)
    73  			if err != nil {
    74  				grip.Noticef("template error for build success to failure notification with '%s': %s",
    75  					currentBuild.Id, err.Error())
    76  				continue
    77  			}
    78  			emails = append(emails, email)
    79  		}
    80  	}
    81  
    82  	return emails, nil
    83  }
    84  
    85  func (self *BuildSuccessToFailureHandler) TemplateNotification(ae *web.App, notification *TriggeredBuildNotification) (Email, error) {
    86  	changeInfo, err := self.GetChangeInfo(notification)
    87  	if err != nil {
    88  		return nil, err
    89  	}
    90  	return self.templateNotification(ae, notification, changeInfo)
    91  }
    92  
    93  func (self *BuildSuccessToFailureHandler) GetChangeInfo(
    94  	notification *TriggeredBuildNotification) ([]ChangeInfo, error) {
    95  	current := notification.Current
    96  	previous := current
    97  	if notification.Previous != nil {
    98  		previous = notification.Previous
    99  	}
   100  
   101  	intermediateBuilds, err := current.FindIntermediateBuilds(previous)
   102  	if err != nil {
   103  		return nil, err
   104  	}
   105  	allBuilds := make([]build.Build, len(intermediateBuilds)+1)
   106  
   107  	// include the current/previous build
   108  	allBuilds[len(allBuilds)-1] = *current
   109  
   110  	// copy any intermediate build(s)
   111  	if len(intermediateBuilds) != 0 {
   112  		copy(allBuilds[0:len(allBuilds)-1], intermediateBuilds)
   113  	}
   114  	return self.constructChangeInfo(allBuilds, &notification.Key)
   115  }