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:
parent
ce161590ae
commit
6ff4143b08
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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).
|
||||
|
@ -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")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -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")
|
||||
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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).
|
||||
|
Loading…
x
Reference in New Issue
Block a user