// populatePatch loads a patch into the project context, using patchId if provided. // If patchId is blank, will try to infer the patch ID from the version already loaded // into context, if available. func (pc *projectContext) populatePatch(patchId string) error { var err error if len(patchId) > 0 { // The patch is explicitly identified in the URL, so fetch it if !patch.IsValidId(patchId) { return fmt.Errorf("patch id '%v' is not an object id", patchId) } pc.Patch, err = patch.FindOne(patch.ById(patch.NewId(patchId)).Project(patch.ExcludePatchDiff)) } else if pc.Version != nil { // patch isn't in URL but the version in context has one, get it pc.Patch, err = patch.FindOne(patch.ByVersion(pc.Version.Id).Project(patch.ExcludePatchDiff)) } if err != nil { return err } // If there's a finalized patch loaded into context but not a version, load the version // associated with the patch as the context's version. if pc.Version == nil && pc.Patch != nil && pc.Patch.Version != "" { pc.Version, err = version.FindOne(version.ById(pc.Patch.Version)) if err != nil { return err } } return nil }
// servePatch is the API hook for returning patch data as json func servePatch(w http.ResponseWriter, r *http.Request) { task := plugin.GetTask(r) patch, err := patch.FindOne(patch.ByVersion(task.Version)) if err != nil { msg := fmt.Sprintf("error fetching patch for task %v from db: %v", task.Id, err) evergreen.Logger.Logf(slogger.ERROR, msg) http.Error(w, msg, http.StatusInternalServerError) return } if patch == nil { msg := fmt.Sprintf("no patch found for task %v", task.Id) evergreen.Logger.Errorf(slogger.ERROR, msg) http.Error(w, msg, http.StatusNotFound) return } plugin.WriteJSON(w, http.StatusOK, patch) }
// construct the change information // struct from a given version struct func constructChangeInfo(v *version.Version, notification *NotificationKey) (changeInfo *ChangeInfo) { changeInfo = &ChangeInfo{} switch notification.NotificationRequester { case evergreen.RepotrackerVersionRequester: changeInfo.Project = v.Identifier changeInfo.Author = v.Author changeInfo.Message = v.Message changeInfo.Revision = v.Revision changeInfo.Email = v.AuthorEmail case evergreen.PatchVersionRequester: // get the author and description from the patch request patch, err := patch.FindOne(patch.ByVersion(v.Id)) if err != nil { evergreen.Logger.Errorf(slogger.ERROR, "Error finding patch for version %v: %v", v.Id, err) return } if patch == nil { evergreen.Logger.Errorf(slogger.ERROR, "%v notification was unable to locate patch with version: %v", notification, v.Id) return } // get the display name and email for this user dbUser, err := user.FindOne(user.ById(patch.Author)) if err != nil { evergreen.Logger.Errorf(slogger.ERROR, "Error finding user %v: %v", patch.Author, err) changeInfo.Author = patch.Author changeInfo.Email = patch.Author } else if dbUser == nil { evergreen.Logger.Errorf(slogger.ERROR, "User %v not found", patch.Author) changeInfo.Author = patch.Author changeInfo.Email = patch.Author } else { changeInfo.Email = dbUser.Email() changeInfo.Author = dbUser.DisplayName() } changeInfo.Project = patch.Project changeInfo.Message = patch.Description changeInfo.Revision = patch.Id.Hex() } return }
// loadAlertContext fetches details from the database for all documents that are associated with the // AlertRequest. For example, it populates the task/build/version/project using the // task/build/version/project ids in the alert request document. func (qp *QueueProcessor) loadAlertContext(a *alert.AlertRequest) (*AlertContext, error) { aCtx := &AlertContext{AlertRequest: a} aCtx.Settings = qp.config taskId, projectId, buildId, versionId := a.TaskId, a.ProjectId, a.BuildId, a.VersionId patchId := a.PatchId var err error if len(a.HostId) > 0 { aCtx.Host, err = host.FindOne(host.ById(a.HostId)) if err != nil { return nil, err } } // Fetch task if there's a task ID present; if we find one, populate build/version IDs from it if len(taskId) > 0 { aCtx.Task, err = model.FindTask(taskId) if err != nil { return nil, err } if aCtx.Task != nil && aCtx.Task.Execution != a.Execution { oldTaskId := fmt.Sprintf("%s_%v", taskId, a.Execution) aCtx.Task, err = model.FindOneOldTask(bson.M{"_id": oldTaskId}, db.NoProjection, db.NoSort) if err != nil { return nil, err } } if aCtx.Task != nil { // override build and version ID with the ones this task belongs to buildId = aCtx.Task.BuildId versionId = aCtx.Task.Version projectId = aCtx.Task.Project aCtx.FailedTests = []model.TestResult{} for _, test := range aCtx.Task.TestResults { if test.Status == "fail" { aCtx.FailedTests = append(aCtx.FailedTests, test) } } } } // Fetch build if there's a build ID present; if we find one, populate version ID from it if len(buildId) > 0 { aCtx.Build, err = build.FindOne(build.ById(buildId)) if err != nil { return nil, err } if aCtx.Build != nil { versionId = aCtx.Build.Version projectId = aCtx.Build.Project } } if len(versionId) > 0 { aCtx.Version, err = version.FindOne(version.ById(versionId)) if err != nil { return nil, err } if aCtx.Version != nil { projectId = aCtx.Version.Identifier } } if len(patchId) > 0 { if !patch.IsValidId(patchId) { return nil, fmt.Errorf("patch id '%v' is not an object id", patchId) } aCtx.Patch, err = patch.FindOne(patch.ById(patch.NewId(patchId)).Project(patch.ExcludePatchDiff)) } else if aCtx.Version != nil { // patch isn't in URL but the version in context has one, get it aCtx.Patch, err = patch.FindOne(patch.ByVersion(aCtx.Version.Id).Project(patch.ExcludePatchDiff)) } // If there's a finalized patch loaded into context but not a version, load the version // associated with the patch as the context's version. if aCtx.Version == nil && aCtx.Patch != nil && aCtx.Patch.Version != "" { aCtx.Version, err = version.FindOne(version.ById(aCtx.Patch.Version).WithoutFields(version.ConfigKey)) if err != nil { return nil, err } } if len(projectId) > 0 { aCtx.ProjectRef, err = qp.findProject(projectId) if err != nil { return nil, err } } return aCtx, nil }
func (task *Task) FetchPatch() (*patch.Patch, error) { // find the patch associated with this version return patch.FindOne(patch.ByVersion(task.Version)) }
func (uis *UIServer) allTaskQueues(w http.ResponseWriter, r *http.Request) { projCtx := MustHaveProjectContext(r) taskQueues, err := model.FindAllTaskQueues() if err != nil { uis.LoggedError(w, r, http.StatusInternalServerError, fmt.Errorf("Error finding task queues: %v", err)) return } // cached map of version id to relevant patch cachedPatches := map[string]*patch.Patch{} // convert the task queues to the ui versions uiTaskQueues := []uiTaskQueue{} for _, tQ := range taskQueues { asUI := uiTaskQueue{ Distro: tQ.Distro, Queue: []uiTaskQueueItem{}, } if len(tQ.Queue) == 0 { uiTaskQueues = append(uiTaskQueues, asUI) continue } // convert the individual task queue items taskIds := []string{} for _, item := range tQ.Queue { // cache the ids, for fetching the tasks from the db taskIds = append(taskIds, item.Id) queueItemAsUI := uiTaskQueueItem{ Id: item.Id, DisplayName: item.DisplayName, BuildVariant: item.BuildVariant, RevisionOrderNumber: item.RevisionOrderNumber, Requester: item.Requester, Revision: item.Revision, Project: item.Project, } asUI.Queue = append(asUI.Queue, queueItemAsUI) } // find all the relevant tasks tasks, err := task.Find(task.ByIds(taskIds).WithFields(task.VersionKey, task.BuildIdKey)) if err != nil { msg := fmt.Sprintf("Error finding tasks: %v", err) evergreen.Logger.Errorf(slogger.ERROR, msg) http.Error(w, msg, http.StatusInternalServerError) return } // store all of the version and build ids in the relevant task queue // items for _, task := range tasks { // this sucks, but it's because we're not guaranteed the order out // of the db for idx, queueItemAsUI := range asUI.Queue { if queueItemAsUI.Id == task.Id { queueItemAsUI.Version = task.Version queueItemAsUI.Build = task.BuildId asUI.Queue[idx] = queueItemAsUI } } } // add all of the necessary patch info into the relevant task queue // items for idx, queueItemAsUI := range asUI.Queue { if queueItemAsUI.Requester == evergreen.PatchVersionRequester { // fetch the patch, if necessary var p *patch.Patch var ok bool if p, ok = cachedPatches[queueItemAsUI.Version]; ok { queueItemAsUI.User = p.Author asUI.Queue[idx] = queueItemAsUI } else { p, err = patch.FindOne( patch.ByVersion(queueItemAsUI.Version).WithFields(patch.AuthorKey), ) if err != nil { msg := fmt.Sprintf("Error finding patch: %v", err) evergreen.Logger.Errorf(slogger.ERROR, msg) http.Error(w, msg, http.StatusInternalServerError) return } if p == nil { msg := fmt.Sprintf("Couldn't find patch for version %v", queueItemAsUI.Version) evergreen.Logger.Errorf(slogger.ERROR, msg) http.Error(w, msg, http.StatusInternalServerError) return } cachedPatches[queueItemAsUI.Version] = p } queueItemAsUI.User = p.Author asUI.Queue[idx] = queueItemAsUI } } uiTaskQueues = append(uiTaskQueues, asUI) } // add other useful statistics to view alongside queue idleHosts, err := host.Find(host.IsIdle) if err != nil { msg := fmt.Sprintf("Error finding idle hosts: %v", err) evergreen.Logger.Errorf(slogger.ERROR, msg) http.Error(w, msg, http.StatusInternalServerError) return } activeHosts, err := host.Find(host.IsLive) if err != nil { msg := fmt.Sprintf("Error finding active hosts: %v", err) evergreen.Logger.Errorf(slogger.ERROR, msg) http.Error(w, msg, http.StatusInternalServerError) return } idleStaticHostsCount := 0 for _, host := range idleHosts { if host.Provider == evergreen.HostTypeStatic { idleStaticHostsCount++ } } activeStaticHostsCount := 0 for _, host := range activeHosts { if host.Provider == evergreen.HostTypeStatic { activeStaticHostsCount++ } } hostStats := uiHostStatistics{ ActiveHosts: len(activeHosts), ActiveStaticHosts: activeStaticHostsCount, IdleHosts: len(idleHosts), IdleStaticHosts: idleStaticHostsCount, } uis.WriteHTML(w, http.StatusOK, struct { ProjectData projectContext User *user.DBUser Flashes []interface{} Data uiResourceInfo }{projCtx, GetUser(r), []interface{}{}, uiResourceInfo{uiTaskQueues, hostStats}}, "base", "task_queues.html", "base_angular.html", "menu.html") }