1
0
mirror of https://github.com/SAP/jenkins-library.git synced 2024-12-14 11:03:09 +02:00
sap-jenkins-library/cmd/abapEnvironmentCreateTag.go

260 lines
8.6 KiB
Go
Raw Normal View History

package cmd
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http/cookiejar"
"strings"
"time"
"github.com/SAP/jenkins-library/pkg/abaputils"
"github.com/SAP/jenkins-library/pkg/command"
piperhttp "github.com/SAP/jenkins-library/pkg/http"
"github.com/SAP/jenkins-library/pkg/log"
"github.com/SAP/jenkins-library/pkg/telemetry"
"github.com/pkg/errors"
)
func abapEnvironmentCreateTag(config abapEnvironmentCreateTagOptions, telemetryData *telemetry.CustomData) {
c := command.Command{}
c.Stdout(log.Writer())
c.Stderr(log.Writer())
var autils = abaputils.AbapUtils{
Exec: &c,
}
client := piperhttp.Client{}
if err := runAbapEnvironmentCreateTag(&config, telemetryData, &autils, &client); err != nil {
log.Entry().WithError(err).Fatal("step execution failed")
}
}
func runAbapEnvironmentCreateTag(config *abapEnvironmentCreateTagOptions, telemetryData *telemetry.CustomData, com abaputils.Communication, client piperhttp.Sender) error {
connectionDetails, errorGetInfo := com.GetAbapCommunicationArrangementInfo(convertTagConfig(config), "")
if errorGetInfo != nil {
return errors.Wrap(errorGetInfo, "Parameters for the ABAP Connection not available")
}
// Configuring the HTTP Client and CookieJar
cookieJar, errorCookieJar := cookiejar.New(nil)
if errorCookieJar != nil {
return errors.Wrap(errorCookieJar, "Could not create a Cookie Jar")
}
client.SetOptions(piperhttp.ClientOptions{
MaxRequestDuration: 180 * time.Second,
CookieJar: cookieJar,
Username: connectionDetails.User,
Password: connectionDetails.Password,
})
backlog, errorPrepare := prepareBacklog(config)
if errorPrepare != nil {
return fmt.Errorf("Something failed during the tag creation: %w", errorPrepare)
}
return createTags(backlog, telemetryData, connectionDetails, client, com)
}
func createTags(backlog []CreateTagBacklog, telemetryData *telemetry.CustomData, con abaputils.ConnectionDetailsHTTP, client piperhttp.Sender, com abaputils.Communication) (err error) {
connection := con
connection.XCsrfToken = "fetch"
connection.URL = con.URL + "/sap/opu/odata/sap/MANAGE_GIT_REPOSITORY/Tags"
resp, err := abaputils.GetHTTPResponse("HEAD", connection, nil, client)
if err != nil {
return abaputils.HandleHTTPError(resp, err, "Authentication on the ABAP system failed", con)
}
defer resp.Body.Close()
log.Entry().WithField("StatusCode", resp.Status).WithField("ABAP Endpoint", connection.URL).Debug("Authentication on the ABAP system successful")
connection.XCsrfToken = resp.Header.Get("X-Csrf-Token")
errorOccurred := false
for _, item := range backlog {
err = createTagsForSingleItem(item, telemetryData, connection, client, com)
if err != nil {
errorOccurred = true
}
}
if errorOccurred {
message := "At least one tag has not been created"
log.Entry().Errorf(message)
return errors.New(message)
}
return nil
}
func createTagsForSingleItem(item CreateTagBacklog, telemetryData *telemetry.CustomData, con abaputils.ConnectionDetailsHTTP, client piperhttp.Sender, com abaputils.Communication) (err error) {
errorOccurred := false
for index := range item.tags {
err = createSingleTag(item, index, telemetryData, con, client, com)
if err != nil {
errorOccurred = true
}
}
if errorOccurred {
message := "At least one tag has not been created"
err = errors.New(message)
}
return err
}
func createSingleTag(item CreateTagBacklog, index int, telemetryData *telemetry.CustomData, con abaputils.ConnectionDetailsHTTP, client piperhttp.Sender, com abaputils.Communication) (err error) {
requestBodyStruct := CreateTagBody{RepositoryName: item.repositoryName, CommitID: item.commitID, Tag: item.tags[index].tagName, Description: item.tags[index].tagDescription}
requestBodyJson, err := json.Marshal(&requestBodyStruct)
if err != nil {
return err
}
log.Entry().Debugf("Request body: %s", requestBodyJson)
resp, err := abaputils.GetHTTPResponse("POST", con, requestBodyJson, client)
if err != nil {
errorMessage := "Could not create tag " + requestBodyStruct.Tag + " for repository " + requestBodyStruct.RepositoryName + " with commitID " + requestBodyStruct.CommitID
err = abaputils.HandleHTTPError(resp, err, errorMessage, con)
return err
}
defer resp.Body.Close()
// Parse response
var createTagResponse CreateTagResponse
var abapResp map[string]*json.RawMessage
bodyText, _ := ioutil.ReadAll(resp.Body)
if err = json.Unmarshal(bodyText, &abapResp); err != nil {
return err
}
if err = json.Unmarshal(*abapResp["d"], &createTagResponse); err != nil {
return err
}
con.URL = con.Host + "/sap/opu/odata/sap/MANAGE_GIT_REPOSITORY/Pull(guid'" + createTagResponse.UUID + "')"
err = checkStatus(con, client, com)
if err == nil {
log.Entry().Info("Created tag " + requestBodyStruct.Tag + " for repository " + requestBodyStruct.RepositoryName + " with commitID " + requestBodyStruct.CommitID)
} else {
log.Entry().Error("NOT created: Tag " + requestBodyStruct.Tag + " for repository " + requestBodyStruct.RepositoryName + " with commitID " + requestBodyStruct.CommitID)
}
return err
}
func checkStatus(con abaputils.ConnectionDetailsHTTP, client piperhttp.Sender, com abaputils.Communication) (err error) {
var status string
pollIntervall := com.GetPollIntervall()
count := 0
for {
count += 1
entity, _, err := abaputils.GetStatus("Could not create Tag", con, client)
if err != nil {
return err
}
status = entity.Status
if status != "R" {
if status == "E" {
err = errors.New("Could not create Tag")
}
return err
}
if count >= 200 {
return errors.New("Could not create Tag (Timeout)")
}
time.Sleep(pollIntervall)
}
}
func prepareBacklog(config *abapEnvironmentCreateTagOptions) (backlog []CreateTagBacklog, err error) {
if config.Repositories != "" && config.RepositoryName != "" {
return nil, errors.New("Configuring the parameter repositories and the parameter repositoryName at the same time is not allowed")
}
if config.RepositoryName != "" && config.CommitID != "" {
backlog = append(backlog, CreateTagBacklog{repositoryName: config.RepositoryName, commitID: config.CommitID})
}
if config.Repositories != "" {
descriptor, err := abaputils.ReadAddonDescriptor(config.Repositories) //config.Repositories should contain a file name
if err != nil {
return nil, err
}
for _, repo := range descriptor.Repositories {
backlogInstance := CreateTagBacklog{repositoryName: repo.Name, commitID: repo.CommitID}
if config.GenerateTagForAddonComponentVersion && repo.VersionYAML != "" {
tag := Tag{tagName: "v" + repo.VersionYAML, tagDescription: "Generated by the ABAP Environment Pipeline"}
backlogInstance.tags = append(backlogInstance.tags, tag)
}
backlog = append(backlog, backlogInstance)
}
if config.GenerateTagForAddonProductVersion {
if descriptor.AddonProduct != "" && descriptor.AddonVersionYAML != "" {
addonProductDash := strings.Replace(descriptor.AddonProduct, "/", "-", 2)
backlog = addTagToList(backlog, addonProductDash+"-"+descriptor.AddonVersionYAML, "Generated by the ABAP Environment Pipeline")
} else {
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")
}
}
}
if config.TagName != "" {
backlog = addTagToList(backlog, config.TagName, config.TagDescription)
}
return backlog, nil
}
func addTagToList(backlog []CreateTagBacklog, tag string, description string) []CreateTagBacklog {
for i, item := range backlog {
tag := Tag{tagName: tag, tagDescription: description}
backlog[i].tags = append(item.tags, tag)
}
return backlog
}
func convertTagConfig(config *abapEnvironmentCreateTagOptions) abaputils.AbapEnvironmentOptions {
subOptions := abaputils.AbapEnvironmentOptions{}
subOptions.CfAPIEndpoint = config.CfAPIEndpoint
subOptions.CfServiceInstance = config.CfServiceInstance
subOptions.CfServiceKeyName = config.CfServiceKeyName
subOptions.CfOrg = config.CfOrg
subOptions.CfSpace = config.CfSpace
subOptions.Host = config.Host
subOptions.Password = config.Password
subOptions.Username = config.Username
return subOptions
}
type CreateTagBacklog struct {
repositoryName string
commitID string
tags []Tag
}
type Tag struct {
tagName string
tagDescription string
}
type CreateTagBody struct {
RepositoryName string `json:"sc_name"`
CommitID string `json:"commit_id"`
Tag string `json:"tag_name"`
Description string `json:"tag_description"`
}
type CreateTagResponse struct {
UUID string `json:"uuid"`
}