// Fetch versions until 'numVersionElements' elements are created, including // elements consisting of multiple versions rolled-up into one. // The skip value indicates how many versions back in time should be skipped // before starting to fetch versions, the project indicates which project the // returned versions should be a part of. func getVersionsAndVariants(skip, numVersionElements int, project *model.Project) (versionVariantData, error) { // the final array of versions to return finalVersions := []waterfallVersion{} // keep track of the build variants we see bvSet := map[string]bool{} waterfallRows := map[string]waterfallRow{} // build variant mappings - used so we can store the display name as // the build variant field of a build buildVariantMappings := project.GetVariantMappings() // keep track of the last rolled-up version, so inactive versions can // be added var lastRolledUpVersion *waterfallVersion = nil // loop until we have enough from the db for len(finalVersions) < numVersionElements { // fetch the versions and associated builds versionsFromDB, buildsByVersion, err := fetchVersionsAndAssociatedBuilds(project, skip, numVersionElements) if err != nil { return versionVariantData{}, fmt.Errorf("error fetching versions and builds:"+ " %v", err) } // if we've reached the beginning of all versions if len(versionsFromDB) == 0 { break } // to fetch started tasks and failed tests for providing additional context // in a tooltip failedAndStartedTaskIds := []string{} // update the amount skipped skip += len(versionsFromDB) // create the necessary versions, rolling up inactive ones for _, versionFromDB := range versionsFromDB { // if we have hit enough versions, break out if len(finalVersions) == numVersionElements { break } // the builds for the version buildsInVersion := buildsByVersion[versionFromDB.Id] // see if there are any active tasks in the version versionActive := anyActiveTasks(buildsInVersion) // add any represented build variants to the set and initialize rows for _, b := range buildsInVersion { bvSet[b.BuildVariant] = true buildVariant := waterfallBuildVariant{ Id: b.BuildVariant, DisplayName: buildVariantMappings[b.BuildVariant], } if buildVariant.DisplayName == "" { buildVariant.DisplayName = b.BuildVariant + " (removed)" } if _, ok := waterfallRows[b.BuildVariant]; !ok { waterfallRows[b.BuildVariant] = waterfallRow{ Builds: map[string]waterfallBuild{}, BuildVariant: buildVariant, } } } // if it is inactive, roll up the version and don't create any // builds for it if !versionActive { if lastRolledUpVersion == nil { lastRolledUpVersion = &waterfallVersion{RolledUp: true, RevisionOrderNumber: versionFromDB.RevisionOrderNumber} } // add the version metadata into the last rolled-up version lastRolledUpVersion.Ids = append(lastRolledUpVersion.Ids, versionFromDB.Id) lastRolledUpVersion.Authors = append(lastRolledUpVersion.Authors, versionFromDB.Author) lastRolledUpVersion.Errors = append( lastRolledUpVersion.Errors, waterfallVersionError{versionFromDB.Errors}) lastRolledUpVersion.Warnings = append( lastRolledUpVersion.Warnings, waterfallVersionError{versionFromDB.Warnings}) lastRolledUpVersion.Messages = append( lastRolledUpVersion.Messages, versionFromDB.Message) lastRolledUpVersion.Ignoreds = append( lastRolledUpVersion.Ignoreds, versionFromDB.Ignored) lastRolledUpVersion.CreateTimes = append( lastRolledUpVersion.CreateTimes, versionFromDB.CreateTime) lastRolledUpVersion.Revisions = append( lastRolledUpVersion.Revisions, versionFromDB.Revision) // move on to the next version continue } // add a pending rolled-up version, if it exists if lastRolledUpVersion != nil { finalVersions = append(finalVersions, *lastRolledUpVersion) lastRolledUpVersion = nil } // if we have hit enough versions, break out if len(finalVersions) == numVersionElements { break } // if the version can not be rolled up, create a fully fledged // version for it activeVersion := waterfallVersion{ Ids: []string{versionFromDB.Id}, Messages: []string{versionFromDB.Message}, Authors: []string{versionFromDB.Author}, CreateTimes: []time.Time{versionFromDB.CreateTime}, Revisions: []string{versionFromDB.Revision}, Errors: []waterfallVersionError{{versionFromDB.Errors}}, Warnings: []waterfallVersionError{{versionFromDB.Warnings}}, Ignoreds: []bool{versionFromDB.Ignored}, RevisionOrderNumber: versionFromDB.RevisionOrderNumber, } // add the builds to the waterfall row for _, b := range buildsInVersion { currentRow := waterfallRows[b.BuildVariant] buildForWaterfall := waterfallBuild{ Id: b.Id, Version: versionFromDB.Id, } tasks, statusCount := createWaterfallTasks(b.Tasks) buildForWaterfall.Tasks = tasks buildForWaterfall.TaskStatusCount = statusCount currentRow.Builds[versionFromDB.Id] = buildForWaterfall waterfallRows[b.BuildVariant] = currentRow for _, task := range buildForWaterfall.Tasks { if task.Status == evergreen.TaskFailed || task.Status == evergreen.TaskStarted { failedAndStartedTaskIds = append(failedAndStartedTaskIds, task.Id) } } } // add the version finalVersions = append(finalVersions, activeVersion) } failedAndStartedTasks, err := task.Find(task.ByIds(failedAndStartedTaskIds)) if err != nil { return versionVariantData{}, fmt.Errorf("error fetching failed tasks:"+ " %v", err) } addFailedAndStartedTests(waterfallRows, failedAndStartedTasks) } // if the last version was rolled-up, add it if lastRolledUpVersion != nil { finalVersions = append(finalVersions, *lastRolledUpVersion) } // create the list of display names for the build variants represented buildVariants := waterfallBuildVariants{} for name := range bvSet { displayName := buildVariantMappings[name] if displayName == "" { displayName = name + " (removed)" } buildVariants = append(buildVariants, waterfallBuildVariant{Id: name, DisplayName: displayName}) } return versionVariantData{ Rows: waterfallRows, Versions: finalVersions, BuildVariants: buildVariants, }, nil }
// Fetch versions until 'numVersionElements' elements are created, including // elements consisting of multiple versions rolled-up into one. // The skip value indicates how many versions back in time should be skipped // before starting to fetch versions, the project indicates which project the // returned versions should be a part of. func getVersionsAndVariants(skip int, numVersionElements int, project *model.Project) ([]waterfallVersion, []string, error) { // the final array of versions to return finalVersions := []waterfallVersion{} // keep track of the build variants we see bvSet := map[string]bool{} // build variant mappings - used so we can store the display name as // the build variant field of a build buildVariantMappings := project.GetVariantMappings() // keep track of the last rolled-up version, so inactive versions can // be added var lastRolledUpVersion *waterfallVersion = nil // loop until we have enough from the db for len(finalVersions) < numVersionElements { // fetch the versions and associated builds versionsFromDB, buildsByVersion, err := fetchVersionsAndAssociatedBuilds(project, skip, numVersionElements) if err != nil { return nil, nil, fmt.Errorf("error fetching versions and builds:"+ " %v", err) } // if we've reached the beginning of all versions if len(versionsFromDB) == 0 { break } // update the amount skipped skip += len(versionsFromDB) // create the necessary versions, rolling up inactive ones for _, version := range versionsFromDB { // if we have hit enough versions, break out if len(finalVersions) == numVersionElements { break } // the builds for the version buildsInVersion := buildsByVersion[version.Id] // see if there are any active tasks in the version versionActive := anyActiveTasks(buildsInVersion) // add any represented build variants to the set for _, build := range buildsInVersion { bvSet[build.BuildVariant] = true } // if it is inactive, roll up the version and don't create any // builds for it if !versionActive { if lastRolledUpVersion == nil { lastRolledUpVersion = &waterfallVersion{RolledUp: true} } // add the version metadata into the last rolled-up version lastRolledUpVersion.Ids = append(lastRolledUpVersion.Ids, version.Id) lastRolledUpVersion.Authors = append(lastRolledUpVersion.Authors, version.Author) lastRolledUpVersion.Errors = append( lastRolledUpVersion.Errors, waterfallVersionError{version.Errors}) lastRolledUpVersion.Warnings = append( lastRolledUpVersion.Warnings, waterfallVersionError{version.Warnings}) lastRolledUpVersion.Messages = append( lastRolledUpVersion.Messages, version.Message) lastRolledUpVersion.CreateTimes = append( lastRolledUpVersion.CreateTimes, version.CreateTime) lastRolledUpVersion.Revisions = append( lastRolledUpVersion.Revisions, version.Revision) // move on to the next version continue } // add a pending rolled-up version, if it exists if lastRolledUpVersion != nil { finalVersions = append(finalVersions, *lastRolledUpVersion) lastRolledUpVersion = nil } // if we have hit enough versions, break out if len(finalVersions) == numVersionElements { break } // if the version can not be rolled up, create a fully fledged // version for it activeVersion := waterfallVersion{ Ids: []string{version.Id}, Messages: []string{version.Message}, Authors: []string{version.Author}, CreateTimes: []time.Time{version.CreateTime}, Revisions: []string{version.Revision}, Errors: []waterfallVersionError{ waterfallVersionError{version.Errors}}, Warnings: []waterfallVersionError{ waterfallVersionError{version.Warnings}}, } // add the builds to the version for _, build := range buildsInVersion { buildForWaterfall := waterfallBuild{ Id: build.Id, BuildVariant: buildVariantMappings[build.BuildVariant], } if buildForWaterfall.BuildVariant == "" { buildForWaterfall.BuildVariant = build.BuildVariant + " (removed)" } // add the tasks to the build for _, task := range build.Tasks { taskForWaterfall := waterfallTask{ Id: task.Id, Status: task.Status, StatusDetails: task.StatusDetails, DisplayName: task.DisplayName, Activated: task.Activated, TimeTaken: task.TimeTaken, } // if the task is inactive, set its status to inactive if !task.Activated { taskForWaterfall.Status = InactiveStatus } buildForWaterfall.Tasks = append(buildForWaterfall.Tasks, taskForWaterfall) } activeVersion.Builds = append(activeVersion.Builds, buildForWaterfall) } // add the version finalVersions = append(finalVersions, activeVersion) } } // if the last version was rolled-up, add it if lastRolledUpVersion != nil { finalVersions = append(finalVersions, *lastRolledUpVersion) } // create the list of display names for the build variants represented buildVariants := []string{} for name, _ := range bvSet { displayName := buildVariantMappings[name] if displayName == "" { displayName = name + " (removed)" } buildVariants = append(buildVariants, displayName) } return finalVersions, buildVariants, nil }