1
0
mirror of https://github.com/SAP/jenkins-library.git synced 2025-01-18 05:18:24 +02:00

Execute checkout & pull when already cloned (#3850)

* Execute checkout & pull when already cloned

* Revert

* Disallow config overload

* Add custom error handler for clone

* Implement new pull parameters

* Add tests

* Formatting

* Rename Param

* Add comment

* Add docu

* Adapt testst to merge

* Fix Unit Test
This commit is contained in:
Daniel Mieg 2022-06-30 10:43:33 +02:00 committed by GitHub
parent ce161590ae
commit 6ff4143b08
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 383 additions and 47 deletions

View File

@ -74,7 +74,7 @@ func runAbapEnvironmentCheckoutBranch(options *abapEnvironmentCheckoutBranchOpti
if err != nil {
return fmt.Errorf("Something failed during the checkout: %w", err)
}
log.Entry().Info("-------------------------")
log.Entry().Infof("-------------------------")
log.Entry().Info("All branches were checked out successfully")
return nil
}
@ -189,15 +189,15 @@ func handleCheckout(repo abaputils.Repository, checkoutConnectionDetails abaputi
func startCheckoutLogs(branchName string, repositoryName string) {
log.Entry().Infof("Starting to switch branch to branch '%v' on repository '%v'", branchName, repositoryName)
log.Entry().Info("--------------------------------")
log.Entry().Infof("-------------------------")
log.Entry().Info("Start checkout branch: " + branchName)
log.Entry().Info("--------------------------------")
log.Entry().Infof("-------------------------")
}
func finishCheckoutLogs(branchName string, repositoryName string) {
log.Entry().Info("--------------------------------")
log.Entry().Infof("-------------------------")
log.Entry().Infof("Checkout of branch %v on repository %v was successful", branchName, repositoryName)
log.Entry().Info("--------------------------------")
log.Entry().Infof("-------------------------")
}
func convertCheckoutConfig(config *abapEnvironmentCheckoutBranchOptions) abaputils.AbapEnvironmentOptions {

View File

@ -4,6 +4,7 @@ import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"net/http/cookiejar"
"reflect"
"time"
@ -59,6 +60,11 @@ func runAbapEnvironmentCloneGitRepo(config *abapEnvironmentCloneGitRepoOptions,
Password: connectionDetails.Password,
})
errConfig := checkConfiguration(config)
if errConfig != nil {
return errors.Wrap(errConfig, "The provided configuration is not allowed")
}
repositories, errGetRepos := abaputils.GetRepositories(&abaputils.RepositoriesConfig{BranchName: config.BranchName, RepositoryName: config.RepositoryName, Repositories: config.Repositories}, true)
if errGetRepos != nil {
return fmt.Errorf("Something failed during the clone: %w", errGetRepos)
@ -75,12 +81,14 @@ func runAbapEnvironmentCloneGitRepo(config *abapEnvironmentCloneGitRepoOptions,
log.Entry().Info("-------------------------")
// Triggering the Clone of the repository into the ABAP Environment system
uriConnectionDetails, errorTriggerClone := triggerClone(repo, connectionDetails, client)
uriConnectionDetails, errorTriggerClone, didCheckoutPullInstead := triggerClone(repo, connectionDetails, client)
if errorTriggerClone != nil {
return errors.Wrapf(errorTriggerClone, errorString)
}
if !didCheckoutPullInstead {
// Polling the status of the repository import on the ABAP Environment system
// If the repository had been cloned already, as checkout/pull has been done - polling the status is not necessary anymore
status, errorPollEntity := abaputils.PollEntity(repo.Name, uriConnectionDetails, client, com.GetPollIntervall())
if errorPollEntity != nil {
return errors.Wrapf(errorPollEntity, errorString)
@ -88,15 +96,25 @@ func runAbapEnvironmentCloneGitRepo(config *abapEnvironmentCloneGitRepoOptions,
if status == "E" {
return errors.New("Clone of " + logString + " failed on the ABAP System")
}
log.Entry().Info("The " + logString + " was cloned successfully")
}
}
log.Entry().Info("-------------------------")
log.Entry().Info("All repositories were cloned successfully")
return nil
}
func triggerClone(repo abaputils.Repository, cloneConnectionDetails abaputils.ConnectionDetailsHTTP, client piperhttp.Sender) (abaputils.ConnectionDetailsHTTP, error) {
func checkConfiguration(config *abapEnvironmentCloneGitRepoOptions) error {
if config.Repositories != "" && config.RepositoryName != "" {
return errors.New("It is not allowed to configure the parameters `repositories`and `repositoryName` at the same time")
}
if config.Repositories == "" && config.RepositoryName == "" {
return errors.New("Please provide one of the following parameters: `repositories` or `repositoryName`")
}
return nil
}
func triggerClone(repo abaputils.Repository, cloneConnectionDetails abaputils.ConnectionDetailsHTTP, client piperhttp.Sender) (abaputils.ConnectionDetailsHTTP, error, bool) {
uriConnectionDetails := cloneConnectionDetails
cloneConnectionDetails.XCsrfToken = "fetch"
@ -107,7 +125,7 @@ func triggerClone(repo abaputils.Repository, cloneConnectionDetails abaputils.Co
resp, err := abaputils.GetHTTPResponse("HEAD", cloneConnectionDetails, nil, client)
if err != nil {
err = abaputils.HandleHTTPError(resp, err, "Authentication on the ABAP system failed", cloneConnectionDetails)
return uriConnectionDetails, err
return uriConnectionDetails, err, false
}
defer resp.Body.Close()
@ -117,14 +135,14 @@ func triggerClone(repo abaputils.Repository, cloneConnectionDetails abaputils.Co
// Trigger the Clone of a Repository
if repo.Name == "" {
return uriConnectionDetails, errors.New("An empty string was passed for the parameter 'repositoryName'")
return uriConnectionDetails, errors.New("An empty string was passed for the parameter 'repositoryName'"), false
}
jsonBody := []byte(repo.GetCloneRequestBody())
resp, err = abaputils.GetHTTPResponse("POST", cloneConnectionDetails, jsonBody, client)
if err != nil {
err = abaputils.HandleHTTPError(resp, err, "Could not clone the "+repo.GetCloneLogString(), uriConnectionDetails)
return uriConnectionDetails, err
err, alreadyCloned := handleCloneError(resp, err, cloneConnectionDetails, client, repo)
return uriConnectionDetails, err, alreadyCloned
}
defer resp.Body.Close()
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")
@ -134,20 +152,83 @@ func triggerClone(repo abaputils.Repository, cloneConnectionDetails abaputils.Co
var abapResp map[string]*json.RawMessage
bodyText, errRead := ioutil.ReadAll(resp.Body)
if errRead != nil {
return uriConnectionDetails, err
return uriConnectionDetails, err, false
}
json.Unmarshal(bodyText, &abapResp)
json.Unmarshal(*abapResp["d"], &body)
if reflect.DeepEqual(abaputils.CloneEntity{}, body) {
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")
err := errors.New("Request to ABAP System not successful")
return uriConnectionDetails, err
return uriConnectionDetails, err, false
}
// The entity "Clones" does not allow for polling. To poll the progress, the related entity "Pull" has to be called
// While "Clones" has the key fields UUID, SC_NAME and BRANCH_NAME, "Pull" only has the key field UUID
uriConnectionDetails.URL = uriConnectionDetails.URL + "/sap/opu/odata/sap/MANAGE_GIT_REPOSITORY/Pull(uuid=guid'" + body.UUID + "')"
return uriConnectionDetails, nil
return uriConnectionDetails, nil, false
}
func handleCloneError(resp *http.Response, err error, cloneConnectionDetails abaputils.ConnectionDetailsHTTP, client piperhttp.Sender, repo abaputils.Repository) (returnedError error, alreadyCloned bool) {
alreadyCloned = false
returnedError = nil
if resp == nil {
log.Entry().WithError(err).WithField("ABAP Endpoint", cloneConnectionDetails.URL).Error("Request failed")
returnedError = errors.New("Response is nil")
return
}
defer resp.Body.Close()
errorText, errorCode, parsingError := abaputils.GetErrorDetailsFromResponse(resp)
if parsingError != nil {
returnedError = err
return
}
if errorCode == "A4C_A2G/257" {
// With the latest release, a repeated "clone" was prohibited
// As an intermediate workaround, we react to the error message A4C_A2G/257 that gets thrown, if the repository had already been cloned
// In this case, a checkout branch and a pull will be performed
alreadyCloned = true
log.Entry().Infof("-------------------------")
log.Entry().Infof("-------------------------")
log.Entry().Infof("%s", "The repository / software component has already been cloned on the ABAP Environment system ")
log.Entry().Infof("%s", "A `checkout branch` and a `pull` will be performed instead")
log.Entry().Infof("-------------------------")
log.Entry().Infof("-------------------------")
checkoutOptions := abapEnvironmentCheckoutBranchOptions{
Username: cloneConnectionDetails.User,
Password: cloneConnectionDetails.Password,
Host: cloneConnectionDetails.Host,
RepositoryName: repo.Name,
BranchName: repo.Branch,
}
c := command.Command{}
c.Stdout(log.Writer())
c.Stderr(log.Writer())
com := abaputils.AbapUtils{
Exec: &c,
}
returnedError = runAbapEnvironmentCheckoutBranch(&checkoutOptions, &com, client)
if returnedError != nil {
return
}
log.Entry().Infof("-------------------------")
log.Entry().Infof("-------------------------")
pullOptions := *&abapEnvironmentPullGitRepoOptions{
Username: cloneConnectionDetails.User,
Password: cloneConnectionDetails.Password,
Host: cloneConnectionDetails.Host,
RepositoryName: repo.Name,
CommitID: repo.CommitID,
}
returnedError = runAbapEnvironmentPullGitRepo(&pullOptions, &com, client)
if returnedError != nil {
return
}
} else {
log.Entry().WithField("StatusCode", resp.Status).Error("Could not clone the " + repo.GetCloneLogString())
abapError := errors.New(fmt.Sprintf("%s - %s", errorCode, errorText))
returnedError = errors.Wrap(abapError, err.Error())
}
return
}
func convertCloneConfig(config *abapEnvironmentCloneGitRepoOptions) abaputils.AbapEnvironmentOptions {

View File

@ -43,7 +43,7 @@ func AbapEnvironmentCloneGitRepoCommand() *cobra.Command {
var createAbapEnvironmentCloneGitRepoCmd = &cobra.Command{
Use: STEP_NAME,
Short: "Clones a git repository to a SAP BTP ABAP Environment system",
Long: `Clones a git repository (Software Component) to a SAP BTP ABAP Environment system.
Long: `Clones a git repository (Software Component) to a SAP BTP ABAP Environment system. If the repository is already cloned, the step will checkout the configured branch and pull the specified commit, instead.
Please provide either of the following options:
* The host and credentials the BTP ABAP Environment system itself. The credentials must be configured for the Communication Scenario [SAP_COM_0510](https://help.sap.com/viewer/65de2977205c403bbc107264b8eccf4b/Cloud/en-US/b04a9ae412894725a2fc539bfb1ca055.html).

View File

@ -1,13 +1,16 @@
package cmd
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"os"
"testing"
"github.com/SAP/jenkins-library/pkg/abaputils"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
)
@ -31,7 +34,7 @@ func init() {
}
func TestCloneStep(t *testing.T) {
t.Run("Run Step - Successful", func(t *testing.T) {
t.Run("Run Step - Successful with repositories.yml", func(t *testing.T) {
var autils = abaputils.AUtilsMock{}
defer autils.Cleanup()
autils.ReturnedConnectionDetailsHTTP.Password = "password"
@ -73,8 +76,6 @@ repositories:
CfServiceKeyName: "testServiceKey",
Username: "testUser",
Password: "testPassword",
RepositoryName: "testRepo1",
BranchName: "testBranch1",
Repositories: "filename.yaml",
}
@ -95,13 +96,44 @@ repositories:
`{"d" : { "status" : "R" } }`,
`{"d" : { "status" : "R" } }`,
`{"d" : { "status" : "R" } }`,
},
Token: "myToken",
}
err := runAbapEnvironmentCloneGitRepo(&config, &autils, client)
assert.NoError(t, err, "Did not expect error")
assert.Equal(t, 0, len(client.BodyList), "Not all requests were done")
})
t.Run("Run Step - Successful with repositoryName", func(t *testing.T) {
var autils = abaputils.AUtilsMock{}
defer autils.Cleanup()
autils.ReturnedConnectionDetailsHTTP.Password = "password"
autils.ReturnedConnectionDetailsHTTP.User = "user"
autils.ReturnedConnectionDetailsHTTP.URL = "https://example.com"
autils.ReturnedConnectionDetailsHTTP.XCsrfToken = "xcsrftoken"
config := abapEnvironmentCloneGitRepoOptions{
CfAPIEndpoint: "https://api.endpoint.com",
CfOrg: "testOrg",
CfSpace: "testSpace",
CfServiceInstance: "testInstance",
CfServiceKeyName: "testServiceKey",
Username: "testUser",
Password: "testPassword",
RepositoryName: "testRepo1",
BranchName: "testBranch1",
}
logResultSuccess := fmt.Sprintf(`{"d": { "sc_name": "/DMO/SWC", "status": "S", "to_Log_Overview": { "results": [ { "log_index": 1, "log_name": "Main Import", "type_of_found_issues": "Success", "timestamp": "/Date(1644332299000+0000)/", "to_Log_Protocol": { "results": [ { "log_index": 1, "index_no": "1", "log_name": "", "type": "Info", "descr": "Main import", "timestamp": null, "criticality": 0 } ] } } ] } } }`)
client := &abaputils.ClientMock{
BodyList: []string{
`{"d" : ` + executionLogStringClone + `}`,
logResultSuccess,
`{"d" : { "EntitySets" : [ "LogOverviews" ] } }`,
`{"d" : { "status" : "S" } }`,
`{"d" : { "status" : "R" } }`,
`{"d" : { "status" : "R" } }`,
`{"d" : { "status" : "R" } }`,
},
Token: "myToken",
StatusCode: 200,
@ -299,8 +331,6 @@ repositories:
CfServiceKeyName: "testServiceKey",
Username: "testUser",
Password: "testPassword",
RepositoryName: "testRepo1",
BranchName: "testBranch1",
Repositories: "filename.yaml",
}
@ -319,4 +349,230 @@ repositories:
}
})
t.Run("Config overload", func(t *testing.T) {
var autils = abaputils.AUtilsMock{}
defer autils.Cleanup()
autils.ReturnedConnectionDetailsHTTP.Password = "password"
autils.ReturnedConnectionDetailsHTTP.User = "user"
autils.ReturnedConnectionDetailsHTTP.URL = "https://example.com"
autils.ReturnedConnectionDetailsHTTP.XCsrfToken = "xcsrftoken"
config := abapEnvironmentCloneGitRepoOptions{
CfAPIEndpoint: "https://api.endpoint.com",
CfOrg: "testOrg",
CfSpace: "testSpace",
CfServiceInstance: "testInstance",
CfServiceKeyName: "testServiceKey",
Username: "testUser",
Password: "testPassword",
Repositories: "filename.yaml",
RepositoryName: "/DMO/REPO",
BranchName: "Branch",
}
logResultError := fmt.Sprintf(`{"d": { "sc_name": "/DMO/SWC", "status": "S", "to_Log_Overview": { "results": [ { "log_index": 1, "log_name": "Main Import", "type_of_found_issues": "Error", "timestamp": "/Date(1644332299000+0000)/", "to_Log_Protocol": { "results": [ { "log_index": 1, "index_no": "1", "log_name": "", "type": "Info", "descr": "Main import", "timestamp": null, "criticality": 0 } ] } } ] } } }`)
client := &abaputils.ClientMock{
BodyList: []string{
logResultError,
`{"d" : { "EntitySets" : [ "LogOverviews" ] } }`,
`{"d" : { "status" : "E" } }`,
`{"d" : { "status" : "R" } }`,
`{"d" : { "status" : "R" } }`,
},
Token: "myToken",
StatusCode: 200,
}
err := runAbapEnvironmentCloneGitRepo(&config, &autils, client)
if assert.Error(t, err, "Expected error") {
assert.Equal(t, "The provided configuration is not allowed: It is not allowed to configure the parameters `repositories`and `repositoryName` at the same time", err.Error(), "Expected different error message")
}
})
}
func TestALreadyCloned(t *testing.T) {
t.Run("Already Cloned", func(t *testing.T) {
var autils = abaputils.AUtilsMock{}
defer autils.Cleanup()
autils.ReturnedConnectionDetailsHTTP.Password = "password"
autils.ReturnedConnectionDetailsHTTP.User = "user"
autils.ReturnedConnectionDetailsHTTP.URL = "https://example.com"
autils.ReturnedConnectionDetailsHTTP.Host = "example.com"
autils.ReturnedConnectionDetailsHTTP.XCsrfToken = "xcsrftoken"
logResultSuccess := fmt.Sprintf(`{"d": { "sc_name": "/DMO/SWC", "status": "S", "to_Log_Overview": { "results": [ { "log_index": 1, "log_name": "Main Import", "type_of_found_issues": "Success", "timestamp": "/Date(1644332299000+0000)/", "to_Log_Protocol": { "results": [ { "log_index": 1, "index_no": "1", "log_name": "", "type": "Info", "descr": "Main import", "timestamp": null, "criticality": 0 } ] } } ] } } }`)
client := &abaputils.ClientMock{
BodyList: []string{
`{"d" : ` + executionLogStringClone + `}`,
logResultSuccess,
`{"d" : { "EntitySets" : [ "LogOverviews" ] } }`,
`{"d" : { "status" : "S" } }`,
`{"d" : { "status" : "R" } }`,
`{"d" : { "status" : "R" } }`,
`{"d" : ` + executionLogStringClone + `}`,
logResultSuccess,
`{"d" : { "EntitySets" : [ "LogOverviews" ] } }`,
`{"d" : { "status" : "S" } }`,
`{"d" : { "status" : "R" } }`,
`{"d" : { "status" : "R" } }`,
},
Token: "myToken",
StatusCode: 200,
}
bodyString := `{"error" : { "code" : "A4C_A2G/257", "message" : { "lang" : "de", "value" : "Already Cloned"} } }`
body := []byte(bodyString)
resp := http.Response{
Status: "400 Bad Request",
StatusCode: 400,
Body: ioutil.NopCloser(bytes.NewReader(body)),
}
repo := abaputils.Repository{
Name: "Test",
Branch: "Branch",
CommitID: "abcd1234",
}
err := errors.New("Custom Error")
err, _ = handleCloneError(&resp, err, autils.ReturnedConnectionDetailsHTTP, client, repo)
assert.NoError(t, err, "Did not expect error")
})
t.Run("Already Cloned, Pull fails", func(t *testing.T) {
var autils = abaputils.AUtilsMock{}
defer autils.Cleanup()
autils.ReturnedConnectionDetailsHTTP.Password = "password"
autils.ReturnedConnectionDetailsHTTP.User = "user"
autils.ReturnedConnectionDetailsHTTP.URL = "https://example.com"
autils.ReturnedConnectionDetailsHTTP.Host = "example.com"
autils.ReturnedConnectionDetailsHTTP.XCsrfToken = "xcsrftoken"
logResultSuccess := fmt.Sprintf(`{"d": { "sc_name": "/DMO/SWC", "status": "S", "to_Log_Overview": { "results": [ { "log_index": 1, "log_name": "Main Import", "type_of_found_issues": "Success", "timestamp": "/Date(1644332299000+0000)/", "to_Log_Protocol": { "results": [ { "log_index": 1, "index_no": "1", "log_name": "", "type": "Info", "descr": "Main import", "timestamp": null, "criticality": 0 } ] } } ] } } }`)
client := &abaputils.ClientMock{
BodyList: []string{
`{"d" : ` + executionLogStringClone + `}`,
logResultSuccess,
`{"d" : { "EntitySets" : [ "LogOverviews" ] } }`,
`{"d" : { "status" : "E" } }`,
`{"d" : { "status" : "R" } }`,
`{"d" : { "status" : "R" } }`,
`{"d" : ` + executionLogStringClone + `}`,
logResultSuccess,
`{"d" : { "EntitySets" : [ "LogOverviews" ] } }`,
`{"d" : { "status" : "S" } }`,
`{"d" : { "status" : "R" } }`,
`{"d" : { "status" : "R" } }`,
},
Token: "myToken",
StatusCode: 200,
}
bodyString := `{"error" : { "code" : "A4C_A2G/257", "message" : { "lang" : "de", "value" : "Already Cloned"} } }`
body := []byte(bodyString)
resp := http.Response{
Status: "400 Bad Request",
StatusCode: 400,
Body: ioutil.NopCloser(bytes.NewReader(body)),
}
repo := abaputils.Repository{
Name: "Test",
Branch: "Branch",
CommitID: "abcd1234",
}
err := errors.New("Custom Error")
err, _ = handleCloneError(&resp, err, autils.ReturnedConnectionDetailsHTTP, client, repo)
if assert.Error(t, err, "Expected error") {
assert.Equal(t, "Pull of the repository / software component 'Test', commit 'abcd1234' failed on the ABAP system", err.Error(), "Expected different error message")
}
})
t.Run("Already Cloned, checkout fails", func(t *testing.T) {
var autils = abaputils.AUtilsMock{}
defer autils.Cleanup()
autils.ReturnedConnectionDetailsHTTP.Password = "password"
autils.ReturnedConnectionDetailsHTTP.User = "user"
autils.ReturnedConnectionDetailsHTTP.URL = "https://example.com"
autils.ReturnedConnectionDetailsHTTP.Host = "example.com"
autils.ReturnedConnectionDetailsHTTP.XCsrfToken = "xcsrftoken"
logResultSuccess := fmt.Sprintf(`{"d": { "sc_name": "/DMO/SWC", "status": "S", "to_Log_Overview": { "results": [ { "log_index": 1, "log_name": "Main Import", "type_of_found_issues": "Success", "timestamp": "/Date(1644332299000+0000)/", "to_Log_Protocol": { "results": [ { "log_index": 1, "index_no": "1", "log_name": "", "type": "Info", "descr": "Main import", "timestamp": null, "criticality": 0 } ] } } ] } } }`)
client := &abaputils.ClientMock{
BodyList: []string{
logResultSuccess,
`{"d" : { "EntitySets" : [ "LogOverviews" ] } }`,
`{"d" : { "status" : "S" } }`,
`{"d" : { "status" : "R" } }`,
`{"d" : { "status" : "R" } }`,
logResultSuccess,
`{"d" : { "EntitySets" : [ "LogOverviews" ] } }`,
`{"d" : { "status" : "E" } }`,
`{"d" : { "status" : "R" } }`,
`{"d" : { "status" : "R" } }`,
},
Token: "myToken",
StatusCode: 200,
}
bodyString := `{"error" : { "code" : "A4C_A2G/257", "message" : { "lang" : "de", "value" : "Already Cloned"} } }`
body := []byte(bodyString)
resp := http.Response{
Status: "400 Bad Request",
StatusCode: 400,
Body: ioutil.NopCloser(bytes.NewReader(body)),
}
repo := abaputils.Repository{
Name: "Test",
Branch: "Branch",
CommitID: "abcd1234",
}
err := errors.New("Custom Error")
err, _ = handleCloneError(&resp, err, autils.ReturnedConnectionDetailsHTTP, client, repo)
if assert.Error(t, err, "Expected error") {
assert.Equal(t, "Something failed during the checkout: Checkout failed: Checkout of branch Branch failed on the ABAP System", err.Error(), "Expected different error message")
}
})
t.Run("Already Cloned, checkout fails", func(t *testing.T) {
var autils = abaputils.AUtilsMock{}
defer autils.Cleanup()
autils.ReturnedConnectionDetailsHTTP.Password = "password"
autils.ReturnedConnectionDetailsHTTP.User = "user"
autils.ReturnedConnectionDetailsHTTP.URL = "https://example.com"
autils.ReturnedConnectionDetailsHTTP.Host = "example.com"
autils.ReturnedConnectionDetailsHTTP.XCsrfToken = "xcsrftoken"
client := &abaputils.ClientMock{
BodyList: []string{
`{"d" : { "status" : "R" } }`,
},
Token: "myToken",
StatusCode: 200,
}
bodyString := `{"error" : { "code" : "A4C_A2G/258", "message" : { "lang" : "de", "value" : "Some error message"} } }`
body := []byte(bodyString)
resp := http.Response{
Status: "400 Bad Request",
StatusCode: 400,
Body: ioutil.NopCloser(bytes.NewReader(body)),
}
repo := abaputils.Repository{
Name: "Test",
Branch: "Branch",
CommitID: "abcd1234",
}
err := errors.New("Custom Error")
err, _ = handleCloneError(&resp, err, autils.ReturnedConnectionDetailsHTTP, client, repo)
if assert.Error(t, err, "Expected error") {
assert.Equal(t, "Custom Error: A4C_A2G/258 - Some error message", err.Error(), "Expected different error message")
}
})
}

View File

@ -176,40 +176,39 @@ func HandleHTTPError(resp *http.Response, err error, message string, connectionD
log.Entry().WithField("StatusCode", resp.Status).Error(message)
errorDetails, parsingError := getErrorDetailsFromResponse(resp)
errorText, errorCode, parsingError := GetErrorDetailsFromResponse(resp)
if parsingError != nil {
return err
}
abapError := errors.New(errorDetails)
abapError := errors.New(fmt.Sprintf("%s - %s", errorCode, errorText))
err = errors.Wrap(abapError, err.Error())
}
return err
}
func getErrorDetailsFromResponse(resp *http.Response) (errorString string, err error) {
func GetErrorDetailsFromResponse(resp *http.Response) (errorString string, errorCode string, err error) {
// Include the error message of the ABAP Environment system, if available
var abapErrorResponse AbapError
bodyText, readError := ioutil.ReadAll(resp.Body)
if readError != nil {
return errorString, readError
return "", "", readError
}
var abapResp map[string]*json.RawMessage
errUnmarshal := json.Unmarshal(bodyText, &abapResp)
if errUnmarshal != nil {
return errorString, errUnmarshal
return "", "", errUnmarshal
}
if _, ok := abapResp["error"]; ok {
json.Unmarshal(*abapResp["error"], &abapErrorResponse)
if (AbapError{}) != abapErrorResponse {
log.Entry().WithField("ErrorCode", abapErrorResponse.Code).Error(abapErrorResponse.Message.Value)
errorString = fmt.Sprintf("%s - %s", abapErrorResponse.Code, abapErrorResponse.Message.Value)
return errorString, nil
log.Entry().WithField("ErrorCode", abapErrorResponse.Code).Debug(abapErrorResponse.Message.Value)
return abapErrorResponse.Message.Value, abapErrorResponse.Code, nil
}
}
return errorString, errors.New("Could not parse the JSON error response")
return "", "", errors.New("Could not parse the JSON error response")
}

View File

@ -28,7 +28,7 @@ func PollEntity(repositoryName string, connectionDetails ConnectionDetailsHTTP,
return status, err
}
status = pullEntity.Status
log.Entry().WithField("StatusCode", responseStatus).Info("Pull Status: " + pullEntity.StatusDescription)
log.Entry().WithField("StatusCode", responseStatus).Info("Status: " + pullEntity.StatusDescription)
if pullEntity.Status != "R" {
printTransportLogs := true
if serviceContainsNewLogEntities(connectionDetails, client) {
@ -233,13 +233,13 @@ func GetStatus(failureMessage string, connectionDetails ConnectionDetailsHTTP, c
var abapResp map[string]*json.RawMessage
bodyText, _ := ioutil.ReadAll(resp.Body)
json.Unmarshal(bodyText, &abapResp)
if err != nil {
return body, resp.Status, errors.Wrap(err, "Could not read response")
marshallError := json.Unmarshal(bodyText, &abapResp)
if marshallError != nil {
return body, status, errors.Wrap(marshallError, "Could not parse response from the ABAP Environment system")
}
json.Unmarshal(*abapResp["d"], &body)
if err != nil {
return body, resp.Status, errors.Wrap(err, "Could not read response")
marshallError = json.Unmarshal(*abapResp["d"], &body)
if marshallError != nil {
return body, status, errors.Wrap(marshallError, "Could not parse response from the ABAP Environment system")
}
if reflect.DeepEqual(PullEntity{}, body) {

View File

@ -2,7 +2,7 @@ metadata:
name: abapEnvironmentCloneGitRepo
description: Clones a git repository to a SAP BTP ABAP Environment system
longDescription: |
Clones a git repository (Software Component) to a SAP BTP ABAP Environment system.
Clones a git repository (Software Component) to a SAP BTP ABAP Environment system. If the repository is already cloned, the step will checkout the configured branch and pull the specified commit, instead.
Please provide either of the following options:
* The host and credentials the BTP ABAP Environment system itself. The credentials must be configured for the Communication Scenario [SAP_COM_0510](https://help.sap.com/viewer/65de2977205c403bbc107264b8eccf4b/Cloud/en-US/b04a9ae412894725a2fc539bfb1ca055.html).