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

     1  package validator
     2  
     3  import (
     4  	"encoding/base64"
     5  	"fmt"
     6  
     7  	"github.com/evergreen-ci/evergreen"
     8  	"github.com/evergreen-ci/evergreen/model"
     9  	"github.com/evergreen-ci/evergreen/model/patch"
    10  	"github.com/evergreen-ci/evergreen/thirdparty"
    11  	"github.com/pkg/errors"
    12  )
    13  
    14  // GetPatchedProject creates and validates a project created by fetching latest commit information from GitHub
    15  // and applying the patch to the latest remote configuration. The error returned can be a validation error.
    16  func GetPatchedProject(p *patch.Patch, settings *evergreen.Settings) (*model.Project, error) {
    17  	if p.Version != "" {
    18  		return nil, errors.Errorf("Patch %v already finalized", p.Version)
    19  	}
    20  	projectRef, err := model.FindOneProjectRef(p.Project)
    21  	if err != nil {
    22  		return nil, errors.WithStack(err)
    23  	}
    24  
    25  	// try to get the remote project file data at the requested revision
    26  	var projectFileBytes []byte
    27  	projectFileURL := thirdparty.GetGithubFileURL(
    28  		projectRef.Owner,
    29  		projectRef.Repo,
    30  		projectRef.RemotePath,
    31  		p.Githash,
    32  	)
    33  	githubFile, err := thirdparty.GetGithubFile(settings.Credentials["github"], projectFileURL)
    34  	if err != nil {
    35  		// if the project file doesn't exist, but our patch includes a project file,
    36  		// we try to apply the diff and proceed.
    37  		if !(p.ConfigChanged(projectRef.RemotePath) && thirdparty.IsFileNotFound(err)) {
    38  			// return an error if the github error is network/auth-related or we aren't patching the config
    39  			return nil, errors.Wrapf(err, "Could not get github file at %v", projectFileURL)
    40  		}
    41  	} else {
    42  		// we successfully got the project file in base64, so we decode it
    43  		projectFileBytes, err = base64.StdEncoding.DecodeString(githubFile.Content)
    44  		if err != nil {
    45  			return nil, errors.Wrapf(err, "Could not decode github file at %v", projectFileURL)
    46  		}
    47  	}
    48  
    49  	project := &model.Project{}
    50  
    51  	// if the patched config exists, use that as the project file bytes.
    52  	if p.PatchedConfig != "" {
    53  		projectFileBytes = []byte(p.PatchedConfig)
    54  	}
    55  
    56  	// apply remote configuration patch if needed
    57  	if p.ConfigChanged(projectRef.RemotePath) && p.PatchedConfig == "" {
    58  		project, err = model.MakePatchedConfig(p, projectRef.RemotePath, string(projectFileBytes))
    59  		if err != nil {
    60  			return nil, errors.Wrapf(err, "Could not patch remote configuration file")
    61  		}
    62  		// overwrite project fields with the project ref to disallow tracking a
    63  		// different project or doing other crazy things via config patches
    64  		verrs, err := CheckProjectSyntax(project)
    65  		if err != nil {
    66  			return nil, errors.WithStack(err)
    67  		}
    68  
    69  		if len(verrs) != 0 {
    70  			var message string
    71  			for _, err := range verrs {
    72  				message += fmt.Sprintf("\n\t=> %+v", err)
    73  			}
    74  			return nil, errors.New(message)
    75  		}
    76  	} else {
    77  		// configuration is not patched
    78  		if err = model.LoadProjectInto(projectFileBytes, projectRef.Identifier, project); err != nil {
    79  			return nil, errors.WithStack(err)
    80  		}
    81  	}
    82  	return project, nil
    83  }