Пример #1
0
func TestGetVariantsWithTask(t *testing.T) {

	Convey("With a project", t, func() {

		project := &Project{
			BuildVariants: []BuildVariant{
				BuildVariant{
					Name: "bv1",
					Tasks: []BuildVariantTask{
						BuildVariantTask{
							Name: "suite1",
						},
					},
				},
				BuildVariant{
					Name: "bv2",
					Tasks: []BuildVariantTask{
						BuildVariantTask{
							Name: "suite1",
						},
						BuildVariantTask{
							Name: "suite2",
						},
					},
				},
				BuildVariant{
					Name: "bv3",
					Tasks: []BuildVariantTask{
						BuildVariantTask{
							Name: "suite2",
						},
					},
				},
			},
		}

		Convey("when getting the build variants where a task applies", func() {

			Convey("it should be run on any build variants where the test is"+
				" specified to run", func() {

				variants := project.GetVariantsWithTask("suite1")
				So(len(variants), ShouldEqual, 2)
				So(util.SliceContains(variants, "bv1"), ShouldBeTrue)
				So(util.SliceContains(variants, "bv2"), ShouldBeTrue)

				variants = project.GetVariantsWithTask("suite2")
				So(len(variants), ShouldEqual, 2)
				So(util.SliceContains(variants, "bv2"), ShouldBeTrue)
				So(util.SliceContains(variants, "bv3"), ShouldBeTrue)

			})

		})

	})
}
Пример #2
0
// creates/returns slice of 'relevant' NotificationKeys a
// notification is relevant if it has at least one recipient
func notificationsToStruct(mciNotification *MCINotification) (notifyOn []NotificationKey) {
	// Get default notifications
	for _, notification := range mciNotification.Notifications {
		if len(notification.Recipients) != 0 {
			// flag the notification as needed
			key := NotificationKey{
				Project:               notification.Project,
				NotificationName:      notification.Name,
				NotificationType:      getType(notification.Name),
				NotificationRequester: evergreen.RepotrackerVersionRequester,
			}

			// prevent duplicate notifications from being sent
			if !util.SliceContains(notifyOn, key) {
				notifyOn = append(notifyOn, key)
			}
		}
	}

	// Get team notifications
	for _, team := range mciNotification.Teams {
		for _, subscription := range team.Subscriptions {
			for _, name := range subscription.NotifyOn {
				key := NotificationKey{
					Project:               subscription.Project,
					NotificationName:      name,
					NotificationType:      getType(name),
					NotificationRequester: evergreen.RepotrackerVersionRequester,
				}

				// prevent duplicate notifications from being sent
				if !util.SliceContains(notifyOn, key) {
					notifyOn = append(notifyOn, key)
				}
			}
		}
	}

	// Get patch notifications
	for _, subscription := range mciNotification.PatchNotifications {
		for _, notification := range subscription.NotifyOn {
			key := NotificationKey{
				Project:               subscription.Project,
				NotificationName:      notification,
				NotificationType:      getType(notification),
				NotificationRequester: evergreen.PatchVersionRequester,
			}

			// prevent duplicate notifications from being sent
			if !util.SliceContains(notifyOn, key) {
				notifyOn = append(notifyOn, key)
			}
		}
	}
	return
}
Пример #3
0
// NewPatchTaskIdTable constructs a new TaskIdTable (map of [variant, task display name]->[task id])
func NewPatchTaskIdTable(proj *Project, v *version.Version, patchConfig TVPairSet) TaskIdTable {
	table := TaskIdTable{}
	processedVariants := map[string]bool{}
	for _, vt := range patchConfig {
		// don't hit the same variant more than once
		if _, ok := processedVariants[vt.Variant]; ok {
			continue
		}
		processedVariants[vt.Variant] = true
		// we must track the project's variants definitions as well,
		// so that we don't create Ids for variants that don't exist.
		projBV := proj.FindBuildVariant(vt.Variant)
		taskNamesForVariant := patchConfig.TaskNames(vt.Variant)
		for _, t := range projBV.Tasks {
			// create Ids for each task that can run on the variant and is requested by the patch.
			if util.SliceContains(taskNamesForVariant, t.Name) {
				taskId := util.CleanName(
					fmt.Sprintf("%v_%v_%v_%v_%v",
						proj.Identifier, projBV.Name, t.Name, v.Revision,
						v.CreateTime.Format(build.IdTimeLayout)))
				table[TVPair{vt.Variant, t.Name}] = taskId
			}
		}
	}
	return table
}
Пример #4
0
// Validate that all necessary params are set and valid.
func (s3pc *S3PutCommand) validateParams() error {
	if s3pc.AwsKey == "" {
		return fmt.Errorf("aws_key cannot be blank")
	}
	if s3pc.AwsSecret == "" {
		return fmt.Errorf("aws_secret cannot be blank")
	}
	if s3pc.LocalFile == "" {
		return fmt.Errorf("local_file cannot be blank")
	}
	if s3pc.RemoteFile == "" {
		return fmt.Errorf("remote_file cannot be blank")
	}
	if s3pc.ContentType == "" {
		return fmt.Errorf("content_type cannot be blank")
	}
	if !util.SliceContains(artifact.ValidVisibilities, s3pc.Visibility) {
		return fmt.Errorf("invalid visibility setting: %v", s3pc.Visibility)
	}

	// make sure the bucket is valid
	if err := validateS3BucketName(s3pc.Bucket); err != nil {
		return fmt.Errorf("%v is an invalid bucket name: %v", s3pc.Bucket, err)
	}

	// make sure the s3 permissions are valid
	if !validS3Permissions(s3pc.Permissions) {
		return fmt.Errorf("permissions '%v' are not valid", s3pc.Permissions)
	}

	return nil
}
// computeScheduledTasksDuration returns the total estimated duration of all
// tasks scheduled to be run in a given task queue
func computeScheduledTasksDuration(
	scheduledDistroTasksData *ScheduledDistroTasksData) (
	scheduledTasksDuration float64, sharedTasksDuration map[string]float64) {

	taskQueueItems := scheduledDistroTasksData.taskQueueItems
	taskRunDistros := scheduledDistroTasksData.taskRunDistros
	tasksAccountedFor := scheduledDistroTasksData.tasksAccountedFor
	currentDistroId := scheduledDistroTasksData.currentDistroId
	sharedTasksDuration = make(map[string]float64)

	// compute the total expected duration for tasks in this queue
	for _, taskQueueItem := range taskQueueItems {
		if !tasksAccountedFor[taskQueueItem.Id] {
			scheduledTasksDuration += taskQueueItem.ExpectedDuration.Seconds()
			tasksAccountedFor[taskQueueItem.Id] = true
		}

		// if the task can be run on multiple distros - including this one - add
		// it to the total duration of 'shared tasks' for the distro and all
		// other distros it can be run on
		distroIds, ok := taskRunDistros[taskQueueItem.Id]
		if ok && util.SliceContains(distroIds, currentDistroId) {
			for _, distroId := range distroIds {
				sharedTasksDuration[distroId] +=
					taskQueueItem.ExpectedDuration.Seconds()
			}
		}
	}
	return
}
Пример #6
0
Файл: perf.go Проект: 3rf/perf
func (pp *PerfPlugin) GetPanelConfig() (*plugin.PanelConfig, error) {
	root := plugin.StaticWebRootFromSourceFile()
	panelHTML, err := ioutil.ReadFile(root + "/task_perf_data.html")
	if err != nil {
		return nil, fmt.Errorf("Can't load panel html file: %v", err)
	}

	return &plugin.PanelConfig{
		StaticRoot: plugin.StaticWebRootFromSourceFile(),
		Panels: []plugin.UIPanel{
			{
				Includes:  includes,
				Page:      plugin.TaskPage,
				Position:  plugin.PageCenter,
				PanelHTML: template.HTML(panelHTML),
				DataFunc: func(context plugin.UIContext) (interface{}, error) {
					return struct {
						Enabled bool `json:"enabled"`
					}{util.SliceContains(pp.Projects, context.ProjectRef.Identifier)}, nil
				},
			},
		},
	}, nil
	return nil, nil
}
Пример #7
0
func applyPatch(patch *service.RestPatch, rootCloneDir string, conf *model.Project, variant *model.BuildVariant) error {
	// patch sets and contain multiple patches, some of them for modules
	for _, patchPart := range patch.Patches {
		var dir string
		if patchPart.ModuleName == "" {
			// if patch is not part of a module, just apply patch against src root
			dir = rootCloneDir
		} else {
			fmt.Println("Applying patches for module", patchPart.ModuleName)
			// if patch is part of a module, apply patch in module root
			module, err := conf.GetModuleByName(patchPart.ModuleName)
			if err != nil || module == nil {
				return fmt.Errorf("can't find module %v: %v", patchPart.ModuleName, err)
			}

			// skip the module if this build variant does not use it
			if !util.SliceContains(variant.Modules, module.Name) {
				continue
			}

			dir = filepath.Join(rootCloneDir, module.Prefix, module.Name)
		}

		args := []string{"apply", "--whitespace=fix"}
		applyCmd := exec.Command("git", args...)
		applyCmd.Stdout, applyCmd.Stderr, applyCmd.Dir = os.Stdout, os.Stderr, dir
		applyCmd.Stdin = bytes.NewReader([]byte(patchPart.PatchSet.Patch))
		err := applyCmd.Run()
		if err != nil {
			return err
		}
	}
	return nil
}
Пример #8
0
// Given a patch version and a list of task names, creates a new task with
// the given name for each variant, if applicable.
func AddNewTasksForPatch(p *patch.Patch, patchVersion *version.Version, project *Project,
	taskNames []string) error {
	// create new tasks for all of the added patch tasks
	var newTasks []string
	for _, taskName := range taskNames {
		if !util.SliceContains(p.Tasks, taskName) {
			newTasks = append(newTasks, taskName)
		}
	}

	// add tasks to the patch in the db
	if err := p.AddTasks(taskNames); err != nil {
		return err
	}

	// add new tasks to the build, if they exist
	if len(newTasks) > 0 {
		builds, err := build.Find(build.ByIds(patchVersion.BuildIds))
		if err != nil {
			return err
		}

		for _, b := range builds {
			if _, err = AddTasksToBuild(&b, project, patchVersion, newTasks); err != nil {
				return err
			}
		}
	}
	return nil
}
Пример #9
0
// confirm asks the user a yes/no question and returns true/false if they reply with y/yes/n/no.
// if defaultYes is true, allows user to just hit enter without typing an explicit yes.
func confirm(message string, defaultYes bool) bool {
	reply := ""
	yes := []string{"y", "yes"}
	no := []string{"n", "no"}
	if defaultYes {
		yes = append(yes, "")
	}
	for {
		reply = prompt(message)
		if util.SliceContains(yes, strings.ToLower(reply)) {
			return true
		}
		if util.SliceContains(no, strings.ToLower(reply)) {
			return false
		}
	}
}
Пример #10
0
// ShouldContainResembling tests whether a slice contains an element that DeepEquals
// the expected input.
func ShouldContainResembling(actual interface{}, expected ...interface{}) string {
	if len(expected) != 1 {
		return "ShouldContainResembling takes 1 argument"
	}
	if !util.SliceContains(actual, expected[0]) {
		return fmt.Sprintf("%#v does not contain %#v", actual, expected[0])
	}
	return ""
}
Пример #11
0
func (self *S3GetCommand) shouldRunForVariant(buildVariantName string) bool {
	//No buildvariant filter, so run always
	if len(self.BuildVariants) == 0 {
		return true
	}

	//Only run if the buildvariant specified appears in our list.
	return util.SliceContains(self.BuildVariants, buildVariantName)
}
Пример #12
0
func (self *BuildEmail) ShouldSkip(skipVariants []string) bool {
	buildVariant := self.Trigger.Current.BuildVariant
	if util.SliceContains(skipVariants, buildVariant) {
		evergreen.Logger.Logf(slogger.DEBUG, "Skipping buildvariant %v “%v” notification: “%v”",
			buildVariant, self.Trigger.Key.NotificationName, self.Subject)
		return true
	}
	return false
}
Пример #13
0
// get the failed task(s) for a given build
func getFailedTasks(current *build.Build, notificationName string) (failedTasks []build.TaskCache) {
	if util.SliceContains(buildFailureKeys, notificationName) {
		for _, task := range current.Tasks {
			if task.Status == evergreen.TaskFailed {
				failedTasks = append(failedTasks, task)
			}
		}
	}
	return
}
Пример #14
0
// Given the patch version and a list of build variants, creates new builds
// with the patch's tasks.
func AddNewBuildsForPatch(p *patch.Patch, patchVersion *version.Version, project *Project,
	buildVariants []string) (*version.Version, error) {

	// compute a list of the newly added build variants
	var newVariants []string
	for _, variant := range buildVariants {
		if !util.SliceContains(p.BuildVariants, variant) {
			newVariants = append(newVariants, variant)
		}
	}

	// update the patch
	if err := p.AddBuildVariants(buildVariants); err != nil {
		return nil, err
	}

	newBuildIds := make([]string, 0)
	newBuildStatuses := make([]version.BuildStatus, 0)
	tt := BuildTaskIdTable(project, patchVersion)
	for _, buildVariant := range newVariants {
		evergreen.Logger.Logf(slogger.INFO,
			"Creating build for version %v, buildVariant %v, activated = %v",
			patchVersion.Id, buildVariant, p.Activated)
		buildId, err := CreateBuildFromVersion(
			project, patchVersion, tt, buildVariant, p.Activated, p.Tasks)
		if err != nil {
			return nil, err
		}
		newBuildIds = append(newBuildIds, buildId)

		newBuildStatuses = append(newBuildStatuses,
			version.BuildStatus{
				BuildVariant: buildVariant,
				BuildId:      buildId,
				Activated:    p.Activated,
			},
		)
		patchVersion.BuildIds = append(patchVersion.BuildIds, buildId)
	}

	err := version.UpdateOne(
		bson.M{version.IdKey: patchVersion.Id},
		bson.M{
			"$push": bson.M{
				version.BuildIdsKey:      bson.M{"$each": newBuildIds},
				version.BuildVariantsKey: bson.M{"$each": newBuildStatuses},
			},
		},
	)
	if err != nil {
		return nil, err
	}

	return patchVersion, nil
}
Пример #15
0
func (uis *UIServer) modifyHosts(w http.ResponseWriter, r *http.Request) {
	_ = MustHaveUser(r)

	opts := &uiParams{}
	err := util.ReadJSONInto(r.Body, opts)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	hostIds := opts.HostIds
	if len(hostIds) == 1 && strings.TrimSpace(hostIds[0]) == "" {
		http.Error(w, "No host ID's found in request", http.StatusBadRequest)
		return
	}

	// fetch all relevant hosts
	hosts, err := host.Find(host.ByIds(hostIds))

	if err != nil {
		uis.LoggedError(w, r, http.StatusInternalServerError, fmt.Errorf("Error finding hosts: %v", err))
		return
	}
	if len(hosts) == 0 {
		http.Error(w, "No matching hosts found.", http.StatusBadRequest)
		return
	}

	// determine what action needs to be taken
	switch opts.Action {
	case "updateStatus":
		newStatus := opts.Status
		if !util.SliceContains(validUpdateToStatuses, newStatus) {
			http.Error(w, fmt.Sprintf("Invalid status: %v", opts.Status), http.StatusBadRequest)
			return
		}
		numHostsUpdated := 0

		for _, host := range hosts {
			err := host.SetStatus(newStatus)
			if err != nil {
				uis.LoggedError(w, r, http.StatusInternalServerError, fmt.Errorf("Error updating host %v", err))
				return
			}
			numHostsUpdated += 1
		}
		msg := NewSuccessFlash(fmt.Sprintf("%v host(s) status successfully updated to '%v'",
			numHostsUpdated, newStatus))
		PushFlash(uis.CookieStore, r, w, msg)
		return
	default:
		http.Error(w, fmt.Sprintf("Unrecognized action: %v", opts.Action), http.StatusBadRequest)
		return
	}
}
Пример #16
0
// IsSuperUser verifies that a given user has super user permissions.
// A user has these permission if they are in the super users list or if the list is empty,
// in which case all users are super users.
func IsSuperUser(settings evergreen.Settings, u User) bool {
	if u == nil {
		return false
	}
	if util.SliceContains(settings.SuperUsers, u.Username()) ||
		len(settings.SuperUsers) == 0 {
		return true
	}

	return false

}
Пример #17
0
// contains returns whether a value is contained by a definition.
// Note that a value that doesn't contain every matrix axis will still
// be evaluated based on the axes that exist.
func (mdef matrixDefinition) contains(mv matrixValue) bool {
	for k, v := range mv {
		axis, ok := mdef[k]
		if !ok {
			return false
		}
		if !util.SliceContains(axis, v) {
			return false
		}
	}
	return true
}
Пример #18
0
// isSuperUser verifies that a given user has super user permissions.
// A user has these permission if they are in the super users list or if the list is empty,
// in which case all users are super users.
func (uis *UIServer) isSuperUser(u *user.DBUser) bool {
	if u == nil {
		return false
	}
	if util.SliceContains(uis.Settings.SuperUsers, u.Id) ||
		len(uis.Settings.SuperUsers) == 0 {
		return true
	}

	return false

}
Пример #19
0
func validS3Permissions(perm string) bool {
	return util.SliceContains(
		[]s3.ACL{
			s3.Private,
			s3.PublicRead,
			s3.PublicReadWrite,
			s3.AuthenticatedRead,
			s3.BucketOwnerRead,
			s3.BucketOwnerFull,
		},
		s3.ACL(perm),
	)
}
Пример #20
0
// get the specific failed test(s) for this task
func getFailedTests(current *model.Task, notificationName string) (failedTests []model.TestResult) {
	if util.SliceContains(taskFailureKeys, notificationName) {
		for _, test := range current.TestResults {
			if test.Status == "fail" {
				// get the base name for windows/non-windows paths
				test.TestFile = path.Base(strings.Replace(test.TestFile, "\\", "/", -1))
				failedTests = append(failedTests, test)
			}
		}
	}

	return
}
Пример #21
0
// create a slice of all valid distro names
func getDistroIds() ([]string, error) {
	// create a slice of all known distros
	distros, err := distro.Find(distro.All)
	if err != nil {
		return nil, err
	}
	distroIds := []string{}
	for _, d := range distros {
		if !util.SliceContains(distroIds, d.Id) {
			distroIds = append(distroIds, d.Id)
		}
	}
	return distroIds, nil
}
Пример #22
0
// S3Copy is responsible for carrying out the core of the S3CopyPlugin's
// function - it makes an API calls to copy a given staged file to it's final
// production destination
func (scc *S3CopyCommand) S3Copy(taskConfig *model.TaskConfig,
	pluginLogger plugin.Logger, pluginCom plugin.PluginCommunicator) error {
	for _, s3CopyFile := range scc.S3CopyFiles {
		if len(s3CopyFile.BuildVariants) > 0 && !util.SliceContains(
			s3CopyFile.BuildVariants, taskConfig.BuildVariant.Name) {
			continue
		}

		pluginLogger.LogExecution(slogger.INFO, "Making API push copy call to "+
			"transfer %v/%v => %v/%v", s3CopyFile.Source.Bucket,
			s3CopyFile.Source.Path, s3CopyFile.Destination.Bucket,
			s3CopyFile.Destination.Path)

		s3CopyReq := S3CopyRequest{
			AwsKey:              scc.AwsKey,
			AwsSecret:           scc.AwsSecret,
			S3SourceBucket:      s3CopyFile.Source.Bucket,
			S3SourcePath:        s3CopyFile.Source.Path,
			S3DestinationBucket: s3CopyFile.Destination.Bucket,
			S3DestinationPath:   s3CopyFile.Destination.Path,
			S3DisplayName:       s3CopyFile.DisplayName,
		}
		resp, err := pluginCom.TaskPostJSON(s3CopyAPIEndpoint, s3CopyReq)
		if resp != nil {
			defer resp.Body.Close()
		}
		if resp != nil && resp.StatusCode != http.StatusOK {
			body, _ := ioutil.ReadAll(resp.Body)
			return fmt.Errorf("S3 push copy failed (%v): %v",
				resp.StatusCode, string(body))
		}
		if err != nil {
			body, _ := ioutil.ReadAll(resp.Body)
			return fmt.Errorf("S3 push copy failed (%v): %v",
				resp.StatusCode, string(body))
		}
		pluginLogger.LogExecution(slogger.INFO, "API push copy call succeeded")
		err = scc.AttachTaskFiles(pluginLogger, pluginCom, s3CopyReq)
		if err != nil {
			body, readAllErr := ioutil.ReadAll(resp.Body)
			if readAllErr != nil {
				return fmt.Errorf("Error: %v", err)
			}
			return fmt.Errorf("Error: %v, (%v): %v",
				resp.StatusCode, err, string(body))
		}
	}
	return nil
}
Пример #23
0
// create a slice of all valid distro names
func populateDistroIds() *ValidationError {
	// create a slice of all known distros
	distros, err := distro.Find(distro.All)
	if err != nil {
		return &ValidationError{
			Message: fmt.Sprintf("error finding distros: %v", err),
			Level:   Error,
		}
	}
	distroIds = []string{}
	for _, d := range distros {
		if !util.SliceContains(distroIds, d.Id) {
			distroIds = append(distroIds, d.Id)
		}
	}
	return nil
}
Пример #24
0
func (uis *UIServer) modifyHost(w http.ResponseWriter, r *http.Request) {
	_ = MustHaveUser(r)

	vars := mux.Vars(r)
	id := vars["host_id"]

	host, err := host.FindOne(host.ById(id))
	if err != nil {
		uis.LoggedError(w, r, http.StatusInternalServerError, err)
		return
	}

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

	opts := &uiParams{}
	err = util.ReadJSONInto(r.Body, opts)
	if err != nil {
		uis.LoggedError(w, r, http.StatusBadRequest, err)
		return
	}

	// determine what action needs to be taken
	switch opts.Action {
	case "updateStatus":
		currentStatus := host.Status
		newStatus := opts.Status
		if !util.SliceContains(validUpdateToStatuses, newStatus) {
			http.Error(w, fmt.Sprintf("'%v' is not a valid status", newStatus), http.StatusBadRequest)
			return
		}
		err := host.SetStatus(newStatus)
		if err != nil {
			uis.LoggedError(w, r, http.StatusInternalServerError, fmt.Errorf("Error updating host: %v", err))
			return
		}
		msg := NewSuccessFlash(fmt.Sprintf("Host status successfully updated from '%v' to '%v'", currentStatus, host.Status))
		PushFlash(uis.CookieStore, r, w, msg)
		uis.WriteJSON(w, http.StatusOK, "Successfully updated host status")
	default:
		uis.WriteJSON(w, http.StatusBadRequest, fmt.Sprintf("Unrecognized action: %v", opts.Action))
	}
}
Пример #25
0
// createTasksForBuild creates all of the necessary tasks for the build.  Returns a
// slice of all of the tasks created, as well as an error if any occurs.
// The slice of tasks will be in the same order as the project's specified tasks
// appear in the specified build variant.
func createTasksForBuild(project *Project, buildVariant *BuildVariant,
	b *build.Build, v *version.Version, tt TaskIdTable, taskNames []string) ([]*Task, error) {

	// the list of tasks we should create.  if tasks are passed in, then
	// use those, else use the default set
	tasksToCreate := []BuildVariantTask{}
	createAll := len(taskNames) == 0
	for _, task := range buildVariant.Tasks {
		// get the task spec out of the project
		taskSpec := project.GetSpecForTask(task.Name)

		// sanity check that the config isn't malformed
		if taskSpec.Name == "" {
			return nil, fmt.Errorf("config is malformed: variant '%v' runs "+
				"task called '%v' but no such task exists for repo %v for "+
				"version %v", buildVariant.Name, task.Name, project.Identifier, v.Id)
		}

		// update task document with spec fields
		task.Populate(taskSpec)

		if ((task.Patchable != nil && *task.Patchable == false) || task.Name == evergreen.PushStage) && //TODO remove PushStage
			b.Requester == evergreen.PatchVersionRequester {
			continue
		}
		if createAll || util.SliceContains(taskNames, task.Name) {
			tasksToCreate = append(tasksToCreate, task)
		}
	}

	// if any tasks already exist in the build, add them to the id table
	// so they can be used as dependencies
	for _, task := range b.Tasks {
		tt.AddId(b.BuildVariant, task.DisplayName, task.Id)
	}

	// create and insert all of the actual tasks
	tasks := make([]*Task, 0, len(tasksToCreate))
	for _, task := range tasksToCreate {
		newTask := createOneTask(tt.GetId(b.BuildVariant, task.Name), task, project, buildVariant, b, v)

		// set Tags based on the spec
		newTask.Tags = project.GetSpecForTask(task.Name).Tags

		// set the new task's dependencies
		// TODO encapsulate better
		if len(task.DependsOn) == 1 &&
			task.DependsOn[0].Name == AllDependencies &&
			task.DependsOn[0].Variant != AllVariants {
			// the task depends on all of the other tasks in the build
			newTask.DependsOn = make([]Dependency, 0, len(tasksToCreate)-1)
			for _, dep := range tasksToCreate {
				status := evergreen.TaskSucceeded
				if task.DependsOn[0].Status != "" {
					status = task.DependsOn[0].Status
				}
				newDep := Dependency{
					TaskId: tt.GetId(b.BuildVariant, dep.Name),
					Status: status,
				}
				if dep.Name != newTask.DisplayName {
					newTask.DependsOn = append(newTask.DependsOn, newDep)
				}
			}
		} else {
			// the task has specific dependencies
			newTask.DependsOn = make([]Dependency, 0, len(task.DependsOn))
			for _, dep := range task.DependsOn {
				// only add as a dependency if the dependency is valid/exists
				status := evergreen.TaskSucceeded
				if dep.Status != "" {
					status = dep.Status
				}
				bv := b.BuildVariant
				if dep.Variant != "" {
					bv = dep.Variant
				}

				newDeps := []Dependency{}

				if dep.Variant == AllVariants {
					// for * case, we need to add all variants of the task
					var ids []string
					if dep.Name != AllDependencies {
						ids = tt.GetIdsForAllVariants(b.BuildVariant, dep.Name)
					} else {
						// edge case where variant and task are both *
						ids = tt.GetIdsForAllTasks(b.BuildVariant, newTask.DisplayName)
					}
					for _, id := range ids {
						newDeps = append(newDeps, Dependency{TaskId: id, Status: status})
					}
				} else {
					// general case
					newDep := Dependency{
						TaskId: tt.GetId(bv, dep.Name),
						Status: status,
					}
					if newDep.TaskId != "" {
						newDeps = []Dependency{newDep}
					}
				}

				newTask.DependsOn = append(newTask.DependsOn, newDeps...)
			}
		}

		// append the task to the list of the created tasks
		tasks = append(tasks, newTask)
	}

	// Set the NumDependents field
	// Existing tasks in the db and tasks in other builds are not updated
	setNumDeps(tasks)

	// return all of the tasks created
	return tasks, nil
}
Пример #26
0
// Ensures that:
// 1. a referenced task within a buildvariant task object exists in
// the set of project tasks
// 2. any referenced distro exists within the current setting's distro directory
func ensureReferentialIntegrity(project *model.Project) []ValidationError {
	errs := []ValidationError{}
	// create a set of all the task names
	allTaskNames := map[string]bool{}
	for _, task := range project.Tasks {
		allTaskNames[task.Name] = true
	}

	for _, buildVariant := range project.BuildVariants {
		buildVariantTasks := map[string]bool{}
		for _, task := range buildVariant.Tasks {
			if _, ok := allTaskNames[task.Name]; !ok {
				if task.Name == "" {
					errs = append(errs,
						ValidationError{
							Message: fmt.Sprintf("tasks for buildvariant '%v' "+
								"in project '%v' must each have a name field",
								project.Identifier, buildVariant.Name),
						},
					)
				} else {
					errs = append(errs,
						ValidationError{
							Message: fmt.Sprintf("buildvariant '%v' in "+
								"project '%v' references a non-existent "+
								"task '%v'", buildVariant.Name,
								project.Identifier, task.Name),
						},
					)
				}
			}
			buildVariantTasks[task.Name] = true
			for _, distroId := range task.Distros {
				if !util.SliceContains(distroIds, distroId) {
					errs = append(errs,
						ValidationError{
							Message: fmt.Sprintf("task '%v' in buildvariant "+
								"'%v' in project '%v' references a "+
								"non-existent distro '%v'.\nValid distros "+
								"include: \n\t- %v", task.Name,
								buildVariant.Name, project.Identifier,
								distroId, strings.Join(distroIds, "\n\t- ")),
						},
					)
				}
			}
		}
		for _, distroId := range buildVariant.RunOn {
			if !util.SliceContains(distroIds, distroId) {
				errs = append(errs,
					ValidationError{
						Message: fmt.Sprintf("buildvariant '%v' in project "+
							"'%v' references a non-existent distro '%v'.\n"+
							"Valid distros include: \n\t- %v",
							buildVariant.Name, project.Identifier, distroId,
							strings.Join(distroIds, "\n\t- ")),
					},
				)
			}
		}
	}
	return errs
}
Пример #27
0
// This function is responsible for validating the notifications file
func ValidateNotifications(configName string, mciNotification *MCINotification) error {
	evergreen.Logger.Logf(slogger.INFO, "Validating notifications...")
	allNotifications := []string{}

	projectNameToBuildVariants, err := findProjectBuildVariants(configName)
	if err != nil {
		return fmt.Errorf("Error loading project build variants: %v", err)
	}

	// Validate default notification recipients
	for _, notification := range mciNotification.Notifications {
		if notification.Project == "" {
			return fmt.Errorf("Must specify a project for each notification - see %v", notification.Name)
		}

		buildVariants, ok := projectNameToBuildVariants[notification.Project]
		if !ok {
			return fmt.Errorf("Notifications validation failed: "+
				"project `%v` not found", notification.Project)
		}

		// ensure all supplied build variants are valid
		for _, buildVariant := range notification.SkipVariants {
			if !util.SliceContains(buildVariants, buildVariant) {
				return fmt.Errorf("Nonexistent buildvariant - ”%v” - specified for ”%v” notification", buildVariant, notification.Name)
			}
		}

		allNotifications = append(allNotifications, notification.Name)
	}

	// Validate team name and addresses
	for _, team := range mciNotification.Teams {
		if team.Name == "" {
			return fmt.Errorf("Each notification team must have a name")
		}

		for _, subscription := range team.Subscriptions {
			for _, notification := range subscription.NotifyOn {
				if !util.SliceContains(allNotifications, notification) {
					return fmt.Errorf("Team ”%v” contains a non-existent subscription - %v", team.Name, notification)
				}
			}
			for _, buildVariant := range subscription.SkipVariants {
				buildVariants, ok := projectNameToBuildVariants[subscription.Project]
				if !ok {
					return fmt.Errorf("Teams validation failed: project `%v` not found", subscription.Project)
				}

				if !util.SliceContains(buildVariants, buildVariant) {
					return fmt.Errorf("Nonexistent buildvariant - ”%v” - specified for team ”%v” ", buildVariant, team.Name)
				}
			}
		}
	}

	// Validate patch notifications
	for _, subscription := range mciNotification.PatchNotifications {
		for _, notification := range subscription.NotifyOn {
			if !util.SliceContains(allNotifications, notification) {
				return fmt.Errorf("Nonexistent patch notification - ”%v” - specified", notification)
			}
		}
	}

	// validate the patch notification buildvariatns
	for _, subscription := range mciNotification.PatchNotifications {
		buildVariants, ok := projectNameToBuildVariants[subscription.Project]
		if !ok {
			return fmt.Errorf("Patch notification build variants validation failed: "+
				"project `%v` not found", subscription.Project)
		}

		for _, buildVariant := range subscription.SkipVariants {
			if !util.SliceContains(buildVariants, buildVariant) {
				return fmt.Errorf("Nonexistent buildvariant - ”%v” - specified for patch notifications", buildVariant)
			}
		}
	}

	// all good!
	return nil
}
Пример #28
0
// RunOnVariant returns true if the plugin command should run on variant; returns false otherwise
func (p PluginCommandConf) RunOnVariant(variant string) bool {
	return len(p.Variants) == 0 || util.SliceContains(p.Variants, variant)
}
Пример #29
0
// applyPatch is used by the agent to copy patch data onto disk
// and then call the necessary git commands to apply the patch file
func (gapc *GitApplyPatchCommand) applyPatch(conf *model.TaskConfig,
	patch *patch.Patch, pluginLogger plugin.Logger) error {

	// patch sets and contain multiple patches, some of them for modules
	for _, patchPart := range patch.Patches {
		var dir string
		if patchPart.ModuleName == "" {
			// if patch is not part of a module, just apply patch against src root
			dir = gapc.Directory
			pluginLogger.LogExecution(slogger.INFO, "Applying patch with git...")
		} else {
			// if patch is part of a module, apply patch in module root
			module, err := conf.Project.GetModuleByName(patchPart.ModuleName)
			if err != nil {
				return fmt.Errorf("Error getting module: %v", err)
			}
			if module == nil {
				return fmt.Errorf("Module not found: %v", patchPart.ModuleName)
			}

			// skip the module if this build variant does not use it
			if !util.SliceContains(conf.BuildVariant.Modules, module.Name) {
				pluginLogger.LogExecution(slogger.INFO, "Skipping patch for"+
					" module %v, since the current build variant does not"+
					" use it", module.Name)
				continue
			}

			dir = filepath.Join(gapc.Directory, module.Prefix, module.Name)
			pluginLogger.LogExecution(slogger.INFO, "Applying module patch with git...")
		}

		// create a temporary folder and store patch files on disk,
		// for later use in shell script
		tempFile, err := ioutil.TempFile("", "mcipatch_")
		if err != nil {
			return err
		}
		defer tempFile.Close()
		_, err = io.WriteString(tempFile, patchPart.PatchSet.Patch)
		if err != nil {
			return err
		}
		tempAbsPath := tempFile.Name()

		// this applies the patch using the patch files in the temp directory
		patchCommandStrings := []string{
			fmt.Sprintf("set -o verbose"),
			fmt.Sprintf("set -o errexit"),
			fmt.Sprintf("ls"),
			fmt.Sprintf("cd '%v'", dir),
			fmt.Sprintf("git checkout '%v'", patchPart.Githash),
			fmt.Sprintf("git apply --check --whitespace=fix '%v'", tempAbsPath),
			fmt.Sprintf("git apply --stat '%v'", tempAbsPath),
			fmt.Sprintf("git apply --whitespace=fix < '%v'", tempAbsPath),
		}

		cmdsJoined := strings.Join(patchCommandStrings, "\n")
		patchCmd := &command.LocalCommand{
			CmdString:        cmdsJoined,
			WorkingDirectory: conf.WorkDir,
			Stdout:           pluginLogger.GetTaskLogWriter(slogger.INFO),
			Stderr:           pluginLogger.GetTaskLogWriter(slogger.ERROR),
			ScriptMode:       true,
		}

		err = patchCmd.Run()
		if err != nil {
			return err
		}
		pluginLogger.Flush()
	}
	return nil
}
Пример #30
0
// isAdmin returns false if the user is nil or if its id is not
// located in ProjectRef's Admins field.
func isAdmin(u *user.DBUser, project *model.ProjectRef) bool {
	if u == nil {
		return false
	}
	return util.SliceContains(project.Admins, u.Id)
}