github.com/jaylevin/jenkins-library@v1.230.4/cmd/abapEnvironmentCloneGitRepo.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 abapEnvironmentCloneGitRepo(config abapEnvironmentCloneGitRepoOptions, _ *telemetry.CustomData) { 20 21 c := command.Command{} 22 23 c.Stdout(log.Writer()) 24 c.Stderr(log.Writer()) 25 26 var autils = abaputils.AbapUtils{ 27 Exec: &c, 28 } 29 30 client := piperhttp.Client{} 31 32 // error situations should stop execution through log.Entry().Fatal() call which leads to an os.Exit(1) in the end 33 err := runAbapEnvironmentCloneGitRepo(&config, &autils, &client) 34 if err != nil { 35 log.Entry().WithError(err).Fatal("step execution failed") 36 } 37 } 38 39 func runAbapEnvironmentCloneGitRepo(config *abapEnvironmentCloneGitRepoOptions, com abaputils.Communication, client piperhttp.Sender) error { 40 // Mapping for options 41 subOptions := convertCloneConfig(config) 42 43 // Determine the host, user and password, either via the input parameters or via a cloud foundry service key 44 connectionDetails, errorGetInfo := com.GetAbapCommunicationArrangementInfo(subOptions, "") 45 if errorGetInfo != nil { 46 return errors.Wrap(errorGetInfo, "Parameters for the ABAP Connection not available") 47 } 48 49 // Configuring the HTTP Client and CookieJar 50 cookieJar, errorCookieJar := cookiejar.New(nil) 51 if errorCookieJar != nil { 52 return errors.Wrap(errorCookieJar, "Could not create a Cookie Jar") 53 } 54 55 client.SetOptions(piperhttp.ClientOptions{ 56 MaxRequestDuration: 180 * time.Second, 57 CookieJar: cookieJar, 58 Username: connectionDetails.User, 59 Password: connectionDetails.Password, 60 }) 61 62 repositories, errGetRepos := abaputils.GetRepositories(&abaputils.RepositoriesConfig{BranchName: config.BranchName, RepositoryName: config.RepositoryName, Repositories: config.Repositories}) 63 if errGetRepos != nil { 64 return fmt.Errorf("Something failed during the clone: %w", errGetRepos) 65 } 66 67 log.Entry().Infof("Start cloning %v repositories", len(repositories)) 68 for _, repo := range repositories { 69 70 logString := repo.GetCloneLogString() 71 errorString := "Clone of " + logString + " failed on the ABAP system" 72 73 log.Entry().Info("-------------------------") 74 log.Entry().Info("Start cloning " + logString) 75 log.Entry().Info("-------------------------") 76 77 // Triggering the Clone of the repository into the ABAP Environment system 78 uriConnectionDetails, errorTriggerClone := triggerClone(repo, connectionDetails, client) 79 if errorTriggerClone != nil { 80 return errors.Wrapf(errorTriggerClone, errorString) 81 } 82 83 // Polling the status of the repository import on the ABAP Environment system 84 status, errorPollEntity := abaputils.PollEntity(repo.Name, uriConnectionDetails, client, com.GetPollIntervall()) 85 if errorPollEntity != nil { 86 return errors.Wrapf(errorPollEntity, errorString) 87 } 88 if status == "E" { 89 return errors.New("Clone of " + logString + " failed on the ABAP System") 90 } 91 92 log.Entry().Info("The " + logString + " was cloned successfully") 93 } 94 log.Entry().Info("-------------------------") 95 log.Entry().Info("All repositories were cloned successfully") 96 return nil 97 } 98 99 func triggerClone(repo abaputils.Repository, cloneConnectionDetails abaputils.ConnectionDetailsHTTP, client piperhttp.Sender) (abaputils.ConnectionDetailsHTTP, error) { 100 101 uriConnectionDetails := cloneConnectionDetails 102 cloneConnectionDetails.XCsrfToken = "fetch" 103 104 cloneConnectionDetails.URL = cloneConnectionDetails.URL + "/sap/opu/odata/sap/MANAGE_GIT_REPOSITORY/Clones" 105 106 // Loging into the ABAP System - getting the x-csrf-token and cookies 107 resp, err := abaputils.GetHTTPResponse("HEAD", cloneConnectionDetails, nil, client) 108 if err != nil { 109 err = abaputils.HandleHTTPError(resp, err, "Authentication on the ABAP system failed", cloneConnectionDetails) 110 return uriConnectionDetails, err 111 } 112 defer resp.Body.Close() 113 114 log.Entry().WithField("StatusCode", resp.Status).WithField("ABAP Endpoint", cloneConnectionDetails.URL).Debug("Authentication on the ABAP system successful") 115 uriConnectionDetails.XCsrfToken = resp.Header.Get("X-Csrf-Token") 116 cloneConnectionDetails.XCsrfToken = uriConnectionDetails.XCsrfToken 117 118 // Trigger the Clone of a Repository 119 if repo.Name == "" { 120 return uriConnectionDetails, errors.New("An empty string was passed for the parameter 'repositoryName'") 121 } 122 123 jsonBody := []byte(repo.GetCloneRequestBody()) 124 resp, err = abaputils.GetHTTPResponse("POST", cloneConnectionDetails, jsonBody, client) 125 if err != nil { 126 err = abaputils.HandleHTTPError(resp, err, "Could not clone the "+repo.GetCloneLogString(), uriConnectionDetails) 127 return uriConnectionDetails, err 128 } 129 defer resp.Body.Close() 130 log.Entry().WithField("StatusCode", resp.Status).WithField("repositoryName", repo.Name).WithField("branchName", repo.Branch).WithField("commitID", repo.CommitID).WithField("Tag", repo.Tag).Info("Triggered Clone of Repository / Software Component") 131 132 // Parse Response 133 var body abaputils.CloneEntity 134 var abapResp map[string]*json.RawMessage 135 bodyText, errRead := ioutil.ReadAll(resp.Body) 136 if errRead != nil { 137 return uriConnectionDetails, err 138 } 139 json.Unmarshal(bodyText, &abapResp) 140 json.Unmarshal(*abapResp["d"], &body) 141 if reflect.DeepEqual(abaputils.CloneEntity{}, body) { 142 log.Entry().WithField("StatusCode", resp.Status).WithField("repositoryName", repo.Name).WithField("branchName", repo.Branch).WithField("commitID", repo.CommitID).WithField("Tag", repo.Tag).Error("Could not Clone the Repository / Software Component") 143 err := errors.New("Request to ABAP System not successful") 144 return uriConnectionDetails, err 145 } 146 147 // The entity "Clones" does not allow for polling. To poll the progress, the related entity "Pull" has to be called 148 // While "Clones" has the key fields UUID, SC_NAME and BRANCH_NAME, "Pull" only has the key field UUID 149 uriConnectionDetails.URL = uriConnectionDetails.URL + "/sap/opu/odata/sap/MANAGE_GIT_REPOSITORY/Pull(uuid=guid'" + body.UUID + "')" 150 return uriConnectionDetails, nil 151 } 152 153 func convertCloneConfig(config *abapEnvironmentCloneGitRepoOptions) abaputils.AbapEnvironmentOptions { 154 subOptions := abaputils.AbapEnvironmentOptions{} 155 156 subOptions.CfAPIEndpoint = config.CfAPIEndpoint 157 subOptions.CfServiceInstance = config.CfServiceInstance 158 subOptions.CfServiceKeyName = config.CfServiceKeyName 159 subOptions.CfOrg = config.CfOrg 160 subOptions.CfSpace = config.CfSpace 161 subOptions.Host = config.Host 162 subOptions.Password = config.Password 163 subOptions.Username = config.Username 164 return subOptions 165 }