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 }