func getTaskHistory(t *task.Task, w http.ResponseWriter, r *http.Request) { var t2 *task.Task = t var err error if t.Requester == evergreen.PatchVersionRequester { t2, err = t.FindTaskOnBaseCommit() if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } t.RevisionOrderNumber = t2.RevisionOrderNumber } before := []TaskJSON{} jsonQuery := db.Query(bson.M{ ProjectIdKey: t.Project, VariantKey: t.BuildVariant, RevisionOrderNumberKey: bson.M{"$lte": t.RevisionOrderNumber}, TaskNameKey: t.DisplayName, IsPatchKey: false, NameKey: mux.Vars(r)["name"]}) jsonQuery = jsonQuery.Sort([]string{"-order"}).Limit(100) err = db.FindAllQ(collection, jsonQuery, &before) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } //reverse order of "before" because we had to sort it backwards to apply the limit correctly: for i, j := 0, len(before)-1; i < j; i, j = i+1, j-1 { before[i], before[j] = before[j], before[i] } after := []TaskJSON{} jsonAfterQuery := db.Query(bson.M{ ProjectIdKey: t.Project, VariantKey: t.BuildVariant, RevisionOrderNumberKey: bson.M{"$gt": t.RevisionOrderNumber}, TaskNameKey: t.DisplayName, IsPatchKey: false, NameKey: mux.Vars(r)["name"]}).Sort([]string{"order"}).Limit(100) err = db.FindAllQ(collection, jsonAfterQuery, &after) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } //concatenate before + after before = append(before, after...) // if our task was a patch, replace the base commit's info in the history with the patch if t.Requester == evergreen.PatchVersionRequester { before, err = fixPatchInHistory(t.Id, t2, before) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } } plugin.WriteJSON(w, http.StatusOK, before) }
// ByProjectId finds all non-patch versions within a project. func ByProjectId(projectId string) db.Q { return db.Query( bson.M{ ProjectKey: projectId, RequesterKey: evergreen.RepotrackerVersionRequester, }) }
// ByUserWithRunningStatus produces a query that returns all // running hosts for the given user id. func ByUserWithRunningStatus(user string) db.Q { return db.Query( bson.M{ StartedByKey: user, StatusKey: bson.M{"$ne": evergreen.HostTerminated}, }) }
func fixPatchInHistory(taskId string, base *task.Task, history []TaskJSON) ([]TaskJSON, error) { var jsonForTask *TaskJSON err := db.FindOneQ(collection, db.Query(bson.M{"task_id": taskId}), &jsonForTask) if err != nil { return nil, err } if base != nil { jsonForTask.RevisionOrderNumber = base.RevisionOrderNumber } if jsonForTask == nil { return history, nil } found := false for i, item := range history { if item.Revision == base.Revision { history[i] = *jsonForTask found = true } } // if found is false, it means we don't have json on the base commit, so it was // not replaced and we must add it explicitly if !found { history = append(history, *jsonForTask) } return history, nil }
// getTasksForLatestVersion sends back the TaskJSON data associated with the latest version. func getTasksForLatestVersion(w http.ResponseWriter, r *http.Request) { name := mux.Vars(r)["name"] var jsonTask TaskJSON projects := []string{} err := util.ReadJSONInto(r.Body, &projects) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } versionData := []VersionData{} for _, project := range projects { err := db.FindOneQ(collection, db.Query(bson.M{NameKey: name, ProjectIdKey: project}).Sort([]string{"-" + RevisionOrderNumberKey}).WithFields(VersionIdKey), &jsonTask) if err != nil { if err != mgo.ErrNotFound { http.Error(w, err.Error(), http.StatusInternalServerError) return } http.Error(w, "{}", http.StatusNotFound) return } if jsonTask.VersionId == "" { http.Error(w, "{}", http.StatusNotFound) } jsonTasks, err := findTasksForVersion(jsonTask.VersionId, name) if jsonTasks == nil { http.Error(w, "{}", http.StatusNotFound) return } if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } // get the version commit info v, err := version.FindOne(version.ById(jsonTask.VersionId)) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } if v == nil { http.Error(w, "{}", http.StatusNotFound) return } commitInfo := CommitInfo{ Author: v.Author, Message: v.Message, CreateTime: v.CreateTime, Revision: v.Revision, VersionId: jsonTask.VersionId, } versionData = append(versionData, VersionData{jsonTasks, commitInfo}) } plugin.WriteJSON(w, http.StatusOK, versionData) }
// getTask finds a json document by using thex task that is in the plugin. func getTaskByName(w http.ResponseWriter, r *http.Request) { t := plugin.GetTask(r) if t == nil { http.Error(w, "task not found", http.StatusNotFound) return } name := mux.Vars(r)["name"] taskName := mux.Vars(r)["task_name"] var jsonForTask TaskJSON err := db.FindOneQ(collection, db.Query(bson.M{VersionIdKey: t.Version, BuildIdKey: t.BuildId, NameKey: name, TaskNameKey: taskName}), &jsonForTask) if err != nil { if err == mgo.ErrNotFound { plugin.WriteJSON(w, http.StatusNotFound, nil) return } http.Error(w, err.Error(), http.StatusInternalServerError) return } if len(r.FormValue("full")) != 0 { // if specified, include the json data's container as well plugin.WriteJSON(w, http.StatusOK, jsonForTask) return } plugin.WriteJSON(w, http.StatusOK, jsonForTask.Data) }
// ByRevisionAndVariant creates a query that returns the non-patch build for // a revision + buildvariant combionation. func ByRevisionAndVariant(revision, variant string) db.Q { return db.Query(bson.M{ RevisionKey: revision, RequesterKey: evergreen.RepotrackerVersionRequester, BuildVariantKey: variant, }) }
func ByFirstFailureInTaskType(versionId, taskName string) db.Q { return db.Query(bson.M{ TypeKey: FirstTaskTypeFailureId, VersionIdKey: versionId, TaskNameKey: taskName, }).Limit(1) }
// ByUserProjectAndGitspec produces a query that returns patches by the given // patch author, project, and gitspec. func ByUserProjectAndGitspec(user string, project string, gitspec string) db.Q { return db.Query(bson.M{ AuthorKey: user, ProjectKey: project, GithashKey: gitspec, }) }
func ByFirstFailureInVariant(versionId, variant string) db.Q { return db.Query(bson.M{ TypeKey: FirstVariantFailureId, VersionIdKey: versionId, VariantKey: variant, }).Limit(1) }
func ByRecentlyFinished(finishTime time.Time, project string, requester string) db.Q { query := bson.M{} andClause := []bson.M{} // filter by finish_time timeOpt := bson.M{ FinishTimeKey: bson.M{ "$gt": finishTime, }, } // filter by requester requesterOpt := bson.M{ RequesterKey: requester, } // build query andClause = append(andClause, bson.M{ "$or": FinishedOpts, }) andClause = append(andClause, timeOpt) andClause = append(andClause, requesterOpt) // filter by project if project != "" { projectOpt := bson.M{ ProjectKey: project, } andClause = append(andClause, projectOpt) } query["$and"] = andClause return db.Query(query) }
func ByLastRevNotFound(projectId, versionId string) db.Q { return db.Query(bson.M{ TypeKey: LastRevisionNotFound, ProjectIdKey: projectId, VersionIdKey: versionId, }).Limit(1) }
func ByIds(userIds ...string) db.Q { return db.Query(bson.M{ IdKey: bson.M{ "$in": userIds, }, }) }
// Helper to make the appropriate query to the versions collection for what // we will need. "before" indicates whether to fetch versions before or // after the passed-in task. func makeVersionsQuery(anchorOrderNum int, projectId string, versionsToFetch int, before bool) ([]version.Version, error) { // decide how the versions we want relative to the task's revision order number ronQuery := bson.M{"$gt": anchorOrderNum} if before { ronQuery = bson.M{"$lt": anchorOrderNum} } // switch how to sort the versions sortVersions := []string{version.RevisionOrderNumberKey} if before { sortVersions = []string{"-" + version.RevisionOrderNumberKey} } // fetch the versions return version.Find( db.Query(bson.M{ version.IdentifierKey: projectId, version.RevisionOrderNumberKey: ronQuery, }).WithFields( version.RevisionOrderNumberKey, version.RevisionKey, version.MessageKey, version.CreateTimeKey, ).Sort(sortVersions).Limit(versionsToFetch)) }
func (iter *taskHistoryIterator) findAllVersions(v *version.Version, numRevisions int, before, include bool) ([]version.Version, bool, error) { versionQuery := bson.M{ version.RequesterKey: evergreen.RepotrackerVersionRequester, version.IdentifierKey: iter.ProjectName, } // If including the specified version in the result, then should // get an additional revision if include { numRevisions++ } // Determine the comparator to use based on whether the revisions // come before/after the specified version compare, order := "$gt", version.RevisionOrderNumberKey if before { compare, order = "$lt", fmt.Sprintf("-%v", version.RevisionOrderNumberKey) if include { compare = "$lte" } } else if include { compare = "$gte" } if v != nil { versionQuery[version.RevisionOrderNumberKey] = bson.M{compare: v.RevisionOrderNumber} } // Get the next numRevisions, plus an additional one to check if have // reached the beginning/end of history versions, err := version.Find( db.Query(versionQuery).WithFields( version.IdKey, version.RevisionOrderNumberKey, version.RevisionKey, version.MessageKey, version.CreateTimeKey, ).Sort([]string{order}).Limit(numRevisions + 1)) // Check if there were fewer results returned by the query than what // the limit was set as exhausted := len(versions) <= numRevisions if !exhausted { // Exclude the last version because we actually only wanted // `numRevisions` number of commits versions = versions[:len(versions)-1] } // The iterator can only be exhausted if an actual version was specified exhausted = exhausted || (v == nil && numRevisions == 0) if !before { // Reverse the order so that the most recent version is first for i, j := 0, len(versions)-1; i < j; i, j = i+1, j-1 { versions[i], versions[j] = versions[j], versions[i] } } return versions, exhausted, err }
// ByDistroId produces a query that returns all working hosts (not terminated and // not quarantined) of the given distro. func ByDistroId(distroId string) db.Q { dId := fmt.Sprintf("%v.%v", DistroKey, distro.IdKey) return db.Query(bson.M{ dId: distroId, StartedByKey: evergreen.User, StatusKey: bson.M{"$in": evergreen.UphostStatus}, }) }
// ByProjectIdAndRevision finds non-patch versions for the given project and revision. func ByProjectIdAndRevision(projectId, revision string) db.Q { return db.Query( bson.M{ ProjectKey: projectId, RevisionKey: revision, RequesterKey: evergreen.RepotrackerVersionRequester, }) }
// ByProjectId finds all versions within a project, ordered by most recently created to oldest. // The requester controls if it should search patch or non-patch versions. func ByMostRecentForRequester(projectId, requester string) db.Q { return db.Query( bson.M{ RequesterKey: requester, ProjectKey: projectId, }, ).Sort([]string{"-" + RevisionOrderNumberKey}) }
// ByHungSince produces a query that returns all working hosts that // started their tasks before the given time. func ByHungSince(threshold time.Time) db.Q { return db.Query(bson.M{ RunningTaskKey: bson.M{"$ne": ""}, TaskDispatchTimeKey: bson.M{"$lte": threshold}, StatusKey: bson.M{"$ne": evergreen.HostTerminated}, StartedByKey: evergreen.User, }) }
// ByUnprovisionedSince produces a query that returns all hosts // Evergreen never finished setting up that were created before // the given time. func ByUnprovisionedSince(threshold time.Time) db.Q { return db.Query(bson.M{ ProvisionedKey: false, CreateTimeKey: bson.M{"$lte": threshold}, StatusKey: bson.M{"$ne": evergreen.HostTerminated}, StartedByKey: evergreen.User, }) }
// ByStatusAndActivation creates a query that returns tasks of a certain status and activation state. func ByStatusAndActivation(status string, active bool) db.Q { return db.Query(bson.M{ ActivatedKey: active, StatusKey: status, //Filter out blacklisted tasks PriorityKey: bson.M{"$gte": 0}, }) }
// ByPreviousFailureTransition finds the last alert record that was stored for a task/variant // within a given project. // This can be used to determine whether or not a newly detected failure transition should trigger // an alert. If an alert was already sent for a failed task, which transitioned from a succsesfulwhose commit order number is func ByLastFailureTransition(taskName, variant, projectId string) db.Q { return db.Query(bson.M{ TypeKey: TaskFailTransitionId, TaskNameKey: taskName, VariantKey: variant, ProjectIdKey: projectId, }).Sort([]string{"-" + RevisionOrderNumberKey}).Limit(1) }
// ByProjectIdAndOrder finds non-patch versions for the given project with revision // order numbers less than or equal to revisionOrderNumber. func ByProjectIdAndOrder(projectId string, revisionOrderNumber int) db.Q { return db.Query( bson.M{ ProjectKey: projectId, RevisionOrderNumberKey: bson.M{"$lte": revisionOrderNumber}, RequesterKey: evergreen.RepotrackerVersionRequester, }) }
// ByAfterRevision builds a query that returns all builds // that happened at or after the given revision for the project/variant. // Results are sorted by revision order, ascending. func ByAfterRevision(project, buildVariant string, revision int) db.Q { return db.Query(bson.M{ ProjectKey: project, BuildVariantKey: buildVariant, RequesterKey: evergreen.RepotrackerVersionRequester, RevisionOrderNumberKey: bson.M{"$gte": revision}, }).Sort([]string{RevisionOrderNumberKey}) }
// ByProjectAndVariant creates a query that finds all completed builds for a given project // and variant, while also specifying a requester func ByProjectAndVariant(project, variant, requester string) db.Q { return db.Query(bson.M{ ProjectKey: project, StatusKey: bson.M{"$in": evergreen.CompletedStatuses}, BuildVariantKey: variant, RequesterKey: requester, }) }
// ByExpiredSicne produces a query that returns any user-spawned hosts // that will expired after the given time. func ByExpiredSince(time time.Time) db.Q { return db.Query(bson.M{ StartedByKey: bson.M{"$ne": evergreen.User}, StatusKey: bson.M{ "$nin": []string{evergreen.HostTerminated, evergreen.HostQuarantined}, }, ExpirationTimeKey: bson.M{"$lte": time}, }) }
// ByExpiringBetween produces a query that returns any user-spawned hosts // that will expire between the specified times. func ByExpiringBetween(lowerBound time.Time, upperBound time.Time) db.Q { return db.Query(bson.M{ StartedByKey: bson.M{"$ne": evergreen.User}, StatusKey: bson.M{ "$nin": []string{evergreen.HostTerminated, evergreen.HostQuarantined}, }, ExpirationTimeKey: bson.M{"$gte": lowerBound, "$lte": upperBound}, }) }
// ByUnproductiveSince produces a query that returns all hosts that // are not doign work and were created before the given time. func ByUnproductiveSince(threshold time.Time) db.Q { return db.Query(bson.M{ "$or": noRunningTask, LTCKey: "", CreateTimeKey: bson.M{"$lte": threshold}, StatusKey: bson.M{"$ne": evergreen.HostTerminated}, StartedByKey: evergreen.User, }) }
func ByOrderNumbersForNameAndVariant(revisionOrder []int, displayName, buildVariant string) db.Q { return db.Query(bson.M{ RevisionOrderNumberKey: bson.M{ "$in": revisionOrder, }, DisplayNameKey: displayName, BuildVariantKey: buildVariant, }) }
// ByCommit creates a query on Evergreen as the requester on a revision, buildVariant, displayName and project. func ByCommit(revision, buildVariant, displayName, project, requester string) db.Q { return db.Query(bson.M{ RevisionKey: revision, RequesterKey: requester, BuildVariantKey: buildVariant, DisplayNameKey: displayName, ProjectKey: project, }) }