github.com/xgoffin/jenkins-library@v1.154.0/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  }