github.com/xgoffin/jenkins-library@v1.154.0/cmd/abapEnvironmentPullGitRepo.go (about) 1 package cmd 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "io/ioutil" 7 "net/http/cookiejar" 8 "reflect" 9 "time" 10 11 "github.com/SAP/jenkins-library/pkg/abaputils" 12 "github.com/SAP/jenkins-library/pkg/command" 13 piperhttp "github.com/SAP/jenkins-library/pkg/http" 14 "github.com/SAP/jenkins-library/pkg/log" 15 "github.com/SAP/jenkins-library/pkg/telemetry" 16 "github.com/pkg/errors" 17 ) 18 19 func abapEnvironmentPullGitRepo(options abapEnvironmentPullGitRepoOptions, _ *telemetry.CustomData) { 20 21 // for command execution use Command 22 c := command.Command{} 23 // reroute command output to logging framework 24 c.Stdout(log.Writer()) 25 c.Stderr(log.Writer()) 26 27 var autils = abaputils.AbapUtils{ 28 Exec: &c, 29 } 30 31 client := piperhttp.Client{} 32 33 // error situations should stop execution through log.Entry().Fatal() call which leads to an os.Exit(1) in the end 34 err := runAbapEnvironmentPullGitRepo(&options, &autils, &client) 35 if err != nil { 36 log.Entry().WithError(err).Fatal("step execution failed") 37 } 38 } 39 40 func runAbapEnvironmentPullGitRepo(options *abapEnvironmentPullGitRepoOptions, com abaputils.Communication, client piperhttp.Sender) (err error) { 41 42 subOptions := convertPullConfig(options) 43 44 // Determine the host, user and password, either via the input parameters or via a cloud foundry service key 45 connectionDetails, err := com.GetAbapCommunicationArrangementInfo(subOptions, "/sap/opu/odata/sap/MANAGE_GIT_REPOSITORY/Pull") 46 if err != nil { 47 return errors.Wrap(err, "Parameters for the ABAP Connection not available") 48 } 49 50 cookieJar, err := cookiejar.New(nil) 51 if err != nil { 52 return errors.Wrap(err, "Could not create a Cookie Jar") 53 } 54 clientOptions := piperhttp.ClientOptions{ 55 MaxRequestDuration: 180 * time.Second, 56 CookieJar: cookieJar, 57 Username: connectionDetails.User, 58 Password: connectionDetails.Password, 59 } 60 client.SetOptions(clientOptions) 61 pollIntervall := com.GetPollIntervall() 62 63 repositories := []abaputils.Repository{} 64 err = checkPullRepositoryConfiguration(*options) 65 if err != nil { 66 return err 67 } 68 repositories, err = abaputils.GetRepositories(&abaputils.RepositoriesConfig{RepositoryNames: options.RepositoryNames, Repositories: options.Repositories}) 69 handleIgnoreCommit(repositories, options.IgnoreCommit) 70 if err != nil { 71 return err 72 } 73 74 err = pullRepositories(repositories, connectionDetails, client, pollIntervall) 75 return err 76 77 } 78 79 func pullRepositories(repositories []abaputils.Repository, pullConnectionDetails abaputils.ConnectionDetailsHTTP, client piperhttp.Sender, pollIntervall time.Duration) (err error) { 80 log.Entry().Infof("Start pulling %v repositories", len(repositories)) 81 for _, repo := range repositories { 82 err = handlePull(repo, pullConnectionDetails, client, pollIntervall) 83 if err != nil { 84 break 85 } 86 } 87 if err == nil { 88 finishPullLogs() 89 } 90 return err 91 } 92 93 func handlePull(repo abaputils.Repository, pullConnectionDetails abaputils.ConnectionDetailsHTTP, client piperhttp.Sender, pollIntervall time.Duration) (err error) { 94 95 logString := repo.GetPullLogString() 96 errorString := "Pull of the " + logString + " failed on the ABAP system" 97 98 log.Entry().Info("-------------------------") 99 log.Entry().Info("Start pulling the " + logString) 100 log.Entry().Info("-------------------------") 101 102 uriConnectionDetails, err := triggerPull(repo, pullConnectionDetails, client) 103 if err != nil { 104 return errors.Wrapf(err, errorString) 105 } 106 107 // Polling the status of the repository import on the ABAP Environment system 108 status, errorPollEntity := abaputils.PollEntity(repo.Name, uriConnectionDetails, client, pollIntervall) 109 if errorPollEntity != nil { 110 return errors.Wrapf(errorPollEntity, errorString) 111 } 112 if status == "E" { 113 return errors.New(errorString) 114 } 115 log.Entry().Info(repo.Name + " was pulled successfully") 116 return err 117 } 118 119 func triggerPull(repo abaputils.Repository, pullConnectionDetails abaputils.ConnectionDetailsHTTP, client piperhttp.Sender) (abaputils.ConnectionDetailsHTTP, error) { 120 121 uriConnectionDetails := pullConnectionDetails 122 uriConnectionDetails.URL = "" 123 pullConnectionDetails.XCsrfToken = "fetch" 124 125 // Loging into the ABAP System - getting the x-csrf-token and cookies 126 resp, err := abaputils.GetHTTPResponse("HEAD", pullConnectionDetails, nil, client) 127 if err != nil { 128 err = abaputils.HandleHTTPError(resp, err, "Authentication on the ABAP system failed", pullConnectionDetails) 129 return uriConnectionDetails, err 130 } 131 defer resp.Body.Close() 132 133 log.Entry().WithField("StatusCode", resp.Status).WithField("ABAP Endpoint", pullConnectionDetails.URL).Debug("Authentication on the ABAP system successful") 134 uriConnectionDetails.XCsrfToken = resp.Header.Get("X-Csrf-Token") 135 pullConnectionDetails.XCsrfToken = uriConnectionDetails.XCsrfToken 136 137 // Trigger the Pull of a Repository 138 if repo.Name == "" { 139 return uriConnectionDetails, errors.New("An empty string was passed for the parameter 'repositoryName'") 140 } 141 142 jsonBody := []byte(repo.GetPullRequestBody()) 143 resp, err = abaputils.GetHTTPResponse("POST", pullConnectionDetails, jsonBody, client) 144 if err != nil { 145 err = abaputils.HandleHTTPError(resp, err, "Could not pull the "+repo.GetPullLogString(), uriConnectionDetails) 146 return uriConnectionDetails, err 147 } 148 defer resp.Body.Close() 149 log.Entry().WithField("StatusCode", resp.Status).WithField("repositoryName", repo.Name).WithField("commitID", repo.CommitID).WithField("Tag", repo.Tag).Debug("Triggered Pull of repository / software component") 150 151 // Parse Response 152 var body abaputils.PullEntity 153 var abapResp map[string]*json.RawMessage 154 bodyText, errRead := ioutil.ReadAll(resp.Body) 155 if errRead != nil { 156 return uriConnectionDetails, err 157 } 158 json.Unmarshal(bodyText, &abapResp) 159 json.Unmarshal(*abapResp["d"], &body) 160 if reflect.DeepEqual(abaputils.PullEntity{}, body) { 161 log.Entry().WithField("StatusCode", resp.Status).WithField("repositoryName", repo.Name).WithField("commitID", repo.CommitID).WithField("Tag", repo.Tag).Error("Could not pull the repository / software component") 162 err := errors.New("Request to ABAP System not successful") 163 return uriConnectionDetails, err 164 } 165 166 uriConnectionDetails.URL = body.Metadata.URI 167 return uriConnectionDetails, nil 168 } 169 170 func checkPullRepositoryConfiguration(options abapEnvironmentPullGitRepoOptions) error { 171 if len(options.RepositoryNames) > 0 && options.Repositories != "" { 172 log.Entry().Info("It seems like you have specified repositories directly via the configuration parameter 'repositoryNames' as well as in the dedicated repositories configuration file. Please note that in this case both configurations will be handled and pulled.") 173 } 174 if len(options.RepositoryNames) == 0 && options.Repositories == "" { 175 return fmt.Errorf("Checking configuration failed: %w", errors.New("You have not specified any repository configuration to be pulled into the ABAP Environment System. Please make sure that you specified the repositories that should be pulled either in a dedicated file or via the parameter 'repositoryNames'. For more information please read the User documentation")) 176 } 177 return nil 178 } 179 180 func finishPullLogs() { 181 log.Entry().Info("-------------------------") 182 log.Entry().Info("All repositories were pulled successfully") 183 } 184 185 func convertPullConfig(config *abapEnvironmentPullGitRepoOptions) abaputils.AbapEnvironmentOptions { 186 subOptions := abaputils.AbapEnvironmentOptions{} 187 188 subOptions.CfAPIEndpoint = config.CfAPIEndpoint 189 subOptions.CfServiceInstance = config.CfServiceInstance 190 subOptions.CfServiceKeyName = config.CfServiceKeyName 191 subOptions.CfOrg = config.CfOrg 192 subOptions.CfSpace = config.CfSpace 193 subOptions.Host = config.Host 194 subOptions.Password = config.Password 195 subOptions.Username = config.Username 196 return subOptions 197 } 198 199 func handleIgnoreCommit(repositories []abaputils.Repository, ignoreCommit bool) { 200 for i := range repositories { 201 if ignoreCommit { 202 repositories[i].CommitID = "" 203 } 204 } 205 }