github.com/billybanfield/evergreen@v0.0.0-20170525200750-eeee692790f7/plugin/builtin/manifest/load_command.go (about) 1 package manifest 2 3 import ( 4 "fmt" 5 "net/http" 6 "time" 7 8 "github.com/evergreen-ci/evergreen/model" 9 "github.com/evergreen-ci/evergreen/model/manifest" 10 "github.com/evergreen-ci/evergreen/plugin" 11 "github.com/evergreen-ci/evergreen/thirdparty" 12 "github.com/evergreen-ci/evergreen/util" 13 "github.com/mongodb/grip/slogger" 14 "github.com/pkg/errors" 15 ) 16 17 // ManifestLoadCommand 18 type ManifestLoadCommand struct{} 19 20 func (mfc *ManifestLoadCommand) Name() string { 21 return ManifestLoadCmd 22 } 23 24 func (mfc *ManifestLoadCommand) Plugin() string { 25 return ManifestPluginName 26 } 27 28 // ManifestLoadCommand-specific implementation of ParseParams. 29 func (mfc *ManifestLoadCommand) ParseParams(params map[string]interface{}) error { 30 return nil 31 } 32 33 // updateExpansions adds the expansions for the manifest's modules into the TaskConfig's Expansions. 34 func (mfc *ManifestLoadCommand) updateExpansions(manifest *manifest.Manifest, 35 conf *model.TaskConfig) { 36 for moduleName := range manifest.Modules { 37 // put the url for the module in the expansions 38 conf.Expansions.Put(fmt.Sprintf("%v_rev", moduleName), manifest.Modules[moduleName].Revision) 39 } 40 } 41 42 // Load performs a GET on /manifest/load 43 func (mfc *ManifestLoadCommand) Load(log plugin.Logger, pluginCom plugin.PluginCommunicator, conf *model.TaskConfig) error { 44 var loadedManifest *manifest.Manifest 45 var err error 46 47 retriableGet := util.RetriableFunc( 48 func() error { 49 resp, err := pluginCom.TaskGetJSON(ManifestLoadAPIEndpoint) 50 if resp != nil { 51 defer resp.Body.Close() 52 } 53 if err != nil { 54 //Some generic error trying to connect - try again 55 log.LogExecution(slogger.WARN, "Error connecting to API server: %v", err) 56 return util.RetriableError{err} 57 } 58 if resp != nil && resp.StatusCode != http.StatusOK { 59 log.LogExecution(slogger.WARN, "Unexpected status code %v, retrying", resp.StatusCode) 60 return util.RetriableError{errors.Errorf("Unexpected status code %v", resp.StatusCode)} 61 } 62 err = util.ReadJSONInto(resp.Body, &loadedManifest) 63 return err 64 }) 65 66 _, err = util.Retry(retriableGet, 10, 1*time.Second) 67 if err != nil { 68 return err 69 } 70 if loadedManifest == nil { 71 return errors.New("Manifest is empty") 72 } 73 mfc.updateExpansions(loadedManifest, conf) 74 return nil 75 } 76 77 // Implementation of Execute. 78 func (mfc *ManifestLoadCommand) Execute(pluginLogger plugin.Logger, 79 pluginCom plugin.PluginCommunicator, conf *model.TaskConfig, 80 stop chan bool) error { 81 82 errChan := make(chan error) 83 go func() { 84 errChan <- mfc.Load(pluginLogger, pluginCom, conf) 85 }() 86 87 select { 88 case err := <-errChan: 89 return err 90 case <-stop: 91 pluginLogger.LogExecution(slogger.INFO, "Received signal to terminate"+ 92 " execution of manifest load command") 93 return nil 94 } 95 96 } 97 98 // ManifestLoadHandler attempts to get the manifest, if it exists it updates the expansions and returns 99 // If it does not exist it performs GitHub API calls for each of the project's modules and gets 100 // the head revision of the branch and inserts it into the manifest collection. 101 // If there is a duplicate key error, then do a find on the manifest again. 102 func (mp *ManifestPlugin) ManifestLoadHandler(w http.ResponseWriter, r *http.Request) { 103 task := plugin.GetTask(r) 104 projectRef, err := model.FindOneProjectRef(task.Project) 105 if err != nil { 106 http.Error(w, fmt.Sprintf("projectRef not found for project %v: %v", task.Project, err), http.StatusBadRequest) 107 return 108 } 109 project, err := model.FindProject("", projectRef) 110 if err != nil { 111 http.Error(w, fmt.Sprintf("project not found for ProjectRef %v: %v", projectRef.Identifier, err), 112 http.StatusBadRequest) 113 return 114 } 115 if project == nil { 116 http.Error(w, fmt.Sprintf("empty project not found for ProjectRef %v: %v", projectRef.Identifier, err), 117 http.StatusBadRequest) 118 return 119 } 120 // try to get the manifest 121 currentManifest, err := manifest.FindOne(manifest.ById(task.Version)) 122 if err != nil { 123 http.Error(w, fmt.Sprintf("error retrieving manifest with version id %v: %v", task.Version, err), 124 http.StatusBadRequest) 125 return 126 } 127 if currentManifest != nil { 128 plugin.WriteJSON(w, http.StatusOK, currentManifest) 129 return 130 } 131 132 if task.Version == "" { 133 http.Error(w, fmt.Sprintf("versionId is empty"), http.StatusNotFound) 134 return 135 } 136 137 // attempt to insert a manifest after making GitHub API calls 138 newManifest := &manifest.Manifest{ 139 Id: task.Version, 140 Revision: task.Revision, 141 ProjectName: task.Project, 142 Branch: project.Branch, 143 } 144 // populate modules 145 var gitBranch *thirdparty.BranchEvent 146 modules := make(map[string]*manifest.Module) 147 for _, module := range project.Modules { 148 owner, repo := module.GetRepoOwnerAndName() 149 gitBranch, err = thirdparty.GetBranchEvent(mp.OAuthCredentials, owner, repo, module.Branch) 150 if err != nil { 151 http.Error(w, fmt.Sprintf("error retrieving getting git branch for module %v: %v", module.Name, err), 152 http.StatusInternalServerError) 153 return 154 } 155 156 modules[module.Name] = &manifest.Module{ 157 Branch: module.Branch, 158 Revision: gitBranch.Commit.SHA, 159 Repo: repo, 160 Owner: owner, 161 URL: gitBranch.Commit.Url, 162 } 163 } 164 newManifest.Modules = modules 165 duplicate, err := newManifest.TryInsert() 166 if err != nil { 167 http.Error(w, fmt.Sprintf("error inserting manifest for %v: %v", newManifest.ProjectName, err), 168 http.StatusInternalServerError) 169 return 170 } 171 // if it is a duplicate, load the manifest again` 172 if duplicate { 173 // try to get the manifest 174 m, err := manifest.FindOne(manifest.ById(task.Version)) 175 if err != nil { 176 http.Error(w, fmt.Sprintf("error getting latest manifest for %v: %v", newManifest.ProjectName, err), 177 http.StatusBadRequest) 178 return 179 } 180 if m != nil { 181 plugin.WriteJSON(w, http.StatusOK, m) 182 return 183 } 184 } 185 // no duplicate key error, use the manifest just created. 186 187 plugin.WriteJSON(w, http.StatusOK, newManifest) 188 return 189 }