Пример #1
0
func FindProject(revision string, projectRef *ProjectRef) (*Project, error) {
	if projectRef == nil {
		return nil, fmt.Errorf("projectRef given is nil")
	}
	if projectRef.Identifier == "" {
		return nil, fmt.Errorf("Invalid project with blank identifier")
	}

	project := &Project{}
	project.Identifier = projectRef.Identifier
	// when the revision is empty we find the last known good configuration from the versions
	// If the last known good configuration does not exist,
	// load the configuration from the local config in the project ref.
	if revision == "" {
		lastGoodVersion, err := version.FindOne(version.ByLastKnownGoodConfig(projectRef.Identifier))
		if err != nil {
			return nil, fmt.Errorf("Error finding recent valid version for %v: %v", projectRef.Identifier, err)
		}
		if lastGoodVersion != nil {
			// for new repositories, we don't want to error out when we don't have
			// any versions stored in the database so we default to the skeletal
			// information we already have from the project file on disk
			err = LoadProjectInto([]byte(lastGoodVersion.Config), projectRef.Identifier, project)
			if err != nil {
				return nil, fmt.Errorf("Error loading project from "+
					"last good version for project, %v: %v", lastGoodVersion.Identifier, err)
			}
		} else {
			// Check to see if there is a local configuration in the project ref
			if projectRef.LocalConfig != "" {
				err = LoadProjectInto([]byte(projectRef.LocalConfig), projectRef.Identifier, project)
				if err != nil {
					return nil, fmt.Errorf("Error loading local config for project ref, %v : %v", projectRef.Identifier, err)
				}
			}
		}
	}

	if revision != "" {
		// we immediately return an error if the repotracker version isn't found
		// for the given project at the given revision
		version, err := version.FindOne(version.ByProjectIdAndRevision(projectRef.Identifier, revision))
		if err != nil {
			return nil, fmt.Errorf("error fetching version for project %v revision %v: %v", projectRef.Identifier, revision, err)
		}
		if version == nil {
			// fall back to the skeletal project
			return project, nil
		}

		project = &Project{}
		if err = LoadProjectInto([]byte(version.Config), projectRef.Identifier, project); err != nil {
			return nil, fmt.Errorf("Error loading project from version: %v", err)
		}
	}
	return project, nil
}
Пример #2
0
func TestLastKnownGoodConfig(t *testing.T) {
	Convey("When calling LastKnownGoodConfig..", t, func() {
		identifier := "identifier"
		Convey("no versions should be returned if there're no good "+
			"last known configurations", func() {
			v := &version.Version{
				Identifier: identifier,
				Requester:  evergreen.RepotrackerVersionRequester,
				Errors:     []string{"error 1", "error 2"},
			}
			testutil.HandleTestingErr(v.Insert(), t, "Error inserting test version: %v")
			lastGood, err := version.FindOne(version.ByLastKnownGoodConfig(identifier))
			testutil.HandleTestingErr(err, t, "error finding last known good: %v")
			So(lastGood, ShouldBeNil)
		})
		Convey("a version should be returned if there is a last known good configuration", func() {
			v := &version.Version{
				Identifier: identifier,
				Requester:  evergreen.RepotrackerVersionRequester,
			}
			testutil.HandleTestingErr(v.Insert(), t, "Error inserting test version: %v")
			lastGood, err := version.FindOne(version.ByLastKnownGoodConfig(identifier))
			testutil.HandleTestingErr(err, t, "error finding last known good: %v")
			So(lastGood, ShouldNotBeNil)
		})
		Convey("most recent version should be found if there are several recent good configs", func() {
			v := &version.Version{
				Id:                  "1",
				Identifier:          identifier,
				Requester:           evergreen.RepotrackerVersionRequester,
				RevisionOrderNumber: 1,
				Config:              "1",
			}
			testutil.HandleTestingErr(v.Insert(), t, "Error inserting test version: %v")
			v.Id = "5"
			v.RevisionOrderNumber = 5
			v.Config = "5"
			testutil.HandleTestingErr(v.Insert(), t, "Error inserting test version: %v")
			v.Id = "2"
			v.RevisionOrderNumber = 2
			v.Config = "2"
			testutil.HandleTestingErr(v.Insert(), t, "Error inserting test version: %v")
			lastGood, err := version.FindOne(version.ByLastKnownGoodConfig(identifier))
			testutil.HandleTestingErr(err, t, "error finding last known good: %v")
			So(lastGood, ShouldNotBeNil)
			So(lastGood.Config, ShouldEqual, "5")
		})
		Reset(func() {
			db.Clear(version.Collection)
		})
	})
}
Пример #3
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)
}
Пример #4
0
// 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
}
Пример #5
0
// Returns a JSON response with the marshalled output of the version
// specified in the request.
func (restapi restAPI) getVersionInfo(w http.ResponseWriter, r *http.Request) {
	versionId := mux.Vars(r)["version_id"]

	srcVersion, err := version.FindOne(version.ById(versionId))
	if err != nil || srcVersion == nil {
		msg := fmt.Sprintf("Error finding version '%v'", versionId)
		statusCode := http.StatusNotFound

		if err != nil {
			evergreen.Logger.Logf(slogger.ERROR, "%v: %v", msg, err)
			statusCode = http.StatusInternalServerError
		}

		restapi.WriteJSON(w, statusCode, responseError{Message: msg})
		return
	}

	destVersion := &restVersion{}
	// Copy the contents from the database into our local version type
	err = angier.TransferByFieldNames(srcVersion, destVersion)
	if err != nil {
		msg := fmt.Sprintf("Error finding version '%v'", versionId)
		evergreen.Logger.Logf(slogger.ERROR, "%v: %v", msg, err)
		restapi.WriteJSON(w, http.StatusInternalServerError, responseError{Message: msg})
		return
	}
	for _, buildStatus := range srcVersion.BuildVariants {
		destVersion.BuildVariants = append(destVersion.BuildVariants, buildStatus.BuildVariant)
		evergreen.Logger.Logf(slogger.ERROR, "adding BuildVariant %v", buildStatus.BuildVariant)
	}

	restapi.WriteJSON(w, http.StatusOK, destVersion)
	return

}
Пример #6
0
// TryMarkPatchBuildFinished attempts to mark a patch as finished if all
// the builds for the patch are finished as well
func TryMarkPatchBuildFinished(b *build.Build, finishTime time.Time) error {
	v, err := version.FindOne(version.ById(b.Version))
	if err != nil {
		return err
	}
	if v == nil {
		return fmt.Errorf("Cannot find version for build %v with version %v", b.Id, b.Version)
	}

	// ensure all builds for this patch are finished as well
	builds, err := build.Find(build.ByIds(v.BuildIds).WithFields(build.StatusKey))
	if err != nil {
		return err
	}

	patchCompleted := true
	status := evergreen.PatchSucceeded
	for _, build := range builds {
		if !build.IsFinished() {
			patchCompleted = false
		}
		if build.Status != evergreen.BuildSucceeded {
			status = evergreen.PatchFailed
		}
	}

	// nothing to do if the patch isn't completed
	if !patchCompleted {
		return nil
	}

	return patch.TryMarkFinished(v.Id, finishTime, status)
}
Пример #7
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

}
Пример #8
0
// Returns a JSON response with the marshalled output of the version
// specified by its revision and project name in the request.
func (restapi restAPI) getVersionInfoViaRevision(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	projectId := vars["project_id"]
	revision := vars["revision"]

	srcVersion, err := version.FindOne(version.ByProjectIdAndRevision(projectId, revision))
	if err != nil || srcVersion == nil {
		msg := fmt.Sprintf("Error finding revision '%v' for project '%v'", revision, projectId)
		statusCode := http.StatusNotFound

		if err != nil {
			evergreen.Logger.Logf(slogger.ERROR, "%v: %v", msg, err)
			statusCode = http.StatusInternalServerError
		}

		restapi.WriteJSON(w, statusCode, responseError{Message: msg})
		return
	}

	destVersion := &restVersion{}
	copyVersion(srcVersion, destVersion)

	for _, buildStatus := range srcVersion.BuildVariants {
		destVersion.BuildVariants = append(destVersion.BuildVariants, buildStatus.BuildVariant)
		evergreen.Logger.Logf(slogger.ERROR, "adding BuildVariant %v", buildStatus.BuildVariant)
	}

	restapi.WriteJSON(w, http.StatusOK, destVersion)
	return

}
Пример #9
0
// createVersionItems populates and stores all the tasks and builds for a version according to
// the given project config.
func createVersionItems(v *version.Version, ref *model.ProjectRef, project *model.Project) error {
	for _, buildvariant := range project.BuildVariants {
		if buildvariant.Disabled {
			continue
		}
		buildId, err := model.CreateBuildFromVersion(project, v, buildvariant.Name, false, nil)
		if err != nil {
			return err
		}

		lastActivated, err := version.FindOne(version.ByLastVariantActivation(ref.Identifier, buildvariant.Name))
		if err != nil {
			evergreen.Logger.Logf(slogger.ERROR, "Error getting activation time for bv %v", buildvariant.Name)
			return err
		}

		var lastActivation *time.Time
		if lastActivated != nil {
			for _, buildStatus := range lastActivated.BuildVariants {
				if buildStatus.BuildVariant == buildvariant.Name && buildStatus.Activated {
					lastActivation = &buildStatus.ActivateAt
					break
				}
			}
		}

		var activateAt time.Time
		var activated bool
		if lastActivation == nil {
			// if we don't have a last activation time then activate now.
			activateAt = time.Now()
			activated = true
		} else {
			activateAt = lastActivation.Add(time.Minute * time.Duration(ref.GetBatchTime(&buildvariant)))
			evergreen.Logger.Logf(slogger.INFO, "Going to activate bv %v for project %v, version %v at %v",
				buildvariant.Name, ref.Identifier, v.Id, activateAt)
		}

		v.BuildIds = append(v.BuildIds, buildId)
		v.BuildVariants = append(v.BuildVariants, version.BuildStatus{
			BuildVariant: buildvariant.Name,
			Activated:    activated,
			ActivateAt:   activateAt,
			BuildId:      buildId,
		})
	}

	if err := v.Insert(); err != nil {
		evergreen.Logger.Errorf(slogger.ERROR, "Error inserting version %v: %v", v.Id, err)
		for _, buildStatus := range v.BuildVariants {
			if buildErr := model.DeleteBuild(buildStatus.BuildId); buildErr != nil {
				evergreen.Logger.Errorf(slogger.ERROR, "Error deleting build %v: %v",
					buildStatus.BuildId, buildErr)
			}
		}
		return err
	}
	return nil
}
Пример #10
0
func TestUpdateBuildStatusForTask(t *testing.T) {
	Convey("With two tasks and a build", t, func() {
		testutil.HandleTestingErr(db.ClearCollections(task.Collection, build.Collection, version.Collection), t,
			"Error clearing task and build collections")
		displayName := "testName"
		b := &build.Build{
			Id:      "buildtest",
			Status:  evergreen.BuildStarted,
			Version: "abc",
		}
		v := &version.Version{
			Id:     b.Version,
			Status: evergreen.VersionStarted,
		}
		testTask := task.Task{
			Id:          "testone",
			DisplayName: displayName,
			Activated:   false,
			BuildId:     b.Id,
			Project:     "sample",
			Status:      evergreen.TaskFailed,
		}
		anotherTask := task.Task{
			Id:          "two",
			DisplayName: displayName,
			Activated:   true,
			BuildId:     b.Id,
			Project:     "sample",
			Status:      evergreen.TaskFailed,
		}

		b.Tasks = []build.TaskCache{
			{
				Id:     testTask.Id,
				Status: evergreen.TaskSucceeded,
			},
			{
				Id:     anotherTask.Id,
				Status: evergreen.TaskFailed,
			},
		}
		So(b.Insert(), ShouldBeNil)
		So(testTask.Insert(), ShouldBeNil)
		So(anotherTask.Insert(), ShouldBeNil)
		So(v.Insert(), ShouldBeNil)
		Convey("updating the build for a task should update the build's status and the version's status", func() {
			So(UpdateBuildAndVersionStatusForTask(testTask.Id), ShouldBeNil)
			b, err := build.FindOne(build.ById(b.Id))
			So(err, ShouldBeNil)
			So(b.Status, ShouldEqual, evergreen.BuildFailed)
			v, err := version.FindOne(version.ById(v.Id))
			So(v.Status, ShouldEqual, evergreen.VersionFailed)

		})

	})
}
Пример #11
0
// prependConfigToVersion modifies the project config with the given id
func prependConfigToVersion(t *testing.T, versionId, configData string) {
	v, err := version.FindOne(version.ById(versionId))
	testutil.HandleTestingErr(err, t, "failed to load version")
	if v == nil {
		err = fmt.Errorf("could not find version to update")
		testutil.HandleTestingErr(err, t, "failed to find version")
	}
	v.Config = configData + v.Config
	testutil.HandleTestingErr(dbutil.ClearCollections(version.Collection), t, "couldnt reset version")
	testutil.HandleTestingErr(v.Insert(), t, "failed to insert version")
}
Пример #12
0
func TestMarkStart(t *testing.T) {
	Convey("With a task, build and version", t, func() {
		testutil.HandleTestingErr(db.ClearCollections(task.Collection, build.Collection, version.Collection), t,
			"Error clearing task and build collections")
		displayName := "testName"
		b := &build.Build{
			Id:      "buildtest",
			Status:  evergreen.BuildCreated,
			Version: "abc",
		}
		v := &version.Version{
			Id:     b.Version,
			Status: evergreen.VersionCreated,
		}
		testTask := task.Task{
			Id:          "testTask",
			DisplayName: displayName,
			Activated:   true,
			BuildId:     b.Id,
			Project:     "sample",
			Status:      evergreen.TaskUndispatched,
			Version:     b.Version,
		}

		b.Tasks = []build.TaskCache{
			{
				Id:     testTask.Id,
				Status: evergreen.TaskUndispatched,
			},
		}
		So(b.Insert(), ShouldBeNil)
		So(testTask.Insert(), ShouldBeNil)
		So(v.Insert(), ShouldBeNil)
		Convey("when calling MarkStart, the task, version and build should be updated", func() {
			So(MarkStart(testTask.Id), ShouldBeNil)
			testTask, err := task.FindOne(task.ById(testTask.Id))
			So(err, ShouldBeNil)
			So(testTask.Status, ShouldEqual, evergreen.TaskStarted)
			b, err := build.FindOne(build.ById(b.Id))
			So(err, ShouldBeNil)
			So(b.Status, ShouldEqual, evergreen.BuildStarted)
			So(b.Tasks, ShouldNotBeNil)
			So(len(b.Tasks), ShouldEqual, 1)
			So(b.Tasks[0].Status, ShouldEqual, evergreen.TaskStarted)
			v, err := version.FindOne(version.ById(v.Id))
			So(err, ShouldBeNil)
			So(v.Status, ShouldEqual, evergreen.VersionStarted)
		})
	})
}
Пример #13
0
// Verifies that the given revision order number is higher than the latest number stored for the project.
func sanityCheckOrderNum(revOrderNum int, projectId string) error {
	latest, err := version.FindOne(version.ByMostRecentForRequester(projectId, evergreen.RepotrackerVersionRequester))
	if err != nil {
		return fmt.Errorf("Error getting latest version: %v", err.Error())
	}

	// When there are no versions in the db yet, sanity check is moot
	if latest != nil {
		if revOrderNum <= latest.RevisionOrderNumber {
			return fmt.Errorf("Commit order number isn't greater than last stored version's: %v <= %v",
				revOrderNum, latest.RevisionOrderNumber)
		}
	}
	return nil
}
Пример #14
0
func (as *APIServer) GetVersion(w http.ResponseWriter, r *http.Request) {
	task := MustHaveTask(r)

	// Get the version for this task, so we can get its config data
	v, err := version.FindOne(version.ById(task.Version))
	if err != nil {
		as.LoggedError(w, r, http.StatusInternalServerError, err)
		return
	}

	if v == nil {
		http.Error(w, "version not found", http.StatusNotFound)
		return
	}

	as.WriteJSON(w, http.StatusOK, v)
}
Пример #15
0
// Construct a map of project names to build variants for that project
func findProjectBuildVariants(configName string) (map[string][]string, error) {
	projectNameToBuildVariants := make(map[string][]string)

	allProjects, err := model.FindAllTrackedProjectRefs()
	if err != nil {
		return nil, err
	}

	for _, projectRef := range allProjects {
		if !projectRef.Enabled {
			continue
		}
		var buildVariants []string
		var proj *model.Project
		var err error
		if projectRef.LocalConfig != "" {
			proj, err = model.FindProject("", &projectRef)
			if err != nil {
				return nil, fmt.Errorf("unable to find project file: %v", err)
			}
		} else {
			lastGood, err := version.FindOne(version.ByLastKnownGoodConfig(projectRef.Identifier))
			if err != nil {
				return nil, fmt.Errorf("unable to find last valid config: %v", err)
			}
			if lastGood == nil { // brand new project + no valid config yet, just return an empty map
				return projectNameToBuildVariants, nil
			}

			proj = &model.Project{}
			err = model.LoadProjectInto([]byte(lastGood.Config), projectRef.Identifier, proj)
			if err != nil {
				return nil, fmt.Errorf("error loading project '%v' from version: %v", projectRef.Identifier, err)
			}
		}

		for _, buildVariant := range proj.BuildVariants {
			buildVariants = append(buildVariants, buildVariant.Name)
		}

		projectNameToBuildVariants[projectRef.Identifier] = buildVariants
	}

	return projectNameToBuildVariants, nil
}
Пример #16
0
// populateTaskBuildVersion takes a task, build, and version ID and populates a projectContext
// with as many of the task, build, and version documents as possible.
// If any of the provided IDs is blank, they will be inferred from the more selective ones.
// Returns the project ID of the data found, which may be blank if the IDs are empty.
func (pc *projectContext) populateTaskBuildVersion(taskId, buildId, versionId string) (string, error) {
	projectId := ""
	var err error
	// Fetch task if there's a task ID present; if we find one, populate build/version IDs from it
	if len(taskId) > 0 {
		pc.Task, err = task.FindOne(task.ById(taskId))
		if err != nil {
			return "", err
		}

		if pc.Task != nil {
			// override build and version ID with the ones this task belongs to
			buildId = pc.Task.BuildId
			versionId = pc.Task.Version
			projectId = pc.Task.Project
		}
	}

	// Fetch build if there's a build ID present; if we find one, populate version ID from it
	if len(buildId) > 0 {
		pc.Build, err = build.FindOne(build.ById(buildId))
		if err != nil {
			return "", err
		}
		if pc.Build != nil {
			versionId = pc.Build.Version
			projectId = pc.Build.Project
		}
	}
	if len(versionId) > 0 {
		pc.Version, err = version.FindOne(version.ById(versionId))
		if err != nil {
			return "", err
		}
		if pc.Version != nil {
			projectId = pc.Version.Identifier
		}
	}
	return projectId, nil

}
Пример #17
0
func (self *TaskNotificationHandler) constructChangeInfo(allTasks []task.Task,
	key *NotificationKey) ([]ChangeInfo, error) {
	changeInfoSlice := make([]ChangeInfo, 0)

	for _, task := range allTasks {
		// add blamelist information for each task
		v, err := version.FindOne(version.ById(task.Version))
		if err != nil {
			return changeInfoSlice, err
		}
		if v == nil {
			return changeInfoSlice, fmt.Errorf("No version found for task %v with version id %v",
				task.Id, task.Version)
		}
		changeInfo := constructChangeInfo(v, key)
		changeInfo.Pushtime = task.PushTime.Format(time.RFC850)
		changeInfoSlice = append(changeInfoSlice, *changeInfo)
	}

	return changeInfoSlice, nil
}
Пример #18
0
func (self *BuildNotificationHandler) constructChangeInfo(allBuilds []build.Build,
	key *NotificationKey) ([]ChangeInfo, error) {
	changeInfoSlice := make([]ChangeInfo, 0)

	for _, build := range allBuilds {
		// add blamelist information for each build
		v, err := version.FindOne(version.ById(build.Version))
		if err != nil {
			return changeInfoSlice, err
		}

		if v == nil {
			err = fmt.Errorf("No version found for build %v with version id %v",
				build.Id, build.Version)
			return changeInfoSlice, err
		}
		changeInfo := constructChangeInfo(v, key)
		changeInfo.Pushtime = build.PushTime.Format(time.RFC850)
		changeInfoSlice = append(changeInfoSlice, *changeInfo)
	}
	return changeInfoSlice, nil
}
Пример #19
0
// Modifies part of the version specified in the request, and returns a
// JSON response with the marshalled output of its new state.
func (restapi restAPI) modifyVersionInfo(w http.ResponseWriter, r *http.Request) {
	versionId := mux.Vars(r)["version_id"]

	var input struct {
		Activated *bool `json:"activated"`
	}
	json.NewDecoder(r.Body).Decode(&input)

	v, err := version.FindOne(version.ById(versionId))
	if err != nil || v == nil {
		msg := fmt.Sprintf("Error finding version '%v'", versionId)
		statusCode := http.StatusNotFound

		if err != nil {
			evergreen.Logger.Logf(slogger.ERROR, "%v: %v", msg, err)
			statusCode = http.StatusInternalServerError
		}

		restapi.WriteJSON(w, statusCode, responseError{Message: msg})
		return
	}

	if input.Activated != nil {
		if err = model.SetVersionActivation(v.Id, *input.Activated); err != nil {
			state := "inactive"
			if *input.Activated {
				state = "active"
			}

			msg := fmt.Sprintf("Error marking version '%v' as %v", versionId, state)
			restapi.WriteJSON(w, http.StatusInternalServerError, responseError{Message: msg})
			return
		}
	}

	restapi.getVersionInfo(w, r)
}
Пример #20
0
// Takes in a version id and a map of "key -> buildvariant" (where "key" is of
// type "versionBuildVariant") and updates the map with an entry for the
// buildvariants associated with "versionStr"
func (self *Scheduler) updateVersionBuildVarMap(versionStr string,
	versionBuildVarMap map[versionBuildVariant]model.BuildVariant) (err error) {
	version, err := version.FindOne(version.ById(versionStr))
	if err != nil {
		return
	}
	if version == nil {
		return fmt.Errorf("nil version returned for version id '%v'", versionStr)
	}
	project := &model.Project{}

	err = model.LoadProjectInto([]byte(version.Config), version.Identifier, project)
	if err != nil {
		return fmt.Errorf("unable to load project config for version %v: "+
			"%v", versionStr, err)
	}

	// create buildvariant map (for accessing purposes)
	for _, buildVariant := range project.BuildVariants {
		key := versionBuildVariant{versionStr, buildVariant.Name}
		versionBuildVarMap[key] = buildVariant
	}
	return
}
Пример #21
0
// 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
}
Пример #22
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")
}
Пример #23
0
// Serves the task history page itself.
func (uis *UIServer) taskHistoryPage(w http.ResponseWriter, r *http.Request) {
	projCtx := MustHaveProjectContext(r)

	if projCtx.Project == nil {
		http.Error(w, "not found", http.StatusNotFound)
		return
	}
	taskName := mux.Vars(r)["task_name"]

	var chunk model.TaskHistoryChunk
	var v *version.Version
	var before bool
	var err error

	if strBefore := r.FormValue("before"); strBefore != "" {
		if before, err = strconv.ParseBool(strBefore); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
	}
	buildVariants := projCtx.Project.GetVariantsWithTask(taskName)

	if revision := r.FormValue("revision"); revision != "" {
		v, err = version.FindOne(version.ByProjectIdAndRevision(projCtx.Project.Identifier, revision))
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
	}

	taskHistoryIterator := model.NewTaskHistoryIterator(taskName, buildVariants, projCtx.Project.Identifier)

	if r.FormValue("format") == "" {
		if v != nil {
			chunk, err = taskHistoryIterator.GetChunk(v, InitRevisionsBefore, InitRevisionsAfter, true)
		} else {
			// Load the most recent MaxNumRevisions if a particular
			// version was unspecified
			chunk, err = taskHistoryIterator.GetChunk(v, MaxNumRevisions, NoRevisions, false)
		}
	} else if before {
		chunk, err = taskHistoryIterator.GetChunk(v, MaxNumRevisions, NoRevisions, false)
	} else {
		chunk, err = taskHistoryIterator.GetChunk(v, NoRevisions, MaxNumRevisions, false)
	}
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	data := taskHistoryPageData{
		TaskName:         taskName,
		Tasks:            chunk.Tasks,
		Variants:         buildVariants,
		FailedTests:      chunk.FailedTests,
		Versions:         chunk.Versions,
		ExhaustedBefore:  chunk.Exhausted.Before,
		ExhaustedAfter:   chunk.Exhausted.After,
		SelectedRevision: r.FormValue("revision"),
	}

	switch r.FormValue("format") {
	case "json":
		uis.WriteJSON(w, http.StatusOK, data)
		return
	default:
		uis.WriteHTML(w, http.StatusOK, struct {
			ProjectData projectContext
			User        *user.DBUser
			Flashes     []interface{}
			Data        taskHistoryPageData
		}{projCtx, GetUser(r), []interface{}{}, data}, "base",
			"task_history.html", "base_angular.html", "menu.html")
	}
}
Пример #24
0
func (uis *UIServer) variantHistory(w http.ResponseWriter, r *http.Request) {
	projCtx := MustHaveProjectContext(r)
	variant := mux.Vars(r)["variant"]
	beforeCommitId := r.FormValue("before")
	isJson := (r.FormValue("format") == "json")

	var beforeCommit *version.Version
	var err error
	beforeCommit = nil
	if beforeCommitId != "" {
		beforeCommit, err = version.FindOne(version.ById(beforeCommitId))
		if err != nil {
			uis.LoggedError(w, r, http.StatusInternalServerError, err)
			return
		}
		if beforeCommit == nil {
			evergreen.Logger.Logf(slogger.WARN, "'before' was specified but query returned nil")
		}
	}

	project, err := model.FindProject("", projCtx.ProjectRef)
	if err != nil {
		uis.LoggedError(w, r, http.StatusInternalServerError, err)
		return
	}

	bv := project.FindBuildVariant(variant)
	if bv == nil {
		http.Error(w, "variant not found", http.StatusNotFound)
		return
	}

	iter := model.NewBuildVariantHistoryIterator(variant, bv.Name, projCtx.Project.Identifier)
	tasks, versions, err := iter.GetItems(beforeCommit, 50)
	if err != nil {
		uis.LoggedError(w, r, http.StatusInternalServerError, err)
		return
	}

	var suites []string
	for _, task := range bv.Tasks {
		suites = append(suites, task.Name)
	}

	sort.Strings(suites)

	data := struct {
		Variant   string
		Tasks     []bson.M
		TaskNames []string
		Versions  []version.Version
		Project   string
	}{variant, tasks, suites, versions, projCtx.Project.Identifier}
	if isJson {
		uis.WriteJSON(w, http.StatusOK, data)
		return
	}
	uis.WriteHTML(w, http.StatusOK, struct {
		ProjectData projectContext
		User        *user.DBUser
		Flashes     []interface{}
		Data        interface{}
	}{projCtx, GetUser(r), []interface{}{}, data}, "base",
		"build_variant_history.html", "base_angular.html", "menu.html")
}
Пример #25
0
func getVersionHistory(versionId string, N int) ([]version.Version, error) {
	v, err := version.FindOne(version.ById(versionId))
	if err != nil {
		return nil, err
	} else if v == nil {
		return nil, fmt.Errorf("Version '%v' not found", versionId)
	}

	// Versions in the same push event, assuming that no two push events happen at the exact same time
	// Never want more than 2N+1 versions, so make sure we add a limit

	siblingVersions, err := version.Find(db.Query(
		bson.M{
			"order":  v.RevisionOrderNumber,
			"r":      evergreen.RepotrackerVersionRequester,
			"branch": v.Project,
		}).WithoutFields(version.ConfigKey).Sort([]string{"order"}).Limit(2*N + 1))
	if err != nil {
		return nil, err
	}

	versionIndex := -1
	for i := 0; i < len(siblingVersions); i++ {
		if siblingVersions[i].Id == v.Id {
			versionIndex = i
		}
	}

	numSiblings := len(siblingVersions) - 1
	versions := siblingVersions

	if versionIndex < N {
		// There are less than N later versions from the same push event
		// N subsequent versions plus the specified one
		subsequentVersions, err := version.Find(
			//TODO encapsulate this query in version pkg
			db.Query(bson.M{
				"order":  bson.M{"$gt": v.RevisionOrderNumber},
				"r":      evergreen.RepotrackerVersionRequester,
				"branch": v.Project,
			}).WithoutFields(version.ConfigKey).Sort([]string{"order"}).Limit(N - versionIndex))
		if err != nil {
			return nil, err
		}

		// Reverse the second array so we have the versions ordered "newest one first"
		for i := 0; i < len(subsequentVersions)/2; i++ {
			subsequentVersions[i], subsequentVersions[len(subsequentVersions)-1-i] = subsequentVersions[len(subsequentVersions)-1-i], subsequentVersions[i]
		}

		versions = append(subsequentVersions, versions...)
	}

	if numSiblings-versionIndex < N {
		previousVersions, err := version.Find(db.Query(bson.M{
			"order":  bson.M{"$lt": v.RevisionOrderNumber},
			"r":      evergreen.RepotrackerVersionRequester,
			"branch": v.Project,
		}).WithoutFields(version.ConfigKey).Sort([]string{"-order"}).Limit(N))
		if err != nil {
			return nil, err
		}
		versions = append(versions, previousVersions...)
	}

	return versions, nil
}
Пример #26
0
func (uis *UIServer) buildHistory(w http.ResponseWriter, r *http.Request) {
	buildId := mux.Vars(r)["build_id"]

	before, err := getIntValue(r, "before", 3)
	if err != nil {
		http.Error(w, fmt.Sprintf("invalid param 'before': %v", r.FormValue("before")), http.StatusBadRequest)
		return
	}

	after, err := getIntValue(r, "after", 3)
	if err != nil {
		http.Error(w, fmt.Sprintf("invalid param 'after': %v", r.FormValue("after")), http.StatusBadRequest)
		return
	}

	builds, err := getBuildVariantHistory(buildId, before, after)
	if err != nil {
		http.Error(w, fmt.Sprintf("error getting build history: %v", err), http.StatusInternalServerError)
		return
	}

	history := &struct {
		Builds      []*uiBuild `json:"builds"`
		LastSuccess *uiBuild   `json:"lastSuccess"`
	}{}

	history.Builds = make([]*uiBuild, len(builds))
	for i := 0; i < len(builds); i++ {
		v, err := version.FindOne(version.ById(builds[i].Version))
		if err != nil {
			http.Error(w, fmt.Sprintf("error getting version for build %v: %v", builds[i].Id, err), http.StatusInternalServerError)
			return
		}
		if v == nil {
			http.Error(w, fmt.Sprintf("no version found for build %v", builds[i].Id), http.StatusNotFound)
			return
		}
		history.Builds[i] = &uiBuild{
			Build:       builds[i],
			CurrentTime: time.Now().UnixNano(),
			Elapsed:     time.Now().Sub(builds[i].StartTime),
			RepoOwner:   v.Owner,
			Repo:        v.Repo,
			Version:     *v,
		}
	}

	lastSuccess, err := getBuildVariantHistoryLastSuccess(buildId)
	if err == nil && lastSuccess != nil {
		v, err := version.FindOne(version.ById(lastSuccess.Version))
		if err != nil {
			http.Error(
				w, fmt.Sprintf("error getting last successful build version: %v", err),
				http.StatusInternalServerError)
			return
		}
		if v == nil {
			http.Error(w, fmt.Sprintf("no version '%v' found", lastSuccess.Version), http.StatusNotFound)
			return
		}
		history.LastSuccess = &uiBuild{
			Build:       *lastSuccess,
			CurrentTime: time.Now().UnixNano(),
			Elapsed:     time.Now().Sub(lastSuccess.StartTime),
			RepoOwner:   v.Owner,
			Repo:        v.Repo,
			Version:     *v,
		}
	}

	uis.WriteJSON(w, http.StatusOK, history)
}
Пример #27
0
func TestStoreRepositoryRevisions(t *testing.T) {
	dropTestDB(t)
	testutil.ConfigureIntegrationTest(t, testConfig, "TestStoreRepositoryRevisions")
	Convey("When storing revisions gotten from a repository...", t, func() {
		err := testutil.CreateTestLocalConfig(testConfig, "mci-test", "")
		So(err, ShouldBeNil)
		repoTracker := RepoTracker{testConfig, projectRef, NewGithubRepositoryPoller(projectRef,
			testConfig.Credentials["github"])}

		// insert distros used in testing.
		d := distro.Distro{Id: "test-distro-one"}
		So(d.Insert(), ShouldBeNil)
		d.Id = "test-distro-two"
		So(d.Insert(), ShouldBeNil)

		Convey("On storing a single repo revision, we expect a version to be created"+
			" in the database for this project, which should be retrieved when we search"+
			" for this project's most recent version", func() {
			createTime := time.Now()
			revisionOne := *createTestRevision("firstRevision", createTime)
			revisions := []model.Revision{revisionOne}

			resultVersion, err := repoTracker.StoreRevisions(revisions)
			testutil.HandleTestingErr(err, t, "Error storing repository revisions %v")

			newestVersion, err := version.FindOne(version.ByMostRecentForRequester(projectRef.String(), evergreen.RepotrackerVersionRequester))
			testutil.HandleTestingErr(err, t, "Error retreiving newest version %v")

			So(resultVersion, ShouldResemble, newestVersion)
		})

		Convey("On storing several repo revisions, we expect a version to be created "+
			"for each revision", func() {
			createTime := time.Now()
			laterCreateTime := createTime.Add(time.Duration(4 * time.Hour))

			revisionOne := *createTestRevision("one", laterCreateTime)
			revisionTwo := *createTestRevision("two", createTime)

			revisions := []model.Revision{revisionOne, revisionTwo}

			_, err := repoTracker.StoreRevisions(revisions)
			testutil.HandleTestingErr(err, t, "Error storing repository revisions %v")

			versionOne, err := version.FindOne(version.ByProjectIdAndRevision(projectRef.Identifier, revisionOne.Revision))
			testutil.HandleTestingErr(err, t, "Error retrieving first stored version %v")
			versionTwo, err := version.FindOne(version.ByProjectIdAndRevision(projectRef.Identifier, revisionTwo.Revision))
			testutil.HandleTestingErr(err, t, "Error retreiving second stored version %v")

			So(versionOne.Revision, ShouldEqual, revisionOne.Revision)
			So(versionTwo.Revision, ShouldEqual, revisionTwo.Revision)
		})

		Reset(func() {
			dropTestDB(t)
		})
	})

	Convey("When storing versions from repositories with remote configuration files...", t, func() {

		project := createTestProject(nil, nil)

		revisions := []model.Revision{
			*createTestRevision("foo", time.Now().Add(1*time.Minute)),
		}

		poller := NewMockRepoPoller(project, revisions)

		repoTracker := RepoTracker{
			testConfig,
			&model.ProjectRef{
				Identifier: "testproject",
				BatchTime:  10,
			},
			poller,
		}

		// insert distros used in testing.
		d := distro.Distro{Id: "test-distro-one"}
		So(d.Insert(), ShouldBeNil)
		d.Id = "test-distro-two"
		So(d.Insert(), ShouldBeNil)

		Convey("We should not fetch configs for versions we already have stored.",
			func() {
				So(poller.ConfigGets, ShouldBeZeroValue)
				// Store revisions the first time
				_, err := repoTracker.StoreRevisions(revisions)
				So(err, ShouldBeNil)
				// We should have fetched the config once for each revision
				So(poller.ConfigGets, ShouldEqual, len(revisions))

				// Store them again
				_, err = repoTracker.StoreRevisions(revisions)
				So(err, ShouldBeNil)
				// We shouldn't have fetched the config any additional times
				// since we have already stored these versions
				So(poller.ConfigGets, ShouldEqual, len(revisions))
			},
		)

		Convey("We should handle invalid configuration files gracefully by storing a stub version",
			func() {
				errStrs := []string{"Someone dun' goof'd"}
				poller.setNextError(projectConfigError{errStrs})
				stubVersion, err := repoTracker.StoreRevisions(revisions)
				// We want this error to get swallowed so a config error
				// doesn't stop additional versions from getting created
				So(err, ShouldBeNil)
				So(stubVersion.Errors, ShouldResemble, errStrs)
			},
		)

		Convey("If there is an error other than a config error while fetching a config, we should fail hard",
			func() {
				unexpectedError := errors.New("Something terrible has happened!!")
				poller.setNextError(unexpectedError)
				v, err := repoTracker.StoreRevisions(revisions)
				So(v, ShouldBeNil)
				So(err, ShouldEqual, unexpectedError)
			},
		)

		Reset(func() {
			dropTestDB(t)
		})

	})
}
Пример #28
0
// Constructs all versions stored from recent repository revisions
// The additional complexity is due to support for project modifications on patch builds.
// We need to parse the remote config as it existed when each revision was created.
// The return value is the most recent version created as a result of storing the revisions.
// This function is idempotent with regard to storing the same version multiple times.
func (repoTracker *RepoTracker) StoreRevisions(revisions []model.Revision) (newestVersion *version.Version, err error) {
	defer func() {
		if newestVersion != nil {
			// Fetch the updated version doc, so that we include buildvariants in the result
			newestVersion, err = version.FindOne(version.ById(newestVersion.Id))
		}
	}()
	ref := repoTracker.ProjectRef

	for i := len(revisions) - 1; i >= 0; i-- {
		revision := revisions[i].Revision
		evergreen.Logger.Logf(slogger.INFO, "Processing revision %v in project %v", revision, ref.Identifier)

		// We check if the version exists here so we can avoid fetching the github config unnecessarily
		existingVersion, err := version.FindOne(version.ByProjectIdAndRevision(ref.Identifier, revisions[i].Revision))
		if err != nil {
			evergreen.Logger.Logf(slogger.ERROR,
				"Error looking up version at %v for project %v: %v", ref.Identifier, revision, err)
		}
		if existingVersion != nil {
			evergreen.Logger.Logf(slogger.INFO,
				"Skipping creation of version for project %v, revision %v since"+
					" we already have a record for it", ref.Identifier, revision)
			// We bind newestVersion here since we still need to return the most recent
			// version, even if it already exists
			newestVersion = existingVersion
			continue
		}

		// Create the stub of the version (not stored in DB yet)
		v, err := NewVersionFromRevision(ref, revisions[i])
		if err != nil {
			evergreen.Logger.Logf(slogger.ERROR, "Error creating version for project %v: %v", ref.Identifier, err)
		}
		err = sanityCheckOrderNum(v.RevisionOrderNumber, ref.Identifier)
		if err != nil { // something seriously wrong (bad data in db?) so fail now
			panic(err)
		}
		project, err := repoTracker.GetProjectConfig(revision)
		if err != nil {
			projectError, isProjectError := err.(projectConfigError)
			if isProjectError {
				// Store just the stub version with the project errors
				v.Errors = projectError.errors
				if err := v.Insert(); err != nil {
					evergreen.Logger.Logf(slogger.ERROR,
						"Failed storing stub version for project %v: %v", ref.Identifier, err)
					return nil, err
				}
				newestVersion = v
				continue
			} else {
				// Fatal error - don't store the stub
				evergreen.Logger.Logf(slogger.INFO,
					"Failed to get config for project %v at revision %v: %v", ref.Identifier, revision, err)
				return nil, err
			}
		}

		// We have a config, so turn it into a usable yaml string to store with the version doc
		projectYamlBytes, err := yaml.Marshal(project)
		if err != nil {
			return nil, fmt.Errorf("Error marshalling config: %v", err)
		}
		v.Config = string(projectYamlBytes)

		// We rebind newestVersion each iteration, so the last binding will be the newest version
		err = createVersionItems(v, ref, project)
		if err != nil {
			evergreen.Logger.Logf(slogger.ERROR, "Error creating version items for %v in project %v: %v",
				v.Id, ref.Identifier, err)
			return nil, err
		}

		newestVersion = v
		if err != nil {
			evergreen.Logger.Logf(slogger.ERROR, "Unable to store revision %v for project %v: %v:",
				revision, ref.Identifier, err)
			return nil, err
		}
	}
	return
}
Пример #29
0
func (uis *UIServer) modifyVersion(w http.ResponseWriter, r *http.Request) {
	projCtx := MustHaveProjectContext(r)
	user := MustHaveUser(r)
	if projCtx.Project == nil || projCtx.Version == nil {
		http.Error(w, "not found", http.StatusNotFound)
		return
	}

	jsonMap := struct {
		Action   string   `json:"action"`
		Active   bool     `json:"active"`
		Abort    bool     `json:"abort"`
		Priority int64    `json:"priority"`
		TaskIds  []string `json:"task_ids"`
	}{}
	err := util.ReadJSONInto(r.Body, &jsonMap)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	// determine what action needs to be taken
	switch jsonMap.Action {
	case "restart":
		if err = model.RestartVersion(projCtx.Version.Id, jsonMap.TaskIds, jsonMap.Abort, user.Id); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
	case "set_active":
		if jsonMap.Abort {
			if err = model.AbortVersion(projCtx.Version.Id); err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
		}
		if err = model.SetVersionActivation(projCtx.Version.Id, jsonMap.Active, user.Id); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
	case "set_priority":
		if jsonMap.Priority > evergreen.MaxTaskPriority {
			if !uis.isSuperUser(user) {
				http.Error(w, fmt.Sprintf("Insufficient access to set priority %v, can only set priority less than or equal to %v", jsonMap.Priority, evergreen.MaxTaskPriority),
					http.StatusBadRequest)
				return
			}
		}
		if err = model.SetVersionPriority(projCtx.Version.Id, jsonMap.Priority); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
	default:
		uis.WriteJSON(w, http.StatusBadRequest, fmt.Sprintf("Unrecognized action: %v", jsonMap.Action))
		return
	}

	// After the version has been modified, re-load it from DB and send back the up-to-date view
	// to the client.
	projCtx.Version, err = version.FindOne(version.ById(projCtx.Version.Id))
	if err != nil {
		uis.LoggedError(w, r, http.StatusInternalServerError, err)
		return
	}

	versionAsUI := uiVersion{
		Version:   *projCtx.Version,
		RepoOwner: projCtx.ProjectRef.Owner,
		Repo:      projCtx.ProjectRef.Repo,
	}
	dbBuilds, err := build.Find(build.ByIds(projCtx.Version.BuildIds))
	if err != nil {
		uis.LoggedError(w, r, http.StatusInternalServerError, err)
		return
	}

	uiBuilds := make([]uiBuild, 0, len(projCtx.Version.BuildIds))
	for _, build := range dbBuilds {
		buildAsUI := uiBuild{Build: build}
		uiTasks := make([]uiTask, 0, len(build.Tasks))
		for _, t := range build.Tasks {
			uiTasks = append(uiTasks,
				uiTask{
					Task: task.Task{Id: t.Id, Activated: t.Activated,
						StartTime: t.StartTime, TimeTaken: t.TimeTaken, Status: t.Status,
						Details: t.StatusDetails, DisplayName: t.DisplayName},
				})
			if t.Activated {
				versionAsUI.ActiveTasks++
			}
		}
		buildAsUI.Tasks = uiTasks
		uiBuilds = append(uiBuilds, buildAsUI)
	}
	versionAsUI.Builds = uiBuilds
	uis.WriteJSON(w, http.StatusOK, versionAsUI)
}
Пример #30
0
// The FetchRevisions method is used by a RepoTracker to run the pipeline for
// tracking repositories. It performs everything from polling the repository to
// persisting any changes retrieved from the repository reference.
func (repoTracker *RepoTracker) FetchRevisions(numNewRepoRevisionsToFetch int) (
	err error) {
	settings := repoTracker.Settings
	projectRef := repoTracker.ProjectRef
	projectIdentifier := projectRef.String()

	if !projectRef.Enabled {
		evergreen.Logger.Logf(slogger.INFO, "Skipping disabled project “%v”", projectRef)
		return nil
	}

	repository, err := model.FindRepository(projectIdentifier)
	if err != nil {
		return fmt.Errorf("error finding repository '%v': %v",
			projectIdentifier, err)
	}

	var revisions []model.Revision
	var lastRevision string

	if repository != nil {
		lastRevision = repository.LastRevision
	}

	if lastRevision == "" {
		// if this is the first time we're running the tracker for this project,
		// fetch the most recent `numNewRepoRevisionsToFetch` revisions
		evergreen.Logger.Logf(slogger.INFO, "No last recorded repository revision "+
			"for “%v”. Proceeding to fetch most recent %v revisions",
			projectRef, numNewRepoRevisionsToFetch)
		revisions, err = repoTracker.GetRecentRevisions(numNewRepoRevisionsToFetch)
	} else {
		evergreen.Logger.Logf(slogger.INFO, "Last recorded repository revision for "+
			"“%v” is “%v”", projectRef, lastRevision)
		revisions, err = repoTracker.GetRevisionsSince(lastRevision,
			settings.RepoTracker.MaxRepoRevisionsToSearch)
	}

	if err != nil {
		evergreen.Logger.Logf(slogger.ERROR, "error fetching revisions for "+
			"repository “%v”: %v", projectRef, err)
		repoTracker.sendFailureNotification(lastRevision, err)
		return nil
	}

	var lastVersion *version.Version

	if len(revisions) > 0 {
		lastVersion, err = repoTracker.StoreRevisions(revisions)
		if err != nil {
			evergreen.Logger.Logf(slogger.ERROR, "error storing revisions for "+
				"repository %v: %v", projectRef, err)
			return err
		}
		err = model.UpdateLastRevision(lastVersion.Identifier, lastVersion.Revision)
		if err != nil {
			evergreen.Logger.Logf(slogger.ERROR, "error updating last revision for "+
				"repository %v: %v", projectRef, err)
			return err
		}
	} else {
		lastVersion, err = version.FindOne(version.ByMostRecentForRequester(projectIdentifier, evergreen.RepotrackerVersionRequester))
		if err != nil {
			evergreen.Logger.Logf(slogger.ERROR, "error getting most recent version for "+
				"repository %v: %v", projectRef, err)
			return err
		}
	}

	if lastVersion == nil {
		evergreen.Logger.Logf(slogger.WARN, "no version to activate for repository %v", projectIdentifier)
		return nil
	}

	err = repoTracker.activateElapsedBuilds(lastVersion)

	if err != nil {
		evergreen.Logger.Logf(slogger.ERROR, "error activating variants: %v", err)
		return err
	}

	return nil
}