func (uis *UIServer) rawDiffPage(w http.ResponseWriter, r *http.Request) { projCtx := MustHaveProjectContext(r) if projCtx.Patch == nil { http.Error(w, "patch not found", http.StatusNotFound) return } fullPatch, err := patch.FindOne(patch.ById(projCtx.Patch.Id)) if err != nil { http.Error(w, fmt.Sprintf("error loading patch: %v", err.Error), http.StatusInternalServerError) return } fullPatch.FetchPatchFiles() patchNum, err := strconv.Atoi(r.FormValue("patch_number")) if err != nil { http.Error(w, fmt.Sprintf("error getting patch number: %v", err.Error), http.StatusInternalServerError) return } if patchNum < 0 || patchNum >= len(fullPatch.Patches) { http.Error(w, "patch number out of range", http.StatusInternalServerError) return } diff := fullPatch.Patches[patchNum].PatchSet.Patch w.Header().Set("Content-Type", "text/plain") w.WriteHeader(http.StatusOK) w.Write([]byte(diff)) }
// 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 }
func (uis *UIServer) patchPage(w http.ResponseWriter, r *http.Request) { projCtx := MustHaveProjectContext(r) if projCtx.Patch == nil { http.Error(w, "not found", http.StatusNotFound) return } currentUser := MustHaveUser(r) var versionAsUI *uiVersion if projCtx.Version != nil { // Patch is already finalized versionAsUI = &uiVersion{ Version: *projCtx.Version, RepoOwner: projCtx.ProjectRef.Owner, Repo: projCtx.ProjectRef.Repo, } } // get the new patch document with the patched configuration var err error projCtx.Patch, err = patch.FindOne(patch.ById(projCtx.Patch.Id)) if err != nil { http.Error(w, fmt.Sprintf("error loading patch: %v", err), http.StatusInternalServerError) return } // Unmarshal the patch's project config so that it is always up to date with the configuration file in the project project := &model.Project{} if err := yaml.Unmarshal([]byte(projCtx.Patch.PatchedConfig), project); err != nil { uis.LoggedError(w, r, http.StatusInternalServerError, fmt.Errorf("Error unmarshaling project config: %v", err)) } projCtx.Project = project // retrieve tasks and variant mappings' names variantMappings := make(map[string]model.BuildVariant) for _, variant := range projCtx.Project.BuildVariants { variantMappings[variant.Name] = variant } tasksList := []interface{}{} for _, task := range projCtx.Project.Tasks { // add a task name to the list if it's patchable if !(task.Patchable != nil && *task.Patchable == false) { tasksList = append(tasksList, struct{ Name string }{task.Name}) } } uis.WriteHTML(w, http.StatusOK, struct { ProjectData projectContext User *user.DBUser Version *uiVersion Variants map[string]model.BuildVariant Tasks []interface{} CanEdit bool }{projCtx, currentUser, versionAsUI, variantMappings, tasksList, uis.canEditPatch(currentUser, projCtx.Patch)}, "base", "patch_version.html", "base_angular.html", "menu.html") }
func CancelPatch(p *patch.Patch, caller string) error { if p.Version != "" { if err := SetVersionActivation(p.Version, false, caller); err != nil { return err } return AbortVersion(p.Version) } else { return patch.Remove(patch.ById(p.Id)) } }
func (uis *UIServer) diffPage(w http.ResponseWriter, r *http.Request) { projCtx := MustHaveProjectContext(r) if projCtx.Patch == nil { http.Error(w, "patch not found", http.StatusNotFound) return } // We have to reload the patch outside of the project context, // since the raw diff is excluded by default. This redundancy is // worth the time savings this behavior offers other pages. fullPatch, err := patch.FindOne(patch.ById(projCtx.Patch.Id)) if err != nil { http.Error(w, fmt.Sprintf("error loading patch: %v", err.Error), http.StatusInternalServerError) return } uis.WriteHTML(w, http.StatusOK, fullPatch, "base", "diff.html") }
func (uis *UIServer) fileDiffPage(w http.ResponseWriter, r *http.Request) { projCtx := MustHaveProjectContext(r) if projCtx.Patch == nil { http.Error(w, "patch not found", http.StatusNotFound) return } fullPatch, err := patch.FindOne(patch.ById(projCtx.Patch.Id)) if err != nil { http.Error(w, fmt.Sprintf("error loading patch: %v", err.Error), http.StatusInternalServerError) return } uis.WriteHTML(w, http.StatusOK, struct { Data patch.Patch FileName string PatchNumber string }{*fullPatch, r.FormValue("file_name"), r.FormValue("patch_number")}, "base", "file_diff.html") }
// Get the patch with the specified request it func getPatchFromRequest(r *http.Request) (*patch.Patch, error) { // get id and secret from the request. vars := mux.Vars(r) patchIdStr := vars["patchId"] if len(patchIdStr) == 0 { return nil, fmt.Errorf("no patch id supplied") } if !patch.IsValidId(patchIdStr) { return nil, fmt.Errorf("patch id '%v' is not valid object id", patchIdStr) } // find the patch existingPatch, err := patch.FindOne(patch.ById(patch.NewId(patchIdStr))) if err != nil { return nil, err } if existingPatch == nil { return nil, fmt.Errorf("no existing request with id: %v", patchIdStr) } return existingPatch, nil }
// 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 (uis *UIServer) schedulePatch(w http.ResponseWriter, r *http.Request) { projCtx := MustHaveProjectContext(r) if projCtx.Patch == nil { http.Error(w, "patch not found", http.StatusNotFound) return } // grab patch again, as the diff was excluded var err error projCtx.Patch, err = patch.FindOne(patch.ById(projCtx.Patch.Id)) if err != nil { http.Error(w, fmt.Sprintf("error loading patch: %v", err), http.StatusInternalServerError) return } patchUpdateReq := struct { Variants []string `json:"variants"` Tasks []string `json:"tasks"` Description string `json:"description"` }{} err = util.ReadJSONInto(r.Body, &patchUpdateReq) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } if projCtx.Patch.Version != "" { // This patch has already been finalized, just add the new builds and tasks if projCtx.Version == nil { uis.LoggedError(w, r, http.StatusInternalServerError, fmt.Errorf("Couldn't find patch for id %v", projCtx.Patch.Version)) return } // First add new tasks to existing builds, if necessary if len(patchUpdateReq.Tasks) > 0 { err = model.AddNewTasksForPatch(projCtx.Patch, projCtx.Version, patchUpdateReq.Tasks) if err != nil { uis.LoggedError(w, r, http.StatusInternalServerError, fmt.Errorf("Error creating new tasks: `%v` for version `%v`", err, projCtx.Version.Id)) return } } if len(patchUpdateReq.Variants) > 0 { _, err := model.AddNewBuildsForPatch(projCtx.Patch, projCtx.Version, patchUpdateReq.Variants) if err != nil { uis.LoggedError(w, r, http.StatusInternalServerError, fmt.Errorf("Error creating new builds: `%v` for version `%v`", err, projCtx.Version.Id)) return } } PushFlash(uis.CookieStore, r, w, NewSuccessFlash("Builds and tasks successfully added to patch.")) uis.WriteJSON(w, http.StatusOK, struct { VersionId string `json:"version"` }{projCtx.Version.Id}) } else { err = projCtx.Patch.SetVariantsAndTasks(patchUpdateReq.Variants, patchUpdateReq.Tasks) if err != nil { uis.LoggedError(w, r, http.StatusInternalServerError, fmt.Errorf("Error setting patch variants and tasks: %v", err)) return } if err = projCtx.Patch.SetDescription(patchUpdateReq.Description); err != nil { uis.LoggedError(w, r, http.StatusInternalServerError, fmt.Errorf("Error setting description: %v", err)) return } // Unmarshal the project config and set it in the project context project := model.Project{} if err := yaml.Unmarshal([]byte(projCtx.Patch.PatchedConfig), &project); err != nil { uis.LoggedError(w, r, http.StatusInternalServerError, fmt.Errorf("Error unmarshaling project config: %v", err)) } projCtx.Project = &project ver, err := model.FinalizePatch(projCtx.Patch, &uis.Settings) if err != nil { uis.LoggedError(w, r, http.StatusInternalServerError, fmt.Errorf("Error finalizing patch: %v", err)) return } PushFlash(uis.CookieStore, r, w, NewSuccessFlash("Patch builds are scheduled.")) uis.WriteJSON(w, http.StatusOK, struct { VersionId string `json:"version"` }{ver.Id}) } }
func (uis *UIServer) schedulePatch(w http.ResponseWriter, r *http.Request) { projCtx := MustHaveProjectContext(r) if projCtx.Patch == nil { http.Error(w, "patch not found", http.StatusNotFound) return } curUser := GetUser(r) if !uis.canEditPatch(curUser, projCtx.Patch) { http.Error(w, "Not authorized to schedule patch", http.StatusUnauthorized) return } // grab patch again, as the diff was excluded var err error projCtx.Patch, err = patch.FindOne(patch.ById(projCtx.Patch.Id)) if err != nil { http.Error(w, fmt.Sprintf("error loading patch: %v", err), http.StatusInternalServerError) return } // Unmarshal the project config and set it in the project context project := &model.Project{} if err := yaml.Unmarshal([]byte(projCtx.Patch.PatchedConfig), project); err != nil { uis.LoggedError(w, r, http.StatusInternalServerError, fmt.Errorf("Error unmarshaling project config: %v", err)) } projCtx.Project = project patchUpdateReq := patchVariantsTasksRequest{} err = util.ReadJSONInto(r.Body, &patchUpdateReq) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } var pairs []model.TVPair if len(patchUpdateReq.VariantsTasks) > 0 { pairs = model.VariantTasksToTVPairs(patchUpdateReq.VariantsTasks) } else { for _, v := range patchUpdateReq.Variants { for _, t := range patchUpdateReq.Tasks { if project.FindTaskForVariant(t, v) != nil { pairs = append(pairs, model.TVPair{v, t}) } } } } pairs = model.IncludePatchDependencies(projCtx.Project, pairs) if err = model.ValidateTVPairs(projCtx.Project, pairs); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } // update the description for both reconfigured and new patches if err = projCtx.Patch.SetDescription(patchUpdateReq.Description); err != nil { uis.LoggedError(w, r, http.StatusInternalServerError, fmt.Errorf("Error setting description: %v", err)) return } // update the description for both reconfigured and new patches if err = projCtx.Patch.SetVariantsTasks(model.TVPairsToVariantTasks(pairs)); err != nil { uis.LoggedError(w, r, http.StatusInternalServerError, fmt.Errorf("Error setting description: %v", err)) return } if projCtx.Patch.Version != "" { projCtx.Patch.Activated = true // This patch has already been finalized, just add the new builds and tasks if projCtx.Version == nil { uis.LoggedError(w, r, http.StatusInternalServerError, fmt.Errorf("Couldn't find patch for id %v", projCtx.Patch.Version)) return } // First add new tasks to existing builds, if necessary err = model.AddNewTasksForPatch(projCtx.Patch, projCtx.Version, projCtx.Project, pairs) if err != nil { uis.LoggedError(w, r, http.StatusInternalServerError, fmt.Errorf("Error creating new tasks: `%v` for version `%v`", err, projCtx.Version.Id)) return } err := model.AddNewBuildsForPatch(projCtx.Patch, projCtx.Version, projCtx.Project, pairs) if err != nil { uis.LoggedError(w, r, http.StatusInternalServerError, fmt.Errorf("Error creating new builds: `%v` for version `%v`", err, projCtx.Version.Id)) return } PushFlash(uis.CookieStore, r, w, NewSuccessFlash("Builds and tasks successfully added to patch.")) uis.WriteJSON(w, http.StatusOK, struct { VersionId string `json:"version"` }{projCtx.Version.Id}) } else { projCtx.Patch.Activated = true err = projCtx.Patch.SetVariantsTasks(model.TVPairsToVariantTasks(pairs)) if err != nil { uis.LoggedError(w, r, http.StatusInternalServerError, fmt.Errorf("Error setting patch variants and tasks: %v", err)) return } ver, err := model.FinalizePatch(projCtx.Patch, &uis.Settings) if err != nil { uis.LoggedError(w, r, http.StatusInternalServerError, fmt.Errorf("Error finalizing patch: %v", err)) return } PushFlash(uis.CookieStore, r, w, NewSuccessFlash("Patch builds are scheduled.")) uis.WriteJSON(w, http.StatusOK, struct { VersionId string `json:"version"` }{ver.Id}) } }
func (uis *UIServer) schedulePatch(w http.ResponseWriter, r *http.Request) { projCtx := MustHaveProjectContext(r) if projCtx.Patch == nil { http.Error(w, "patch not found", http.StatusNotFound) return } // grab patch again, as the diff was excluded var err error projCtx.Patch, err = patch.FindOne(patch.ById(projCtx.Patch.Id)) if err != nil { http.Error(w, fmt.Sprintf("error loading patch: %v", err), http.StatusInternalServerError) return } // Unmarshal the project config and set it in the project context project := &model.Project{} if err := yaml.Unmarshal([]byte(projCtx.Patch.PatchedConfig), project); err != nil { uis.LoggedError(w, r, http.StatusInternalServerError, fmt.Errorf("Error unmarshaling project config: %v", err)) } projCtx.Project = project patchUpdateReq := struct { Variants []string `json:"variants"` Tasks []string `json:"tasks"` Description string `json:"description"` }{} err = util.ReadJSONInto(r.Body, &patchUpdateReq) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } // Add all dependencies to patchUpdateReq.Tasks and add their variants to patchUpdateReq.Variants // Construct a set of variants to include in patchUpdateReq.Variants updateReqVariants := make(map[string]bool) for _, variant := range patchUpdateReq.Variants { updateReqVariants[variant] = true } // Construct a set of tasks to include in patchUpdateReq.Tasks // Add all dependencies, and add their variants to updateReqVariants updateReqTasks := make(map[string]bool) for _, v := range patchUpdateReq.Variants { for _, t := range projCtx.Project.FindTasksForVariant(v) { for _, task := range patchUpdateReq.Tasks { if t == task { deps, variants, err := getDeps(task, v, projCtx.Project) if err != nil { if err == TaskNotPatchableError { continue } else { uis.LoggedError(w, r, http.StatusInternalServerError, fmt.Errorf("Error getting dependencies for task: %v", err)) return } } updateReqTasks[task] = true for _, dep := range deps { updateReqTasks[dep] = true } for _, variant := range variants { updateReqVariants[variant] = true } } } } } // Reset patchUpdateReq.Tasks and patchUpdateReq.Variants patchUpdateReq.Tasks = make([]string, 0, len(updateReqTasks)) for task := range updateReqTasks { patchUpdateReq.Tasks = append(patchUpdateReq.Tasks, task) } patchUpdateReq.Variants = make([]string, 0, len(updateReqVariants)) for variant := range updateReqVariants { patchUpdateReq.Variants = append(patchUpdateReq.Variants, variant) } if projCtx.Patch.Version != "" { // This patch has already been finalized, just add the new builds and tasks if projCtx.Version == nil { uis.LoggedError(w, r, http.StatusInternalServerError, fmt.Errorf("Couldn't find patch for id %v", projCtx.Patch.Version)) return } // First add new tasks to existing builds, if necessary if len(patchUpdateReq.Tasks) > 0 { err = model.AddNewTasksForPatch(projCtx.Patch, projCtx.Version, projCtx.Project, patchUpdateReq.Tasks) if err != nil { uis.LoggedError(w, r, http.StatusInternalServerError, fmt.Errorf("Error creating new tasks: `%v` for version `%v`", err, projCtx.Version.Id)) return } } if len(patchUpdateReq.Variants) > 0 { _, err := model.AddNewBuildsForPatch(projCtx.Patch, projCtx.Version, projCtx.Project, patchUpdateReq.Variants) if err != nil { uis.LoggedError(w, r, http.StatusInternalServerError, fmt.Errorf("Error creating new builds: `%v` for version `%v`", err, projCtx.Version.Id)) return } } PushFlash(uis.CookieStore, r, w, NewSuccessFlash("Builds and tasks successfully added to patch.")) uis.WriteJSON(w, http.StatusOK, struct { VersionId string `json:"version"` }{projCtx.Version.Id}) } else { err = projCtx.Patch.SetVariantsAndTasks(patchUpdateReq.Variants, patchUpdateReq.Tasks) if err != nil { uis.LoggedError(w, r, http.StatusInternalServerError, fmt.Errorf("Error setting patch variants and tasks: %v", err)) return } if err = projCtx.Patch.SetDescription(patchUpdateReq.Description); err != nil { uis.LoggedError(w, r, http.StatusInternalServerError, fmt.Errorf("Error setting description: %v", err)) return } ver, err := model.FinalizePatch(projCtx.Patch, &uis.Settings) if err != nil { uis.LoggedError(w, r, http.StatusInternalServerError, fmt.Errorf("Error finalizing patch: %v", err)) return } PushFlash(uis.CookieStore, r, w, NewSuccessFlash("Patch builds are scheduled.")) uis.WriteJSON(w, http.StatusOK, struct { VersionId string `json:"version"` }{ver.Id}) } }