github.com/billybanfield/evergreen@v0.0.0-20170525200750-eeee692790f7/model/context.go (about)

     1  package model
     2  
     3  import (
     4  	"github.com/evergreen-ci/evergreen/model/build"
     5  	"github.com/evergreen-ci/evergreen/model/patch"
     6  	"github.com/evergreen-ci/evergreen/model/task"
     7  	"github.com/evergreen-ci/evergreen/model/version"
     8  	"github.com/pkg/errors"
     9  )
    10  
    11  // Context is the set of all the related entities in a
    12  // task/build/version/project hierarchy. Using the LoadContext
    13  // function, all the other applicable fields in the Context can
    14  // inferred and populated from the id of any one of the fields.
    15  type Context struct {
    16  	Task       *task.Task
    17  	Build      *build.Build
    18  	Version    *version.Version
    19  	Patch      *patch.Patch
    20  	Project    *Project
    21  	ProjectRef *ProjectRef
    22  }
    23  
    24  // LoadContext builds a Context from the set of given resource ID's
    25  // by inferring all the relationships between them - for example, e.g. loading a project based on
    26  // the the task, or the version based on the patch, etc.
    27  func LoadContext(taskId, buildId, versionId, patchId, projectId string) (Context, error) {
    28  	ctx := &Context{}
    29  
    30  	pId, err := ctx.populateTaskBuildVersion(taskId, buildId, versionId)
    31  	if err != nil {
    32  		return *ctx, err
    33  	}
    34  	if len(projectId) == 0 || (len(pId) > 0 && pId != projectId) {
    35  		projectId = pId
    36  	}
    37  
    38  	err = ctx.populatePatch(patchId)
    39  	if err != nil {
    40  		return *ctx, err
    41  	}
    42  	if ctx.Patch != nil && len(projectId) == 0 {
    43  		projectId = ctx.Patch.Project
    44  	}
    45  
    46  	// Try to load project for the ID we found, and set cookie with it for subsequent requests
    47  	if len(projectId) > 0 {
    48  		// Also lookup the ProjectRef itself and add it to context.
    49  		ctx.ProjectRef, err = FindOneProjectRef(projectId)
    50  		if err != nil {
    51  			return *ctx, err
    52  		}
    53  
    54  		if ctx.ProjectRef != nil {
    55  			ctx.Project, err = FindProject("", ctx.ProjectRef)
    56  			if err != nil {
    57  				return *ctx, err
    58  			}
    59  		}
    60  	}
    61  	return *ctx, nil
    62  }
    63  
    64  // populateTaskBuildVersion takes a task, build, and version ID and populates a Context
    65  // with as many of the task, build, and version documents as possible.
    66  // If any of the provided IDs is blank, they will be inferred from the more selective ones.
    67  // Returns the project ID of the data found, which may be blank if the IDs are empty.
    68  func (ctx *Context) populateTaskBuildVersion(taskId, buildId, versionId string) (string, error) {
    69  	projectId := ""
    70  	var err error
    71  	// Fetch task if there's a task ID present; if we find one, populate build/version IDs from it
    72  	if len(taskId) > 0 {
    73  		ctx.Task, err = task.FindOne(task.ById(taskId))
    74  		if err != nil {
    75  			return "", err
    76  		}
    77  
    78  		if ctx.Task != nil {
    79  			// override build and version ID with the ones this task belongs to
    80  			buildId = ctx.Task.BuildId
    81  			versionId = ctx.Task.Version
    82  			projectId = ctx.Task.Project
    83  		}
    84  	}
    85  
    86  	// Fetch build if there's a build ID present; if we find one, populate version ID from it
    87  	if len(buildId) > 0 {
    88  		ctx.Build, err = build.FindOne(build.ById(buildId))
    89  		if err != nil {
    90  			return "", err
    91  		}
    92  		if ctx.Build != nil {
    93  			versionId = ctx.Build.Version
    94  			projectId = ctx.Build.Project
    95  		}
    96  	}
    97  	if len(versionId) > 0 {
    98  		ctx.Version, err = version.FindOne(version.ById(versionId))
    99  		if err != nil {
   100  			return "", err
   101  		}
   102  		if ctx.Version != nil {
   103  			projectId = ctx.Version.Identifier
   104  		}
   105  	}
   106  	return projectId, nil
   107  }
   108  
   109  // populatePatch loads a patch into the project context, using patchId if provided.
   110  // If patchId is blank, will try to infer the patch ID from the version already loaded
   111  // into context, if available.
   112  func (ctx *Context) populatePatch(patchId string) error {
   113  	var err error
   114  	if len(patchId) > 0 {
   115  		// The patch is explicitly identified in the URL, so fetch it
   116  		if !patch.IsValidId(patchId) {
   117  			return errors.Errorf("patch id '%s' is not an object id", patchId)
   118  		}
   119  		ctx.Patch, err = patch.FindOne(patch.ById(patch.NewId(patchId)).Project(patch.ExcludePatchDiff))
   120  	} else if ctx.Version != nil {
   121  		// patch isn't in URL but the version in context has one, get it
   122  		ctx.Patch, err = patch.FindOne(patch.ByVersion(ctx.Version.Id).Project(patch.ExcludePatchDiff))
   123  	}
   124  	if err != nil {
   125  		return err
   126  	}
   127  
   128  	// If there's a finalized patch loaded into context but not a version, load the version
   129  	// associated with the patch as the context's version.
   130  	if ctx.Version == nil && ctx.Patch != nil && ctx.Patch.Version != "" {
   131  		ctx.Version, err = version.FindOne(version.ById(ctx.Patch.Version))
   132  		if err != nil {
   133  			return errors.WithStack(err)
   134  		}
   135  	}
   136  	return nil
   137  }