Beispiel #1
0
// 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)
}
Beispiel #2
0
// IncKeyHandler increments the value stored in the given key, and returns it
func IncKeyHandler(w http.ResponseWriter, r *http.Request) {
	key := ""
	err := util.ReadJSONInto(r.Body, &key)
	if err != nil {
		evergreen.Logger.Logf(slogger.ERROR, "Error geting key: %v", err)
		plugin.WriteJSON(w, http.StatusInternalServerError, err.Error())
		return
	}

	change := mgo.Change{
		Update: bson.M{
			"$inc": bson.M{"value": 1},
		},
		ReturnNew: true,
		Upsert:    true,
	}

	keyVal := &KeyVal{}
	_, err = db.FindAndModify(KeyValCollection, bson.M{"_id": key}, nil, change, keyVal)
	if err != nil {
		evergreen.Logger.Logf(slogger.ERROR, "error doing findAndModify: %v", err)
		plugin.WriteJSON(w, http.StatusInternalServerError, err.Error())
		return
	}

	plugin.WriteJSON(w, http.StatusOK, keyVal)
}
// getNote retrieves the latest note from the database.
func (bbp *BuildBaronPlugin) getNote(w http.ResponseWriter, r *http.Request) {
	taskId := mux.Vars(r)["task_id"]
	n, err := NoteForTask(taskId)
	if err != nil {
		plugin.WriteJSON(w, http.StatusInternalServerError, err.Error())
		return
	}
	if n == nil {
		plugin.WriteJSON(w, http.StatusOK, "")
		return
	}
	plugin.WriteJSON(w, http.StatusOK, n)
}
Beispiel #4
0
// insertTask creates a TaskJSON document with the data sent in the request body.
func insertTask(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"]
	rawData := map[string]interface{}{}
	err := util.ReadJSONInto(r.Body, &rawData)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	jsonBlob := TaskJSON{
		TaskId:              t.Id,
		TaskName:            t.DisplayName,
		Name:                name,
		BuildId:             t.BuildId,
		Variant:             t.BuildVariant,
		ProjectId:           t.Project,
		VersionId:           t.Version,
		CreateTime:          t.CreateTime,
		Revision:            t.Revision,
		RevisionOrderNumber: t.RevisionOrderNumber,
		Data:                rawData,
		IsPatch:             t.Requester == evergreen.PatchVersionRequester,
	}
	_, err = db.Upsert(collection, bson.M{TaskIdKey: t.Id, NameKey: name}, jsonBlob)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	plugin.WriteJSON(w, http.StatusOK, "ok")
	return
}
Beispiel #5
0
// AttachFilesHandler updates file mappings for a task or build
func AttachFilesHandler(w http.ResponseWriter, r *http.Request) {
	task := plugin.GetTask(r)
	evergreen.Logger.Logf(slogger.INFO, "Attaching files to task %v", task.Id)

	fileEntry := &artifact.Entry{}
	fileEntry.TaskId = task.Id
	fileEntry.TaskDisplayName = task.DisplayName
	fileEntry.BuildId = task.BuildId

	err := util.ReadJSONInto(r.Body, &fileEntry.Files)
	if err != nil {
		message := fmt.Sprintf("error reading file definitions: %v", err)
		evergreen.Logger.Errorf(slogger.ERROR, message)
		http.Error(w, message, http.StatusBadRequest)
		return
	}

	if err := fileEntry.Upsert(); err != nil {
		message := fmt.Sprintf("Error updating artifact file info: %v", err)
		evergreen.Logger.Errorf(slogger.ERROR, message)
		http.Error(w, message, http.StatusInternalServerError)
		return
	}

	plugin.WriteJSON(w, http.StatusOK, fmt.Sprintf("Artifact files for task %v successfully attached", task.Id))
}
Beispiel #6
0
// 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)
}
//XXX remove this once the transition is complete...
//AttachResultsHandler is an API hook for receiving and updating test results
func AttachResultsHandler(w http.ResponseWriter, r *http.Request) {
	task := plugin.GetTask(r)
	if task == nil {
		message := "Cannot find task for attach results request"
		evergreen.Logger.Errorf(slogger.ERROR, message)
		http.Error(w, message, http.StatusBadRequest)
		return
	}
	results := &model.TestResults{}
	err := util.ReadJSONInto(r.Body, results)
	if err != nil {
		message := fmt.Sprintf("error reading test results: %v", err)
		evergreen.Logger.Errorf(slogger.ERROR, message)
		http.Error(w, message, http.StatusBadRequest)
		return
	}
	// set test result of task
	if err := task.SetResults(results.Results); err != nil {
		message := fmt.Sprintf("Error calling set results on task %v: %v", task.Id, err)
		evergreen.Logger.Errorf(slogger.ERROR, message)
		http.Error(w, message, http.StatusInternalServerError)
		return
	}
	plugin.WriteJSON(w, http.StatusOK, "Test results successfully attached")
}
Beispiel #8
0
func (m *ManifestPlugin) GetManifest(w http.ResponseWriter, r *http.Request) {
	project := mux.Vars(r)["project_id"]
	revision := mux.Vars(r)["revision"]

	version, err := version.FindOne(version.ByProjectIdAndRevision(project, revision))
	if err != nil {
		http.Error(w, fmt.Sprintf("error getting version for project %v with revision %v: %v",
			project, revision, err), http.StatusBadRequest)
		return
	}
	if version == nil {
		http.Error(w, fmt.Sprintf("version not found for project %v, with revision %v", project, revision),
			http.StatusNotFound)
		return
	}

	foundManifest, err := manifest.FindOne(manifest.ById(version.Id))
	if err != nil {
		http.Error(w, fmt.Sprintf("error getting manifest with version id %v: %v",
			version.Id, err), http.StatusBadRequest)
		return
	}
	if foundManifest == nil {
		http.Error(w, fmt.Sprintf("manifest not found for version %v", version.Id), http.StatusNotFound)
		return
	}
	plugin.WriteJSON(w, http.StatusOK, foundManifest)
	return

}
Beispiel #9
0
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)
}
Beispiel #10
0
// getTaskForVariant finds a task by name and variant and finds
// the document in the json collection associated with that task's id.
func getTaskForVariant(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"]
	variantId := mux.Vars(r)["variant"]
	// Find the task for the other variant, if it exists
	ts, err := task.Find(db.Query(bson.M{task.VersionKey: t.Version, task.BuildVariantKey: variantId,
		task.DisplayNameKey: taskName}).Limit(1))
	if err != nil {
		if err == mgo.ErrNotFound {
			plugin.WriteJSON(w, http.StatusNotFound, nil)
			return
		}
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	if len(ts) == 0 {
		plugin.WriteJSON(w, http.StatusNotFound, nil)
		return
	}
	otherVariantTask := ts[0]

	var jsonForTask TaskJSON
	err = db.FindOneQ(collection, db.Query(bson.M{TaskIdKey: otherVariantTask.Id, NameKey: name}), &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)
}
Beispiel #11
0
// handleTaskTags will update the TaskJSON's tags depending on the request.
func handleTaskTag(w http.ResponseWriter, r *http.Request) {
	t, err := task.FindOne(task.ById(mux.Vars(r)["task_id"]))
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	if t == nil {
		http.Error(w, "{}", http.StatusNotFound)
		return
	}
	if r.Method == "DELETE" {
		if _, err = db.UpdateAll(collection,
			bson.M{VersionIdKey: t.Version, NameKey: mux.Vars(r)["name"]},
			bson.M{"$unset": bson.M{TagKey: 1}}); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		plugin.WriteJSON(w, http.StatusOK, "")
	}
	inTag := struct {
		Tag string `json:"tag"`
	}{}
	err = util.ReadJSONInto(r.Body, &inTag)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	if len(inTag.Tag) == 0 {
		http.Error(w, "tag must not be blank", http.StatusBadRequest)
		return
	}

	_, err = db.UpdateAll(collection,
		bson.M{VersionIdKey: t.Version, NameKey: mux.Vars(r)["name"]},
		bson.M{"$set": bson.M{TagKey: inTag.Tag}})

	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	plugin.WriteJSON(w, http.StatusOK, "")
}
Beispiel #12
0
// FetchVarsHandler is an API hook for returning the project variables
// associated with a task's project.
func FetchVarsHandler(w http.ResponseWriter, r *http.Request) {
	task := plugin.GetTask(r)
	if task == nil {
		http.Error(w, "task not found", http.StatusNotFound)
		return
	}
	projectVars, err := model.FindOneProjectVars(task.Project)
	if err != nil {
		message := fmt.Sprintf("Failed to fetch vars for task %v: %v", task.Id, err)
		evergreen.Logger.Logf(slogger.ERROR, message)
		http.Error(w, message, http.StatusInternalServerError)
		return
	}
	if projectVars == nil {
		plugin.WriteJSON(w, http.StatusOK, ExpansionVars{})
		return
	}

	plugin.WriteJSON(w, http.StatusOK, projectVars.Vars)
	return
}
Beispiel #13
0
// getTasksForVersion sends back the list of TaskJSON documents associated with a version id.
func getTasksForVersion(w http.ResponseWriter, r *http.Request) {
	jsonForTasks, err := findTasksForVersion(mux.Vars(r)["version_id"], mux.Vars(r)["name"])
	if jsonForTasks == nil {
		http.Error(w, "{}", http.StatusNotFound)
		return
	}
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	plugin.WriteJSON(w, http.StatusOK, jsonForTasks)
	return
}
Beispiel #14
0
// getTaskJSONByTag finds a TaskJSON by a tag
func getTaskJSONByTag(w http.ResponseWriter, r *http.Request) {
	var jsonForTask TaskJSON
	err := db.FindOneQ(collection,
		db.Query(bson.M{"project_id": mux.Vars(r)["project_id"],
			TagKey:      mux.Vars(r)["tag"],
			VariantKey:  mux.Vars(r)["variant"],
			TaskNameKey: mux.Vars(r)["task_name"],
			NameKey:     mux.Vars(r)["name"],
		}), &jsonForTask)
	if err != nil {
		if err != mgo.ErrNotFound {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		http.Error(w, "{}", http.StatusNotFound)
		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)
}
Beispiel #15
0
// getTaskById sends back a JSONTask with the corresponding task id.
func getTaskById(w http.ResponseWriter, r *http.Request) {
	var jsonForTask TaskJSON
	err := db.FindOneQ(collection, db.Query(bson.M{TaskIdKey: mux.Vars(r)["task_id"], NameKey: mux.Vars(r)["name"]}), &jsonForTask)
	if err != nil {
		if err != mgo.ErrNotFound {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		http.Error(w, "{}", http.StatusNotFound)
		return
	}
	plugin.WriteJSON(w, http.StatusOK, jsonForTask)

}
Beispiel #16
0
func getCommit(w http.ResponseWriter, r *http.Request) {
	var jsonForTask TaskJSON
	err := db.FindOneQ(collection,
		db.Query(bson.M{ProjectIdKey: mux.Vars(r)["project_id"],
			RevisionKey: bson.RegEx{"^" + regexp.QuoteMeta(mux.Vars(r)["revision"]), "i"},
			VariantKey:  mux.Vars(r)["variant"],
			TaskNameKey: mux.Vars(r)["task_name"],
			NameKey:     mux.Vars(r)["name"],
			IsPatchKey:  false,
		}), &jsonForTask)
	if err != nil {
		if err != mgo.ErrNotFound {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		http.Error(w, "{}", http.StatusNotFound)
		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)
}
// BuildFailuresSearchHandler handles the requests of searching jira in the build
//  failures project
func (bbp *BuildBaronPlugin) buildFailuresSearch(w http.ResponseWriter, r *http.Request) {
	taskId := mux.Vars(r)["task_id"]
	task, err := model.FindTask(taskId)
	if err != nil {
		plugin.WriteJSON(w, http.StatusInternalServerError, err.Error())
		return
	}
	jql := taskToJQL(task)

	jiraHandler := thirdparty.NewJiraHandler(
		bbp.opts.Host,
		bbp.opts.Username,
		bbp.opts.Password,
	)

	results, err := jiraHandler.JQLSearch(jql)
	if err != nil {
		message := fmt.Sprintf("%v: %v, %v", JIRAFailure, err, jql)
		evergreen.Logger.Errorf(slogger.ERROR, message)
		plugin.WriteJSON(w, http.StatusInternalServerError, message)
		return
	}
	plugin.WriteJSON(w, http.StatusOK, results)
}
// 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 := task.FetchPatch()
	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)
}
Beispiel #19
0
func MockPluginEcho(w http.ResponseWriter, request *http.Request) {
	arg1 := mux.Vars(request)["param1"]
	arg2, err := strconv.Atoi(mux.Vars(request)["param2"])
	if err != nil {
		http.Error(w, "bad val for param2", http.StatusBadRequest)
		return
	}

	newTask := plugin.GetTask(request)
	if newTask != nil {
		//task should have been populated for us, by the API server
		plugin.WriteJSON(w, http.StatusOK, map[string]string{
			"echo": fmt.Sprintf("%v/%v/%v", arg1, arg2, newTask.Id),
		})
		return
	}
	http.Error(w, "couldn't get task from context", http.StatusInternalServerError)
}
Beispiel #20
0
// getTags finds TaskJSONs that have tags
func getTags(w http.ResponseWriter, r *http.Request) {
	t, err := task.FindOne(task.ById(mux.Vars(r)["task_id"]))
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	tags := []struct {
		Tag string `bson:"_id" json:"tag"`
	}{}
	err = db.Aggregate(collection, []bson.M{
		{"$match": bson.M{ProjectIdKey: t.Project, TagKey: bson.M{"$exists": true, "$ne": ""}}},
		{"$project": bson.M{TagKey: 1}}, bson.M{"$group": bson.M{"_id": "$tag"}},
	}, &tags)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	plugin.WriteJSON(w, http.StatusOK, tags)
}
Beispiel #21
0
// getTaskByTag returns a TaskJSON with a specific task name and tag
func getTaskByTag(w http.ResponseWriter, r *http.Request) {
	t := plugin.GetTask(r)
	if t == nil {
		http.Error(w, "task not found", http.StatusNotFound)
		return
	}
	tagged := []TaskJSON{}
	jsonQuery := db.Query(bson.M{
		ProjectIdKey: t.Project,
		VariantKey:   t.BuildVariant,
		TaskNameKey:  mux.Vars(r)["task_name"],
		TagKey:       bson.M{"$exists": true, "$ne": ""},
		NameKey:      mux.Vars(r)["name"]})
	err := db.FindAllQ(collection, jsonQuery, &tagged)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	plugin.WriteJSON(w, http.StatusOK, tagged)
}
// saveNote reads a request containing a note's content along with the last seen
// edit time and updates the note in the database.
func (bbp *BuildBaronPlugin) saveNote(w http.ResponseWriter, r *http.Request) {
	taskId := mux.Vars(r)["task_id"]
	n := &Note{}
	if err := util.ReadJSONInto(r.Body, n); err != nil {
		plugin.WriteJSON(w, http.StatusBadRequest, err.Error())
		return
	}

	// prevent incredibly large notes
	if len(n.Content) > maxNoteSize {
		plugin.WriteJSON(w, http.StatusBadRequest, "note is too large")
		return
	}

	// We need to make sure the user isn't blowing away a new edit,
	// so we load the existing note. If the user's last seen edit time is less
	// than the most recent edit, we error with a helpful message.
	old, err := NoteForTask(taskId)
	if err != nil {
		plugin.WriteJSON(w, http.StatusInternalServerError, err.Error())
		return
	}
	// we compare times by millisecond rather than nanosecond so we can
	// work around the rounding that occurs when javascript forces these
	// large values into in float type.
	if old != nil && n.UnixNanoTime/msPerNS != old.UnixNanoTime/msPerNS {
		plugin.WriteJSON(w, http.StatusBadRequest,
			"this note has already been edited. Please refresh and try again.")
		return
	}

	n.TaskId = taskId
	n.UnixNanoTime = time.Now().UnixNano()
	if err := n.Upsert(); err != nil {
		plugin.WriteJSON(w, http.StatusInternalServerError, err.Error())
		return
	}
	plugin.WriteJSON(w, http.StatusOK, n)
}
Beispiel #23
0
// getVersion returns a StatusOK if the route is hit
func getVersion(w http.ResponseWriter, r *http.Request) {
	plugin.WriteJSON(w, http.StatusOK, "1")
}
Beispiel #24
0
// Takes a request for a task's file to be copied from
// one s3 location to another. Ensures that if the destination
// file path already exists, no file copy is performed.
func S3CopyHandler(w http.ResponseWriter, r *http.Request) {
	task := plugin.GetTask(r)
	if task == nil {
		http.Error(w, "task not found", http.StatusNotFound)
		return
	}
	s3CopyReq := &S3CopyRequest{}
	err := util.ReadJSONInto(r.Body, s3CopyReq)
	if err != nil {
		evergreen.Logger.Errorf(slogger.ERROR, "error reading push request: %v", err)
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	// Get the version for this task, so we can check if it has
	// any already-done pushes
	v, err := version.FindOne(version.ById(task.Version))
	if err != nil {
		evergreen.Logger.Logf(slogger.ERROR, "error querying task %v with version id %v: %v",
			task.Id, task.Version, err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	// Check for an already-pushed file with this same file path,
	// but from a conflicting or newer commit sequence num
	if v == nil {
		evergreen.Logger.Logf(slogger.ERROR, "no version found for build %v", task.BuildId)
		http.Error(w, "version not found", http.StatusNotFound)
		return
	}

	copyFromLocation := strings.Join([]string{s3CopyReq.S3SourceBucket, s3CopyReq.S3SourcePath}, "/")
	copyToLocation := strings.Join([]string{s3CopyReq.S3DestinationBucket, s3CopyReq.S3DestinationPath}, "/")

	newestPushLog, err := model.FindPushLogAfter(copyToLocation, v.RevisionOrderNumber)
	if err != nil {
		evergreen.Logger.Logf(slogger.ERROR, "error querying for push log at %v: %v", copyToLocation, err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	if newestPushLog != nil {
		evergreen.Logger.Logf(slogger.ERROR, "conflict with existing pushed file: "+
			"%v", copyToLocation)
		http.Error(w, "conflicting push target for this file already exists.", http.StatusConflict)
		return
	}

	// It's now safe to put the file in its permanent location.
	newPushLog := model.NewPushLog(v, task, copyToLocation)
	err = newPushLog.Insert()
	if err != nil {
		evergreen.Logger.Logf(slogger.ERROR, "failed to create new push log: %v %v", newPushLog, err)
		http.Error(w, fmt.Sprintf("failed to create push log: %v", err), http.StatusInternalServerError)
		return
	}

	// Now copy the file into the permanent location
	auth := &aws.Auth{
		AccessKey: s3CopyReq.AwsKey,
		SecretKey: s3CopyReq.AwsSecret,
	}

	evergreen.Logger.Logf(slogger.INFO, "performing S3 copy: '%v' => '%v'",
		copyFromLocation, copyToLocation)

	_, err = util.RetryArithmeticBackoff(func() error {
		err := thirdparty.S3CopyFile(auth,
			s3CopyReq.S3SourceBucket,
			s3CopyReq.S3SourcePath,
			s3CopyReq.S3DestinationBucket,
			s3CopyReq.S3DestinationPath,
			string(s3.PublicRead),
		)
		if err != nil {
			evergreen.Logger.Logf(slogger.ERROR, "S3 copy failed for task %v, "+
				"retrying: %v", task.Id, err)
			return util.RetriableError{err}
		} else {
			err := newPushLog.UpdateStatus(model.PushLogSuccess)
			if err != nil {
				evergreen.Logger.Logf(slogger.ERROR, "updating pushlog status failed"+
					" for task %v: %v", task.Id, err)
			}
			return err
		}
	}, s3CopyRetryNumRetries, s3CopyRetrySleepTimeSec*time.Second)

	if err != nil {
		message := fmt.Sprintf("S3 copy failed for task %v: %v", task.Id, err)
		evergreen.Logger.Logf(slogger.ERROR, message)
		err = newPushLog.UpdateStatus(model.PushLogFailed)
		if err != nil {
			evergreen.Logger.Logf(slogger.ERROR, "updating pushlog status failed: %v", err)
		}
		http.Error(w, message, http.StatusInternalServerError)
		return
	}
	plugin.WriteJSON(w, http.StatusOK, "S3 copy Successful")
}
Beispiel #25
0
// ManifestLoadHandler attempts to get the manifest, if it exists it updates the expansions and returns
// If it does not exist it performs GitHub API calls for each of the project's modules and gets
// the head revision of the branch and inserts it into the manifest collection.
// If there is a duplicate key error, then do a find on the manifest again.
func (mp *ManifestPlugin) ManifestLoadHandler(w http.ResponseWriter, r *http.Request) {
	task := plugin.GetTask(r)
	projectRef, err := model.FindOneProjectRef(task.Project)
	if err != nil {
		http.Error(w, fmt.Sprintf("projectRef not found for project %v: %v", task.Project, err), http.StatusNotFound)
		return
	}
	project, err := model.FindProject("", projectRef)
	if err != nil {
		http.Error(w, fmt.Sprintf("project not found for ProjectRef %v: %v", projectRef.Identifier, err),
			http.StatusNotFound)
		return
	}
	if project == nil {
		http.Error(w, fmt.Sprintf("empty project not found for ProjectRef %v: %v", projectRef.Identifier, err),
			http.StatusNotFound)
		return
	}

	// try to get the manifest
	currentManifest, err := manifest.FindOne(manifest.ById(task.Version))
	if err != nil {
		http.Error(w, fmt.Sprintf("error retrieving manifest with version id %v: %v", task.Version, err),
			http.StatusNotFound)
		return
	}
	if currentManifest != nil {
		plugin.WriteJSON(w, http.StatusOK, currentManifest)
		return
	}

	if task.Version == "" {
		http.Error(w, fmt.Sprintf("versionId is empty"), http.StatusNotFound)
		return
	}

	// attempt to insert a manifest after making GitHub API calls
	newManifest := &manifest.Manifest{
		Id:          task.Version,
		Revision:    task.Revision,
		ProjectName: task.Project,
		Branch:      project.Branch,
	}

	// populate modules
	modules := make(map[string]*manifest.Module)
	for _, module := range project.Modules {
		owner, repo := module.GetRepoOwnerAndName()
		gitBranch, err := thirdparty.GetBranchEvent(mp.OAuthCredentials, owner, repo, module.Branch)
		if err != nil {
			http.Error(w, fmt.Sprintf("error retrieving getting git branch for module %v: %v", module.Name, err),
				http.StatusNotFound)
			return
		}

		modules[module.Name] = &manifest.Module{
			Branch:   module.Branch,
			Revision: gitBranch.Commit.SHA,
			Repo:     repo,
			Owner:    owner,
			URL:      gitBranch.Commit.Url,
		}
	}
	newManifest.Modules = modules
	duplicate, err := newManifest.TryInsert()
	if err != nil {
		http.Error(w, fmt.Sprintf("error inserting manifest for %v: %v", newManifest.ProjectName, err),
			http.StatusNotFound)
		return
	}
	// if it is a duplicate, load the manifest again`
	if duplicate {
		// try to get the manifest
		m, err := manifest.FindOne(manifest.ById(task.Version))
		if err != nil {
			http.Error(w, fmt.Sprintf("error getting latest manifest for %v: %v", newManifest.ProjectName, err),
				http.StatusNotFound)
			return
		}
		if m != nil {
			plugin.WriteJSON(w, http.StatusOK, m)
			return
		}
	}
	// no duplicate key error, use the manifest just created.

	plugin.WriteJSON(w, http.StatusOK, newManifest)
	return
}
Beispiel #26
0
func (hwp *JSONPlugin) GetUIHandler() http.Handler {
	r := mux.NewRouter()
	r.HandleFunc("/version", func(w http.ResponseWriter, r *http.Request) {
		plugin.WriteJSON(w, http.StatusOK, "1")
	})
	r.HandleFunc("/task/{task_id}/{name}/", func(w http.ResponseWriter, r *http.Request) {
		var jsonForTask TaskJSON
		err := db.FindOneQ(collection, db.Query(bson.M{"task_id": mux.Vars(r)["task_id"], "name": mux.Vars(r)["name"]}), &jsonForTask)
		if err != nil {
			if err != mgo.ErrNotFound {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
			http.Error(w, "{}", http.StatusNotFound)
			return
		}
		plugin.WriteJSON(w, http.StatusOK, jsonForTask)
	})

	r.HandleFunc("/task/{task_id}/{name}/tags", func(w http.ResponseWriter, r *http.Request) {
		t, err := model.FindTask(mux.Vars(r)["task_id"])
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		tags := []struct {
			Tag string `bson:"_id" json:"tag"`
		}{}
		err = db.Aggregate(collection, []bson.M{
			{"$match": bson.M{"project_id": t.Project, "tag": bson.M{"$exists": true, "$ne": ""}}},
			{"$project": bson.M{"tag": 1}}, bson.M{"$group": bson.M{"_id": "$tag"}},
		}, &tags)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		plugin.WriteJSON(w, http.StatusOK, tags)
	})
	r.HandleFunc("/task/{task_id}/{name}/tag", func(w http.ResponseWriter, r *http.Request) {
		t, err := model.FindTask(mux.Vars(r)["task_id"])
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		if t == nil {
			http.Error(w, "{}", http.StatusNotFound)
			return
		}
		if r.Method == "DELETE" {
			if _, err = db.UpdateAll(collection,
				bson.M{"version_id": t.Version, "name": mux.Vars(r)["name"]},
				bson.M{"$unset": bson.M{"tag": 1}}); err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
			plugin.WriteJSON(w, http.StatusOK, "")
		}
		inTag := struct {
			Tag string `json:"tag"`
		}{}
		err = util.ReadJSONInto(r.Body, &inTag)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		if len(inTag.Tag) == 0 {
			http.Error(w, "tag must not be blank", http.StatusBadRequest)
			return
		}

		_, err = db.UpdateAll(collection,
			bson.M{"version_id": t.Version, "name": mux.Vars(r)["name"]},
			bson.M{"$set": bson.M{"tag": inTag.Tag}})

		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		plugin.WriteJSON(w, http.StatusOK, "")
	})
	r.HandleFunc("/tag/{project_id}/{tag}/{variant}/{task_name}/{name}", func(w http.ResponseWriter, r *http.Request) {
		var jsonForTask TaskJSON
		err := db.FindOneQ(collection,
			db.Query(bson.M{"project_id": mux.Vars(r)["project_id"],
				"tag":       mux.Vars(r)["tag"],
				"variant":   mux.Vars(r)["variant"],
				"task_name": mux.Vars(r)["task_name"],
				"name":      mux.Vars(r)["name"],
			}), &jsonForTask)
		if err != nil {
			if err != mgo.ErrNotFound {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
			http.Error(w, "{}", http.StatusNotFound)
			return
		}
		plugin.WriteJSON(w, http.StatusOK, jsonForTask)
	})
	r.HandleFunc("/commit/{project_id}/{revision}/{variant}/{task_name}/{name}", func(w http.ResponseWriter, r *http.Request) {
		var jsonForTask TaskJSON
		err := db.FindOneQ(collection,
			db.Query(bson.M{"project_id": mux.Vars(r)["project_id"],
				"revision":  bson.RegEx{"^" + regexp.QuoteMeta(mux.Vars(r)["revision"]), "i"},
				"variant":   mux.Vars(r)["variant"],
				"task_name": mux.Vars(r)["task_name"],
				"name":      mux.Vars(r)["name"],
				"is_patch":  false,
			}), &jsonForTask)
		if err != nil {
			if err != mgo.ErrNotFound {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
			http.Error(w, "{}", http.StatusNotFound)
			return
		}
		plugin.WriteJSON(w, http.StatusOK, jsonForTask)
	})
	r.HandleFunc("/history/{task_id}/{name}", func(w http.ResponseWriter, r *http.Request) {
		t, err := model.FindTask(mux.Vars(r)["task_id"])
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		if t == nil {
			http.Error(w, "{}", http.StatusNotFound)
			return
		}

		before := []TaskJSON{}
		jsonQuery := db.Query(bson.M{
			"project_id": t.Project,
			"variant":    t.BuildVariant,
			"order":      bson.M{"$lte": t.RevisionOrderNumber},
			"task_name":  t.DisplayName,
			"is_patch":   false,
			"name":       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{
			"project_id": t.Project,
			"variant":    t.BuildVariant,
			"order":      bson.M{"$gt": t.RevisionOrderNumber},
			"task_name":  t.DisplayName,
			"is_patch":   false,
			"name":       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...)
		plugin.WriteJSON(w, http.StatusOK, before)
	})
	return r
}
Beispiel #27
0
// GetRoutes returns an API route for serving patch data.
func (jsp *JSONPlugin) GetAPIHandler() http.Handler {
	r := mux.NewRouter()
	r.HandleFunc("/tags/{task_name}/{name}", func(w http.ResponseWriter, r *http.Request) {
		t := plugin.GetTask(r)
		if t == nil {
			http.Error(w, "task not found", http.StatusNotFound)
			return
		}
		tagged := []TaskJSON{}
		jsonQuery := db.Query(bson.M{
			"project_id": t.Project,
			"variant":    t.BuildVariant,
			"task_name":  mux.Vars(r)["task_name"],
			"tag":        bson.M{"$exists": true, "$ne": ""},
			"name":       mux.Vars(r)["name"]})
		err := db.FindAllQ(collection, jsonQuery, &tagged)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		plugin.WriteJSON(w, http.StatusOK, tagged)
	})
	r.HandleFunc("/history/{task_name}/{name}", func(w http.ResponseWriter, r *http.Request) {
		t := plugin.GetTask(r)
		if t == nil {
			http.Error(w, "task not found", http.StatusNotFound)
			return
		}
		before := []TaskJSON{}
		jsonQuery := db.Query(bson.M{
			"project_id": t.Project,
			"variant":    t.BuildVariant,
			"order":      bson.M{"$lte": t.RevisionOrderNumber},
			"task_name":  mux.Vars(r)["task_name"],
			"is_patch":   false,
			"name":       mux.Vars(r)["name"]}).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{
			"project_id": t.Project,
			"variant":    t.BuildVariant,
			"order":      bson.M{"$gt": t.RevisionOrderNumber},
			"task_name":  mux.Vars(r)["task_name"],
			"is_patch":   false,
			"name":       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...)
		plugin.WriteJSON(w, http.StatusOK, before)
	})

	r.HandleFunc("/data/{name}", func(w http.ResponseWriter, r *http.Request) {
		task := plugin.GetTask(r)
		if task == nil {
			http.Error(w, "task not found", http.StatusNotFound)
			return
		}
		name := mux.Vars(r)["name"]
		rawData := map[string]interface{}{}
		err := util.ReadJSONInto(r.Body, &rawData)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		jsonBlob := TaskJSON{
			TaskId:              task.Id,
			TaskName:            task.DisplayName,
			Name:                name,
			BuildId:             task.BuildId,
			Variant:             task.BuildVariant,
			ProjectId:           task.Project,
			VersionId:           task.Version,
			Revision:            task.Revision,
			RevisionOrderNumber: task.RevisionOrderNumber,
			Data:                rawData,
			IsPatch:             task.Requester == evergreen.PatchVersionRequester,
		}
		_, err = db.Upsert(collection, bson.M{"task_id": task.Id, "name": name}, jsonBlob)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		plugin.WriteJSON(w, http.StatusOK, "ok")
		return
	})

	r.HandleFunc("/data/{task_name}/{name}", func(w http.ResponseWriter, r *http.Request) {
		task := plugin.GetTask(r)
		if task == 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{"version_id": task.Version, "build_id": task.BuildId, "name": name, "task_name": taskName}), &jsonForTask)
		if err != nil {
			if err == mgo.ErrNotFound {
				plugin.WriteJSON(w, http.StatusNotFound, nil)
				return
			}
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		plugin.WriteJSON(w, http.StatusOK, jsonForTask.Data)
	})
	r.HandleFunc("/data/{task_name}/{name}/{variant}", func(w http.ResponseWriter, r *http.Request) {
		task := plugin.GetTask(r)
		if task == nil {
			http.Error(w, "task not found", http.StatusNotFound)
			return
		}
		name := mux.Vars(r)["name"]
		taskName := mux.Vars(r)["task_name"]
		variantId := mux.Vars(r)["variant"]
		// Find the task for the other variant, if it exists
		ts, err := model.FindTasks(db.Query(bson.M{model.TaskVersionKey: task.Version, model.TaskBuildVariantKey: variantId, model.TaskDisplayNameKey: taskName}).Limit(1))
		if err != nil {
			if err == mgo.ErrNotFound {
				plugin.WriteJSON(w, http.StatusNotFound, nil)
				return
			}
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		if len(ts) == 0 {
			plugin.WriteJSON(w, http.StatusNotFound, nil)
			return
		}
		otherVariantTask := ts[0]

		var jsonForTask TaskJSON
		err = db.FindOneQ(collection, db.Query(bson.M{"task_id": otherVariantTask.Id, "name": name}), &jsonForTask)
		if err != nil {
			if err == mgo.ErrNotFound {
				plugin.WriteJSON(w, http.StatusNotFound, nil)
				return
			}
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		plugin.WriteJSON(w, http.StatusOK, jsonForTask.Data)
	})
	return r
}
Beispiel #28
0
// getTasksForLatestVersion sends back the TaskJSON data associated with the latest version.
func getTasksForLatestVersion(w http.ResponseWriter, r *http.Request) {
	project := mux.Vars(r)["project_id"]
	name := mux.Vars(r)["name"]
	skip, err := util.GetIntValue(r, "skip", 0)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	if skip < 0 {
		http.Error(w, "negative skip", http.StatusBadRequest)
		return
	}
	pipeline := []bson.M{
		// match on name and project
		{"$match": bson.M{
			NameKey:      name,
			ProjectIdKey: project,
		}},

		// sort on the revision number
		{"$sort": bson.M{
			RevisionOrderNumberKey: -1,
		}},

		// group by version id
		{"$group": bson.M{
			"_id": bson.M{
				"r":   "$" + RevisionOrderNumberKey,
				"vid": "$" + VersionIdKey,
			},
			"t": bson.M{
				"$push": bson.M{
					"d":    "$" + DataKey,
					"t_id": "$" + TaskIdKey,
					"tn":   "$" + TaskNameKey,
					"var":  "$" + VariantKey,
				},
			},
		}},

		// sort on the _id
		{"$sort": bson.M{
			"_id.r": -1,
		}},

		{"$skip": skip},
		{"$limit": 2},
	}

	tasksForVersions := []TasksForVersion{}
	err = db.Aggregate(collection, pipeline, &tasksForVersions)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	if len(tasksForVersions) == 0 {
		http.Error(w, "no tasks found", http.StatusNotFound)
		return
	}

	// we default have another revision
	lastRevision := false
	currentVersion := tasksForVersions[0]

	// if there is only one version, then we are at the last revision.
	if len(tasksForVersions) < 2 {
		lastRevision = true
	}

	// get the version commit info
	v, err := version.FindOne(version.ById(currentVersion.Id.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:  v.Id,
	}

	data := VersionData{currentVersion.Tasks, commitInfo, lastRevision}
	plugin.WriteJSON(w, http.StatusOK, data)
}