github.com/billybanfield/evergreen@v0.0.0-20170525200750-eeee692790f7/model/version_history.go (about)

     1  package model
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/evergreen-ci/evergreen"
     7  	"github.com/evergreen-ci/evergreen/db"
     8  	"github.com/evergreen-ci/evergreen/model/build"
     9  	"github.com/evergreen-ci/evergreen/model/version"
    10  	"github.com/pkg/errors"
    11  	"gopkg.in/mgo.v2/bson"
    12  )
    13  
    14  // Maximum number of versions to consider for last_green, more than 100
    15  // revisions back considered "stale"
    16  const (
    17  	StaleVersionCutoff = 100
    18  )
    19  
    20  // Given a project name and a list of build variants, return the latest version
    21  // on which all the given build variants succeeded. Gives up after 100 versions.
    22  func FindLastPassingVersionForBuildVariants(project *Project, buildVariantNames []string) (*version.Version, error) {
    23  	if len(buildVariantNames) == 0 {
    24  		return nil, errors.New("No build variants specified!")
    25  	}
    26  
    27  	// Get latest commit order number for this project
    28  	latestVersion, err := version.FindOne(db.Query(
    29  		version.ByMostRecentForRequester(project.Identifier, evergreen.RepotrackerVersionRequester).
    30  			WithFields(version.RevisionOrderNumberKey)))
    31  	if err != nil {
    32  		return nil, errors.Wrap(err, "Error getting latest version")
    33  	}
    34  	if latestVersion == nil {
    35  		return nil, nil
    36  	}
    37  
    38  	mostRecentRevisionOrderNumber := latestVersion.RevisionOrderNumber
    39  
    40  	// Earliest commit order number to consider
    41  	leastRecentRevisionOrderNumber := mostRecentRevisionOrderNumber - StaleVersionCutoff
    42  	if leastRecentRevisionOrderNumber < 0 {
    43  		leastRecentRevisionOrderNumber = 0
    44  	}
    45  
    46  	pipeline := []bson.M{
    47  		// Limit ourselves to builds for non-stale versions and the given project
    48  		// and build variants
    49  		{
    50  			"$match": bson.M{
    51  				build.ProjectKey:             project.Identifier,
    52  				build.RevisionOrderNumberKey: bson.M{"$gte": leastRecentRevisionOrderNumber},
    53  				build.BuildVariantKey:        bson.M{"$in": buildVariantNames},
    54  				build.StatusKey:              evergreen.BuildSucceeded,
    55  			},
    56  		},
    57  		// Sum up the number of builds that succeeded for each commit order number
    58  		{
    59  			"$group": bson.M{
    60  				"_id": fmt.Sprintf("$%v", build.RevisionOrderNumberKey),
    61  				"numSucceeded": bson.M{
    62  					"$sum": 1,
    63  				},
    64  			},
    65  		},
    66  		// Find builds that succeeded on all of the requested build variants
    67  		{
    68  			"$match": bson.M{"numSucceeded": len(buildVariantNames)},
    69  		},
    70  		// Order by commit order number, descending
    71  		{
    72  			"$sort": bson.M{"_id": -1},
    73  		},
    74  		// Get the highest commit order number where builds succeeded on all the
    75  		// requested build variants
    76  		{
    77  			"$limit": 1,
    78  		},
    79  	}
    80  
    81  	var result []bson.M
    82  
    83  	err = db.Aggregate(build.Collection, pipeline, &result)
    84  	if err != nil {
    85  		return nil, errors.Wrap(err, "Aggregation failed")
    86  	}
    87  
    88  	if len(result) == 0 {
    89  		return nil, nil
    90  	}
    91  
    92  	// Get the version corresponding to the resulting commit order number
    93  	v, err := version.FindOne(
    94  		db.Query(bson.M{
    95  			version.RequesterKey:           evergreen.RepotrackerVersionRequester,
    96  			version.IdentifierKey:          project.Identifier,
    97  			version.RevisionOrderNumberKey: result[0]["_id"],
    98  		}))
    99  	if err != nil {
   100  		return nil, err
   101  	}
   102  	if v == nil {
   103  		return nil, errors.Errorf("Couldn't find version with id `%v` after "+
   104  			"successful aggregation.", result[0]["_id"])
   105  	}
   106  	return v, nil
   107  }