1
0
mirror of https://github.com/SAP/jenkins-library.git synced 2025-11-06 09:09:19 +02:00

Adapt clone step to work with customer-managed Repos (BYOG) (#4966)

* adding byog credentials for clone command

* adding unit tests for clone body

* adding parameters

* adding optional byog parameters

* fixing typo in username

* remove aliases in config yaml

* change yaml config

* logs

* change info log

* change logs

* remove logs

* adding log statements

* remove log statements

* fixing typo in test class

* change repoTest structure

* remove comment

* remove comment

* generate

* adding unit test comments

* adding error handling

* adding isByog check

* fixing unit test

* generate

* Update manageGitRepositoryUtils_test.go

* restructure isByog parameter

* adding empty line for md linter

* adding config.yaml example to docs

* Update documentation/docs/steps/abapEnvironmentCloneGitRepo.md

Co-authored-by: Daniel Mieg <56156797+DanielMieg@users.noreply.github.com>

* Update documentation/docs/steps/abapEnvironmentCloneGitRepo.md

Co-authored-by: Daniel Mieg <56156797+DanielMieg@users.noreply.github.com>

* Update documentation/docs/steps/abapEnvironmentCloneGitRepo.md

Co-authored-by: Daniel Mieg <56156797+DanielMieg@users.noreply.github.com>

* Update documentation/docs/steps/abapEnvironmentCloneGitRepo.md

Co-authored-by: Daniel Mieg <56156797+DanielMieg@users.noreply.github.com>

* Update documentation/docs/steps/abapEnvironmentCloneGitRepo.md

Co-authored-by: Daniel Mieg <56156797+DanielMieg@users.noreply.github.com>

* adding release

---------

Co-authored-by: Daniel Mieg <56156797+DanielMieg@users.noreply.github.com>
This commit is contained in:
Simon Dold
2024-06-25 10:09:31 +02:00
committed by GitHub
parent b9022dc10d
commit 65dbd4526c
14 changed files with 281 additions and 44 deletions

View File

@@ -285,6 +285,9 @@ type AbapEnvironmentRunATCCheckOptions struct {
type AbapEnvironmentOptions struct {
Username string `json:"username,omitempty"`
Password string `json:"password,omitempty"`
ByogUsername string `json:"byogUsername,omitempty"`
ByogPassword string `json:"byogPassword,omitempty"`
ByogAuthMethod string `json:"byogAuthMethod,omitempty"`
Host string `json:"host,omitempty"`
CfAPIEndpoint string `json:"cfApiEndpoint,omitempty"`
CfOrg string `json:"cfOrg,omitempty"`

View File

@@ -42,6 +42,10 @@ type Repository struct {
Tag string `json:"tag,omitempty"`
Branch string `json:"branch,omitempty"`
CommitID string `json:"commitID,omitempty"`
ByogUsername string `json:"byogUsername"`
ByogPassword string `json:"byogPassword"`
ByogAuthMethod string `json:"byogAuthMethod"`
IsByog bool `json:",omitempty"`
VersionYAML string `json:"version,omitempty"`
Version string `json:"versionAAK"`
AdditionalPiecelist string `json:"additionalPiecelist,omitempty"`

View File

@@ -163,7 +163,7 @@ func printHeader(logEntry LogResultsV2, api SoftwareComponentApiInterface) {
}
}
// GetRepositories for parsing one or multiple branches and repositories from repositories file or branchName and repositoryName configuration
// GetRepositories for parsing one or multiple branches and repositories from repositories file or branchName and repositoryName configuration
func GetRepositories(config *RepositoriesConfig, branchRequired bool) ([]Repository, error) {
var repositories = make([]Repository, 0)
if reflect.DeepEqual(RepositoriesConfig{}, config) {
@@ -193,6 +193,7 @@ func GetRepositories(config *RepositoriesConfig, branchRequired bool) ([]Reposit
if config.RepositoryName != "" && !branchRequired {
repositories = append(repositories, Repository{Name: config.RepositoryName, CommitID: config.CommitID})
}
if len(config.RepositoryNames) > 0 {
for _, repository := range config.RepositoryNames {
repositories = append(repositories, Repository{Name: repository})
@@ -210,6 +211,25 @@ func (repo *Repository) GetRequestBodyForCommitOrTag() (requestBodyString string
return requestBodyString
}
func (repo *Repository) GetRequestBodyForBYOGCredentials() (string, error) {
var byogBodyString string
if repo.ByogAuthMethod != "" {
byogBodyString += `, "auth_method":"` + repo.ByogAuthMethod + `"`
}
if repo.ByogUsername != "" {
byogBodyString += `, "username":"` + repo.ByogUsername + `"`
} else {
return "", fmt.Errorf("Failed to get BYOG credentials: %w", errors.New("Username for BYOG is missing, please provide git username to authenticate"))
}
if repo.ByogPassword != "" {
byogBodyString += `, "password":"` + repo.ByogPassword + `"`
} else {
return "", fmt.Errorf("Failed to get BYOG credentials: %w", errors.New("Password/Token for BYOG is missing, please provide git password or token to authenticate"))
}
return byogBodyString, nil
}
func (repo *Repository) GetLogStringForCommitOrTag() (logString string) {
if repo.CommitID != "" {
logString = ", commit '" + repo.CommitID + "'"
@@ -228,13 +248,21 @@ func (repo *Repository) GetCloneRequestBodyWithSWC() (body string) {
return body
}
func (repo *Repository) GetCloneRequestBody() (body string) {
func (repo *Repository) GetCloneRequestBody() (body string, err error) {
if repo.CommitID != "" && repo.Tag != "" {
log.Entry().WithField("Tag", repo.Tag).WithField("Commit ID", repo.CommitID).Info("The commit ID takes precedence over the tag")
}
requestBodyString := repo.GetRequestBodyForCommitOrTag()
body = `{"branch_name":"` + repo.Branch + `"` + requestBodyString + `}`
return body
var byogBodyString = ""
if repo.IsByog {
byogBodyString, err = repo.GetRequestBodyForBYOGCredentials()
if err != nil {
return "", err
}
}
body = `{"branch_name":"` + repo.Branch + `"` + requestBodyString + byogBodyString + `}`
return body, nil
}
func (repo *Repository) GetCloneLogString() (logString string) {

View File

@@ -268,7 +268,7 @@ func TestCreateRequestBodies(t *testing.T) {
CommitID: "1234567",
Tag: "myTag",
}
body := repo.GetCloneRequestBody()
body, _ := repo.GetCloneRequestBody()
assert.Equal(t, `{"branch_name":"main", "commit_id":"1234567"}`, body, "Expected different body")
})
t.Run("Clone Body Tag", func(t *testing.T) {

View File

@@ -225,10 +225,10 @@ func (api *SAP_COM_0510) GetAction() (string, error) {
return abapStatusCode, nil
}
func (api *SAP_COM_0510) GetRepository() (bool, string, error) {
func (api *SAP_COM_0510) GetRepository() (bool, string, error, bool) {
if api.repository.Name == "" {
return false, "", errors.New("An empty string was passed for the parameter 'repositoryName'")
return false, "", errors.New("An empty string was passed for the parameter 'repositoryName'"), false
}
swcConnectionDetails := api.con
@@ -236,7 +236,7 @@ func (api *SAP_COM_0510) GetRepository() (bool, string, error) {
resp, err := GetHTTPResponse("GET", swcConnectionDetails, nil, api.client)
if err != nil {
_, errRepo := HandleHTTPError(resp, err, "Reading the Repository / Software Component failed", api.con)
return false, "", errRepo
return false, "", errRepo, false
}
defer resp.Body.Close()
@@ -244,25 +244,25 @@ func (api *SAP_COM_0510) GetRepository() (bool, string, error) {
var abapResp map[string]*json.RawMessage
bodyText, errRead := io.ReadAll(resp.Body)
if errRead != nil {
return false, "", err
return false, "", err, false
}
if err := json.Unmarshal(bodyText, &abapResp); err != nil {
return false, "", err
return false, "", err, false
}
if err := json.Unmarshal(*abapResp["d"], &body); err != nil {
return false, "", err
return false, "", err, false
}
if reflect.DeepEqual(RepositoryEntity{}, body) {
log.Entry().WithField("StatusCode", resp.Status).WithField("repositoryName", api.repository.Name).WithField("branchName", api.repository.Branch).WithField("commitID", api.repository.CommitID).WithField("Tag", api.repository.Tag).Error("Could not Clone the Repository / Software Component")
err := errors.New("Request to ABAP System not successful")
return false, "", err
return false, "", err, false
}
if body.AvailOnInst {
return true, body.ActiveBranch, nil
return true, body.ActiveBranch, nil, false
}
return false, "", err
return false, "", err, false
}
@@ -399,3 +399,8 @@ func (api *SAP_COM_0510) ConvertTime(logTimeStamp string) time.Time {
t := time.Unix(n, 0).UTC()
return t
}
// Dummy implementation of the "optional" method UpdateRepoWithBYOGCredentials (only used in SAP_COM_0948)
func (api *SAP_COM_0510) UpdateRepoWithBYOGCredentials(byogAuthMethod string, byogUsername string, byogPassword string) {
panic("UpdateRepoWithBYOGCredentials cannot be used in SAP_COM_0510")
}

View File

@@ -368,7 +368,7 @@ func TestGetRepo(t *testing.T) {
assert.NoError(t, err)
assert.IsType(t, &SAP_COM_0510{}, api.(*SAP_COM_0510), "API has wrong type")
cloned, activeBranch, errAction := api.GetRepository()
cloned, activeBranch, errAction, _ := api.GetRepository()
assert.True(t, cloned)
assert.Equal(t, "testBranch1", activeBranch)
assert.NoError(t, errAction)

View File

@@ -238,10 +238,10 @@ func (api *SAP_COM_0948) GetAction() (string, error) {
return abapStatusCode, nil
}
func (api *SAP_COM_0948) GetRepository() (bool, string, error) {
func (api *SAP_COM_0948) GetRepository() (bool, string, error, bool) {
if api.repository.Name == "" {
return false, "", errors.New("An empty string was passed for the parameter 'repositoryName'")
return false, "", errors.New("An empty string was passed for the parameter 'repositoryName'"), false
}
swcConnectionDetails := api.con
@@ -249,30 +249,42 @@ func (api *SAP_COM_0948) GetRepository() (bool, string, error) {
resp, err := GetHTTPResponse("GET", swcConnectionDetails, nil, api.client)
if err != nil {
_, errRepo := HandleHTTPError(resp, err, "Reading the Repository / Software Component failed", api.con)
return false, "", errRepo
return false, "", errRepo, false
}
defer resp.Body.Close()
var body RepositoryEntity
bodyText, errRead := io.ReadAll(resp.Body)
if errRead != nil {
return false, "", err
return false, "", err, false
}
if err := json.Unmarshal(bodyText, &body); err != nil {
return false, "", err
return false, "", err, false
}
if reflect.DeepEqual(RepositoryEntity{}, body) {
log.Entry().WithField("StatusCode", resp.Status).WithField("repositoryName", api.repository.Name).WithField("branchName", api.repository.Branch).WithField("commitID", api.repository.CommitID).WithField("Tag", api.repository.Tag).Error("Could not Clone the Repository / Software Component")
err := errors.New("Request to ABAP System not successful")
return false, "", err
return false, "", err, false
}
if body.AvailOnInst {
return true, body.ActiveBranch, nil
return true, body.ActiveBranch, nil, false
}
return false, "", err
if body.ByogUrl != "" {
return false, "", err, true
}
return false, "", err, false
}
func (api *SAP_COM_0948) UpdateRepoWithBYOGCredentials(byogAuthMethod string, byogUsername string, byogPassword string) {
api.repository.ByogAuthMethod = byogAuthMethod
api.repository.ByogUsername = byogUsername
api.repository.ByogPassword = byogPassword
api.repository.IsByog = true
}
func (api *SAP_COM_0948) Clone() error {
@@ -284,9 +296,12 @@ func (api *SAP_COM_0948) Clone() error {
cloneConnectionDetails := api.con
cloneConnectionDetails.URL = api.con.URL + api.path + api.softwareComponentEntity + api.getRepoNameForPath() + api.cloneAction
body := []byte(api.repository.GetCloneRequestBody())
body, err := api.repository.GetCloneRequestBody()
if err != nil {
return errors.Wrap(err, "Failed to clone repository")
}
return api.triggerRequest(cloneConnectionDetails, body)
return api.triggerRequest(cloneConnectionDetails, []byte(body))
}

View File

@@ -23,6 +23,11 @@ func init() {
repoTest0948.Name = "/DMO/REPO"
repoTest0948.Branch = "main"
repoTest0948.IsByog = false
repoTest0948.ByogAuthMethod = "token"
repoTest0948.ByogUsername = "byogUser"
repoTest0948.ByogPassword = "byogToken"
}
func TestRetry0948(t *testing.T) {
@@ -52,7 +57,7 @@ func TestRetry0948(t *testing.T) {
errAction := api.(*SAP_COM_0948).triggerRequest(ConnectionDetailsHTTP{User: "CC_USER", Password: "abc123", URL: "https://example.com/path"}, []byte("{}"))
assert.NoError(t, errAction)
assert.Equal(t, "GUID", api.getUUID(), "API does not cotain correct UUID")
assert.Equal(t, "GUID", api.getUUID(), "API does not contain correct UUID")
})
@@ -82,7 +87,7 @@ func TestRetry0948(t *testing.T) {
errAction := api.(*SAP_COM_0948).triggerRequest(ConnectionDetailsHTTP{User: "CC_USER", Password: "abc123", URL: "https://example.com/path"}, []byte("{}"))
assert.ErrorContains(t, errAction, "HTTP 400: A4C_A2G/224 - Error Text")
assert.Empty(t, api.getUUID(), "API does not cotain correct UUID")
assert.Empty(t, api.getUUID(), "API does not contain correct UUID")
})
@@ -128,7 +133,7 @@ func TestRetry0948(t *testing.T) {
errAction := api.(*SAP_COM_0948).triggerRequest(ConnectionDetailsHTTP{User: "CC_USER", Password: "abc123", URL: "https://example.com/path"}, []byte("{}"))
assert.ErrorContains(t, errAction, "HTTP 400: A4C_A2G/228 - Error Text")
assert.Empty(t, api.getUUID(), "API does not cotain correct UUID")
assert.Empty(t, api.getUUID(), "API does not contain correct UUID")
assert.Equal(t, 6, len(client.BodyList), "Expected maxSleepTime to limit requests")
})
@@ -175,7 +180,7 @@ func TestRetry0948(t *testing.T) {
errAction := api.(*SAP_COM_0948).triggerRequest(ConnectionDetailsHTTP{User: "CC_USER", Password: "abc123", URL: "https://example.com/path"}, []byte("{}"))
assert.ErrorContains(t, errAction, "HTTP 400: A4C_A2G/228 - Error Text")
assert.Empty(t, api.getUUID(), "API does not cotain correct UUID")
assert.Empty(t, api.getUUID(), "API does not contain correct UUID")
assert.Equal(t, 5, len(client.BodyList), "Expected maxRetries to limit requests")
})
@@ -201,7 +206,7 @@ func TestClone0948(t *testing.T) {
errClone := api.Clone()
assert.NoError(t, errClone)
assert.Equal(t, "GUID", api.getUUID(), "API does not cotain correct UUID")
assert.Equal(t, "GUID", api.getUUID(), "API does not contain correct UUID")
})
t.Run("Test Clone Failure", func(t *testing.T) {
@@ -225,7 +230,7 @@ func TestClone0948(t *testing.T) {
errClone := api.Clone()
assert.ErrorContains(t, errClone, "Request to ABAP System not successful")
assert.Empty(t, api.getUUID(), "API does not cotain correct UUID")
assert.Empty(t, api.getUUID(), "API does not contain correct UUID")
})
t.Run("Test Clone Retry", func(t *testing.T) {
@@ -254,8 +259,48 @@ func TestClone0948(t *testing.T) {
errClone := api.Clone()
assert.NoError(t, errClone)
assert.Equal(t, "GUID", api.getUUID(), "API does not cotain correct UUID")
assert.Equal(t, "GUID", api.getUUID(), "API does not contain correct UUID")
})
t.Run("Test Clone Body Success", func(t *testing.T) {
cloneBody, _ := repoTest0948.GetCloneRequestBody()
assert.Equal(t, "{\"branch_name\":\"main\"}", string([]byte(cloneBody)), "Clone body is not correct")
})
t.Run("Test Clone Body Failure", func(t *testing.T) {
repoTest0948.Branch = "wrongBranch"
cloneBody, _ := repoTest0948.GetCloneRequestBody()
assert.NotEqual(t, "{\"branch_name\":\"main\"}", string([]byte(cloneBody)), "Clone body should not match")
repoTest0948.Branch = "main"
})
t.Run("Test Clone Body BYOG Success", func(t *testing.T) {
repoTest0948.IsByog = true
cloneBody, _ := repoTest0948.GetCloneRequestBody()
assert.Equal(t, "{\"branch_name\":\"main\", \"auth_method\":\"token\", \"username\":\"byogUser\", \"password\":\"byogToken\"}", string([]byte(cloneBody)), "Clone body for byog parameter is not correct")
repoTest0948.IsByog = false
})
t.Run("Test Clone Body BYOG Failure", func(t *testing.T) {
repoTest0948.ByogPassword = "wrongToken"
repoTest0948.IsByog = true
cloneBody, _ := repoTest0948.GetCloneRequestBody()
assert.NotEqual(t, "{\"branch_name\":\"main\", \"auth_method\":\"token\", \"username\":\"byogUser\", \"password\":\"byogToken\"}", string([]byte(cloneBody)), "Clone body for byog parameter should not match")
repoTest0948.ByogPassword = "byogToken"
repoTest0948.IsByog = false
})
}
func TestPull0948(t *testing.T) {
@@ -278,7 +323,7 @@ func TestPull0948(t *testing.T) {
errPull := api.Pull()
assert.NoError(t, errPull)
assert.Equal(t, "GUID", api.getUUID(), "API does not cotain correct UUID")
assert.Equal(t, "GUID", api.getUUID(), "API does not contain correct UUID")
})
t.Run("Test Pull Failure", func(t *testing.T) {
@@ -300,7 +345,7 @@ func TestPull0948(t *testing.T) {
errPull := api.Pull()
assert.ErrorContains(t, errPull, "Request to ABAP System not successful")
assert.Empty(t, api.getUUID(), "API does not cotain correct UUID")
assert.Empty(t, api.getUUID(), "API does not contain correct UUID")
})
}
@@ -324,7 +369,7 @@ func TestCheckout0948(t *testing.T) {
errCheckout := api.CheckoutBranch()
assert.NoError(t, errCheckout)
assert.Equal(t, "GUID", api.getUUID(), "API does not cotain correct UUID")
assert.Equal(t, "GUID", api.getUUID(), "API does not contain correct UUID")
})
t.Run("Test Checkout Failure", func(t *testing.T) {
@@ -346,7 +391,7 @@ func TestCheckout0948(t *testing.T) {
errCheckoput := api.CheckoutBranch()
assert.ErrorContains(t, errCheckoput, "Request to ABAP System not successful")
assert.Empty(t, api.getUUID(), "API does not cotain correct UUID")
assert.Empty(t, api.getUUID(), "API does not contain correct UUID")
})
}
@@ -368,7 +413,7 @@ func TestGetRepo0948(t *testing.T) {
assert.NoError(t, err)
assert.IsType(t, &SAP_COM_0948{}, api.(*SAP_COM_0948), "API has wrong type")
cloned, activeBranch, errAction := api.GetRepository()
cloned, activeBranch, errAction, _ := api.GetRepository()
assert.True(t, cloned)
assert.Equal(t, "testBranch1", activeBranch)
assert.NoError(t, errAction)
@@ -395,7 +440,7 @@ func TestCreateTag0948(t *testing.T) {
errCreateTag := api.CreateTag(Tag{TagName: "myTag", TagDescription: "descr"})
assert.NoError(t, errCreateTag)
assert.Equal(t, "GUID", api.getUUID(), "API does not cotain correct UUID")
assert.Equal(t, "GUID", api.getUUID(), "API does not contain correct UUID")
})
t.Run("Test Tag Failure", func(t *testing.T) {
@@ -417,7 +462,7 @@ func TestCreateTag0948(t *testing.T) {
errCreateTag := api.CreateTag(Tag{TagName: "myTag", TagDescription: "descr"})
assert.ErrorContains(t, errCreateTag, "Request to ABAP System not successful")
assert.Empty(t, api.getUUID(), "API does not cotain correct UUID")
assert.Empty(t, api.getUUID(), "API does not contain correct UUID")
})
t.Run("Test Tag Empty", func(t *testing.T) {
@@ -439,7 +484,7 @@ func TestCreateTag0948(t *testing.T) {
errCreateTag := api.CreateTag(Tag{})
assert.ErrorContains(t, errCreateTag, "No Tag provided")
assert.Empty(t, api.getUUID(), "API does not cotain correct UUID")
assert.Empty(t, api.getUUID(), "API does not contain correct UUID")
})
}

View File

@@ -59,7 +59,7 @@ type SoftwareComponentApiInterface interface {
setSleepTimeConfig(timeUnit time.Duration, maxSleepTime time.Duration)
getSleepTime(n int) (time.Duration, error)
getUUID() string
GetRepository() (bool, string, error)
GetRepository() (bool, string, error, bool)
Clone() error
Pull() error
CheckoutBranch() error
@@ -69,6 +69,7 @@ type SoftwareComponentApiInterface interface {
GetLogProtocol(LogResultsV2, int) (result []LogProtocol, count int, err error)
ConvertTime(logTimeStamp string) time.Time
GetExecutionLog() (ExecutionLog, error)
UpdateRepoWithBYOGCredentials(string, string, string)
}
/****************************************
@@ -128,6 +129,7 @@ type CloneEntity struct {
type RepositoryEntity struct {
Metadata AbapMetadata `json:"__metadata"`
ScName string `json:"sc_name"`
ByogUrl string `json:"url"`
ActiveBranch string `json:"active_branch"`
AvailOnInst bool `json:"avail_on_inst"`
}
@@ -201,6 +203,9 @@ type RepositoriesConfig struct {
BranchName string
CommitID string
RepositoryName string
ByogUsername string
ByogPassword string
ByogAuthMethod string
RepositoryNames []string
Repositories string
}