github.com/ouraigua/jenkins-library@v0.0.0-20231028010029-fbeaf2f3aa9b/cmd/abapEnvironmentCreateTag.go (about) 1 package cmd 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "io" 7 "net/http/cookiejar" 8 "strings" 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 abapEnvironmentCreateTag(config abapEnvironmentCreateTagOptions, telemetryData *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 if err := runAbapEnvironmentCreateTag(&config, telemetryData, &autils, &client); err != nil { 33 log.Entry().WithError(err).Fatal("step execution failed") 34 } 35 } 36 37 func runAbapEnvironmentCreateTag(config *abapEnvironmentCreateTagOptions, telemetryData *telemetry.CustomData, com abaputils.Communication, client piperhttp.Sender) error { 38 39 connectionDetails, errorGetInfo := com.GetAbapCommunicationArrangementInfo(convertTagConfig(config), "") 40 if errorGetInfo != nil { 41 return errors.Wrap(errorGetInfo, "Parameters for the ABAP Connection not available") 42 } 43 44 // Configuring the HTTP Client and CookieJar 45 cookieJar, errorCookieJar := cookiejar.New(nil) 46 if errorCookieJar != nil { 47 return errors.Wrap(errorCookieJar, "Could not create a Cookie Jar") 48 } 49 50 client.SetOptions(piperhttp.ClientOptions{ 51 MaxRequestDuration: 180 * time.Second, 52 CookieJar: cookieJar, 53 Username: connectionDetails.User, 54 Password: connectionDetails.Password, 55 }) 56 57 backlog, errorPrepare := prepareBacklog(config) 58 if errorPrepare != nil { 59 return fmt.Errorf("Something failed during the tag creation: %w", errorPrepare) 60 } 61 62 return createTags(backlog, telemetryData, connectionDetails, client, com) 63 } 64 65 func createTags(backlog []CreateTagBacklog, telemetryData *telemetry.CustomData, con abaputils.ConnectionDetailsHTTP, client piperhttp.Sender, com abaputils.Communication) (err error) { 66 67 connection := con 68 connection.XCsrfToken = "fetch" 69 connection.URL = con.URL + "/sap/opu/odata/sap/MANAGE_GIT_REPOSITORY/Tags" 70 resp, err := abaputils.GetHTTPResponse("HEAD", connection, nil, client) 71 if err != nil { 72 return abaputils.HandleHTTPError(resp, err, "Authentication on the ABAP system failed", con) 73 } 74 defer resp.Body.Close() 75 76 log.Entry().WithField("StatusCode", resp.Status).WithField("ABAP Endpoint", connection.URL).Debug("Authentication on the ABAP system successful") 77 connection.XCsrfToken = resp.Header.Get("X-Csrf-Token") 78 79 errorOccurred := false 80 for _, item := range backlog { 81 err = createTagsForSingleItem(item, telemetryData, connection, client, com) 82 if err != nil { 83 errorOccurred = true 84 } 85 } 86 87 if errorOccurred { 88 message := "At least one tag has not been created" 89 log.Entry().Errorf(message) 90 return errors.New(message) 91 } 92 return nil 93 94 } 95 96 func createTagsForSingleItem(item CreateTagBacklog, telemetryData *telemetry.CustomData, con abaputils.ConnectionDetailsHTTP, client piperhttp.Sender, com abaputils.Communication) (err error) { 97 98 errorOccurred := false 99 for index := range item.tags { 100 err = createSingleTag(item, index, telemetryData, con, client, com) 101 if err != nil { 102 errorOccurred = true 103 } 104 } 105 if errorOccurred { 106 message := "At least one tag has not been created" 107 err = errors.New(message) 108 } 109 return err 110 } 111 112 func createSingleTag(item CreateTagBacklog, index int, telemetryData *telemetry.CustomData, con abaputils.ConnectionDetailsHTTP, client piperhttp.Sender, com abaputils.Communication) (err error) { 113 114 requestBodyStruct := CreateTagBody{RepositoryName: item.repositoryName, CommitID: item.commitID, Tag: item.tags[index].tagName, Description: item.tags[index].tagDescription} 115 requestBodyJson, err := json.Marshal(&requestBodyStruct) 116 if err != nil { 117 return err 118 } 119 120 log.Entry().Debugf("Request body: %s", requestBodyJson) 121 resp, err := abaputils.GetHTTPResponse("POST", con, requestBodyJson, client) 122 if err != nil { 123 errorMessage := "Could not create tag " + requestBodyStruct.Tag + " for repository " + requestBodyStruct.RepositoryName + " with commitID " + requestBodyStruct.CommitID 124 err = abaputils.HandleHTTPError(resp, err, errorMessage, con) 125 return err 126 } 127 defer resp.Body.Close() 128 129 // Parse response 130 var createTagResponse CreateTagResponse 131 var abapResp map[string]*json.RawMessage 132 bodyText, _ := io.ReadAll(resp.Body) 133 134 if err = json.Unmarshal(bodyText, &abapResp); err != nil { 135 return err 136 } 137 if err = json.Unmarshal(*abapResp["d"], &createTagResponse); err != nil { 138 return err 139 } 140 141 con.URL = con.Host + "/sap/opu/odata/sap/MANAGE_GIT_REPOSITORY/Pull(guid'" + createTagResponse.UUID + "')" 142 err = checkStatus(con, client, com) 143 144 if err == nil { 145 log.Entry().Info("Created tag " + requestBodyStruct.Tag + " for repository " + requestBodyStruct.RepositoryName + " with commitID " + requestBodyStruct.CommitID) 146 } else { 147 log.Entry().Error("NOT created: Tag " + requestBodyStruct.Tag + " for repository " + requestBodyStruct.RepositoryName + " with commitID " + requestBodyStruct.CommitID) 148 } 149 150 return err 151 } 152 153 func checkStatus(con abaputils.ConnectionDetailsHTTP, client piperhttp.Sender, com abaputils.Communication) (err error) { 154 var status string 155 pollIntervall := com.GetPollIntervall() 156 count := 0 157 for { 158 count += 1 159 entity, _, err := abaputils.GetStatus("Could not create Tag", con, client) 160 if err != nil { 161 return err 162 } 163 status = entity.Status 164 if status != "R" { 165 if status == "E" { 166 err = errors.New("Could not create Tag") 167 } 168 return err 169 } 170 if count >= 200 { 171 return errors.New("Could not create Tag (Timeout)") 172 } 173 time.Sleep(pollIntervall) 174 } 175 } 176 177 func prepareBacklog(config *abapEnvironmentCreateTagOptions) (backlog []CreateTagBacklog, err error) { 178 179 if config.Repositories != "" && config.RepositoryName != "" { 180 return nil, errors.New("Configuring the parameter repositories and the parameter repositoryName at the same time is not allowed") 181 } 182 183 if config.RepositoryName != "" && config.CommitID != "" { 184 backlog = append(backlog, CreateTagBacklog{repositoryName: config.RepositoryName, commitID: config.CommitID}) 185 } 186 187 if config.Repositories != "" { 188 descriptor, err := abaputils.ReadAddonDescriptor(config.Repositories) //config.Repositories should contain a file name 189 if err != nil { 190 return nil, err 191 } 192 for _, repo := range descriptor.Repositories { 193 backlogInstance := CreateTagBacklog{repositoryName: repo.Name, commitID: repo.CommitID} 194 if config.GenerateTagForAddonComponentVersion && repo.VersionYAML != "" { 195 tag := Tag{tagName: "v" + repo.VersionYAML, tagDescription: "Generated by the ABAP Environment Pipeline"} 196 backlogInstance.tags = append(backlogInstance.tags, tag) 197 } 198 backlog = append(backlog, backlogInstance) 199 } 200 if config.GenerateTagForAddonProductVersion { 201 if descriptor.AddonProduct != "" && descriptor.AddonVersionYAML != "" { 202 addonProductDash := strings.Replace(descriptor.AddonProduct, "/", "-", 2) 203 backlog = addTagToList(backlog, addonProductDash+"-"+descriptor.AddonVersionYAML, "Generated by the ABAP Environment Pipeline") 204 } else { 205 log.Entry().WithField("generateTagForAddonProductVersion", config.GenerateTagForAddonProductVersion).WithField("AddonProduct", descriptor.AddonProduct).WithField("AddonVersion", descriptor.AddonVersionYAML).Infof("Not all required values are provided to create an addon product version tag") 206 } 207 } 208 } 209 if config.TagName != "" { 210 backlog = addTagToList(backlog, config.TagName, config.TagDescription) 211 } 212 return backlog, nil 213 } 214 215 func addTagToList(backlog []CreateTagBacklog, tag string, description string) []CreateTagBacklog { 216 217 for i, item := range backlog { 218 tag := Tag{tagName: tag, tagDescription: description} 219 backlog[i].tags = append(item.tags, tag) 220 } 221 return backlog 222 } 223 224 func convertTagConfig(config *abapEnvironmentCreateTagOptions) abaputils.AbapEnvironmentOptions { 225 subOptions := abaputils.AbapEnvironmentOptions{} 226 227 subOptions.CfAPIEndpoint = config.CfAPIEndpoint 228 subOptions.CfServiceInstance = config.CfServiceInstance 229 subOptions.CfServiceKeyName = config.CfServiceKeyName 230 subOptions.CfOrg = config.CfOrg 231 subOptions.CfSpace = config.CfSpace 232 subOptions.Host = config.Host 233 subOptions.Password = config.Password 234 subOptions.Username = config.Username 235 236 return subOptions 237 } 238 239 type CreateTagBacklog struct { 240 repositoryName string 241 commitID string 242 tags []Tag 243 } 244 245 type Tag struct { 246 tagName string 247 tagDescription string 248 } 249 250 type CreateTagBody struct { 251 RepositoryName string `json:"sc_name"` 252 CommitID string `json:"commit_id"` 253 Tag string `json:"tag_name"` 254 Description string `json:"tag_description"` 255 } 256 257 type CreateTagResponse struct { 258 UUID string `json:"uuid"` 259 }