func (uis *UIServer) taskPage(w http.ResponseWriter, r *http.Request) { projCtx := MustHaveProjectContext(r) if projCtx.Task == nil { http.Error(w, "Not found", http.StatusNotFound) return } if projCtx.Build == nil { uis.LoggedError(w, r, http.StatusInternalServerError, fmt.Errorf("build not found")) return } if projCtx.Version == nil { uis.LoggedError(w, r, http.StatusInternalServerError, fmt.Errorf("version not found")) return } if projCtx.ProjectRef == nil { evergreen.Logger.Logf(slogger.ERROR, "Project ref is nil") uis.LoggedError(w, r, http.StatusInternalServerError, fmt.Errorf("version not found")) return } executionStr := mux.Vars(r)["execution"] archived := false if executionStr != "" { // otherwise we can look in either tasks or old_tasks // where tasks are looked up in the old_tasks collection with key made up of // the original key and the execution number joined by an "_" // and the tasks are looked up in the tasks collection by key and execution // number, so that we avoid finding the wrong execution in the tasks // collection execution, err := strconv.Atoi(executionStr) if err != nil { http.Error(w, fmt.Sprintf("Bad execution number: %v", executionStr), http.StatusBadRequest) return } oldTaskId := fmt.Sprintf("%v_%v", projCtx.Task.Id, executionStr) taskFromDb, err := task.FindOneOld(task.ById(oldTaskId)) if err != nil { uis.LoggedError(w, r, http.StatusInternalServerError, err) return } archived = true if taskFromDb == nil { if execution != projCtx.Task.Execution { uis.LoggedError(w, r, http.StatusInternalServerError, fmt.Errorf("Error finding old task: %v", err)) return } archived = false } else { projCtx.Task = taskFromDb } } // Build a struct containing the subset of task data needed for display in the UI tId := projCtx.Task.Id if archived { tId = projCtx.Task.OldTaskId } task := uiTaskData{ Id: tId, DisplayName: projCtx.Task.DisplayName, Revision: projCtx.Task.Revision, Status: projCtx.Task.Status, TaskEndDetails: projCtx.Task.Details, Distro: projCtx.Task.DistroId, BuildVariant: projCtx.Task.BuildVariant, BuildId: projCtx.Task.BuildId, Activated: projCtx.Task.Activated, Restarts: projCtx.Task.Restarts, Execution: projCtx.Task.Execution, Requester: projCtx.Task.Requester, StartTime: projCtx.Task.StartTime.UnixNano(), DispatchTime: projCtx.Task.DispatchTime.UnixNano(), FinishTime: projCtx.Task.FinishTime.UnixNano(), ExpectedDuration: projCtx.Task.ExpectedDuration, PushTime: projCtx.Task.PushTime, TimeTaken: projCtx.Task.TimeTaken, Priority: projCtx.Task.Priority, TestResults: projCtx.Task.TestResults, Aborted: projCtx.Task.Aborted, CurrentTime: time.Now().UnixNano(), BuildVariantDisplay: projCtx.Build.DisplayName, Message: projCtx.Version.Message, Project: projCtx.Version.Identifier, Author: projCtx.Version.Author, AuthorEmail: projCtx.Version.AuthorEmail, VersionId: projCtx.Version.Id, RepoOwner: projCtx.ProjectRef.Owner, Repo: projCtx.ProjectRef.Repo, Archived: archived, } deps, taskWaiting, err := getTaskDependencies(projCtx.Task) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } task.DependsOn = deps task.TaskWaiting = taskWaiting task.MinQueuePos, err = model.FindMinimumQueuePositionForTask(task.Id) if err != nil { uis.LoggedError(w, r, http.StatusInternalServerError, err) return } if task.MinQueuePos < 0 { task.MinQueuePos = 0 } var taskHost *host.Host if projCtx.Task.HostId != "" { task.HostDNS = projCtx.Task.HostId task.HostId = projCtx.Task.HostId var err error taskHost, err = host.FindOne(host.ById(projCtx.Task.HostId)) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } if taskHost != nil { task.HostDNS = taskHost.Host } } if projCtx.Patch != nil { taskOnBaseCommit, err := projCtx.Task.FindTaskOnBaseCommit() if err != nil { uis.LoggedError(w, r, http.StatusInternalServerError, err) return } taskPatch := &uiPatch{Patch: *projCtx.Patch} if taskOnBaseCommit != nil { taskPatch.BaseTaskId = taskOnBaseCommit.Id taskPatch.BaseTimeTaken = taskOnBaseCommit.TimeTaken } taskPatch.StatusDiffs = model.StatusDiffTasks(taskOnBaseCommit, projCtx.Task).Tests task.PatchInfo = taskPatch } flashes := PopFlashes(uis.CookieStore, r, w) pluginContext := projCtx.ToPluginContext(uis.Settings, GetUser(r)) pluginContent := getPluginDataAndHTML(uis, plugin.TaskPage, pluginContext) uis.WriteHTML(w, http.StatusOK, struct { ProjectData projectContext User *user.DBUser Flashes []interface{} Task uiTaskData Host *host.Host PluginContent pluginData }{projCtx, GetUser(r), flashes, task, taskHost, pluginContent}, "base", "task.html", "base_angular.html", "menu.html") }
// Returns a JSON response with the marshalled output of the task // specified in the request. func (restapi restAPI) getTaskInfo(w http.ResponseWriter, r *http.Request) { projCtx := MustHaveRESTContext(r) srcTask := projCtx.Task if srcTask == nil { restapi.WriteJSON(w, http.StatusNotFound, responseError{Message: "error finding task"}) return } destTask := &RestTask{} destTask.Id = srcTask.Id destTask.CreateTime = srcTask.CreateTime destTask.ScheduledTime = srcTask.ScheduledTime destTask.DispatchTime = srcTask.DispatchTime destTask.StartTime = srcTask.StartTime destTask.FinishTime = srcTask.FinishTime destTask.PushTime = srcTask.PushTime destTask.Version = srcTask.Version destTask.Project = srcTask.Project destTask.Revision = srcTask.Revision destTask.Priority = srcTask.Priority destTask.LastHeartbeat = srcTask.LastHeartbeat destTask.Activated = srcTask.Activated destTask.BuildId = srcTask.BuildId destTask.DistroId = srcTask.DistroId destTask.BuildVariant = srcTask.BuildVariant destTask.DependsOn = srcTask.DependsOn destTask.DisplayName = srcTask.DisplayName destTask.HostId = srcTask.HostId destTask.Restarts = srcTask.Restarts destTask.Execution = srcTask.Execution destTask.Archived = srcTask.Archived destTask.RevisionOrderNumber = srcTask.RevisionOrderNumber destTask.Requester = srcTask.Requester destTask.Status = srcTask.Status destTask.Aborted = srcTask.Aborted destTask.TimeTaken = srcTask.TimeTaken destTask.ExpectedDuration = srcTask.ExpectedDuration var err error destTask.MinQueuePos, err = model.FindMinimumQueuePositionForTask(destTask.Id) if err != nil { msg := fmt.Sprintf("Error calculating task queue position for '%v'", srcTask.Id) evergreen.Logger.Logf(slogger.ERROR, "%v: %v", msg, err) restapi.WriteJSON(w, http.StatusInternalServerError, responseError{Message: msg}) return } if destTask.MinQueuePos < 0 { destTask.MinQueuePos = 0 } // Copy over the status details destTask.StatusDetails.TimedOut = srcTask.Details.TimedOut destTask.StatusDetails.TimeoutStage = srcTask.Details.Description // Copy over the test results destTask.TestResults = make(taskTestResultsByName, len(srcTask.TestResults)) for _, _testResult := range srcTask.TestResults { numSecs := _testResult.EndTime - _testResult.StartTime testResult := taskTestResult{ Status: _testResult.Status, TimeTaken: time.Duration(numSecs * float64(time.Second)), Logs: taskTestLogURL{_testResult.URL}, } destTask.TestResults[_testResult.TestFile] = testResult } // Copy over artifacts and binaries entries, err := artifact.FindAll(artifact.ByTaskId(srcTask.Id)) if err != nil { msg := fmt.Sprintf("Error finding task '%v'", srcTask.Id) evergreen.Logger.Logf(slogger.ERROR, "%v: %v", msg, err) restapi.WriteJSON(w, http.StatusInternalServerError, responseError{Message: msg}) return } for _, entry := range entries { for _, _file := range entry.Files { file := taskFile{ Name: _file.Name, URL: _file.Link, } destTask.Files = append(destTask.Files, file) } } if projCtx.Patch != nil { destTask.PatchNumber = projCtx.Patch.PatchNumber destTask.PatchId = projCtx.Patch.Id.Hex() } restapi.WriteJSON(w, http.StatusOK, destTask) return }