1
0
mirror of https://github.com/SAP/jenkins-library.git synced 2025-02-21 19:48:53 +02:00

Add commit to clone and pull (#2258)

* commit ID for clone

* commit ID for clone

* Remove old default values

* Add commitID to Pull

* Print http response on debug level

* Fix tests

* Adapt tests

* Shorten sleep

* Fix clone tests

* Add ignore commit option

* Adapt tests

* Adapt docu

* Implement feedback

* fix codeclimate issue
This commit is contained in:
Daniel Mieg 2020-11-02 14:17:13 +01:00 committed by GitHub
parent edd5ef7709
commit 7639175def
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 412 additions and 149 deletions

View File

@ -30,10 +30,6 @@ func abapEnvironmentCheckoutBranch(options abapEnvironmentCheckoutBranchOptions,
client := piperhttp.Client{}
// for http calls import piperhttp "github.com/SAP/jenkins-library/pkg/http"
// and use a &piperhttp.Client{} in a custom system
// Example: step checkmarxExecuteScan.go
// error situations should stop execution through log.Entry().Fatal() call which leads to an os.Exit(1) in the end
err := runAbapEnvironmentCheckoutBranch(&options, telemetryData, &autils, &client)
if err != nil {
@ -44,16 +40,7 @@ func abapEnvironmentCheckoutBranch(options abapEnvironmentCheckoutBranchOptions,
func runAbapEnvironmentCheckoutBranch(options *abapEnvironmentCheckoutBranchOptions, telemetryData *telemetry.CustomData, com abaputils.Communication, client piperhttp.Sender) (err error) {
// Mapping for options
subOptions := abaputils.AbapEnvironmentOptions{}
subOptions.CfAPIEndpoint = options.CfAPIEndpoint
subOptions.CfServiceInstance = options.CfServiceInstance
subOptions.CfServiceKeyName = options.CfServiceKeyName
subOptions.CfOrg = options.CfOrg
subOptions.CfSpace = options.CfSpace
subOptions.Host = options.Host
subOptions.Password = options.Password
subOptions.Username = options.Username
subOptions := convertCheckoutConfig(options)
// Determine the host, user and password, either via the input parameters or via a cloud foundry service key
connectionDetails, errorGetInfo := com.GetAbapCommunicationArrangementInfo(subOptions, "/sap/opu/odata/sap/MANAGE_GIT_REPOSITORY/")
@ -93,7 +80,7 @@ func runAbapEnvironmentCheckoutBranch(options *abapEnvironmentCheckoutBranchOpti
}
func checkoutBranches(repositories []abaputils.Repository, checkoutConnectionDetails abaputils.ConnectionDetailsHTTP, client piperhttp.Sender, pollIntervall time.Duration) (err error) {
log.Entry().Infof("Start switching of %v branches", len(repositories))
log.Entry().Infof("Start switching %v branches", len(repositories))
for _, repo := range repositories {
err = handleCheckout(repo, checkoutConnectionDetails, client, pollIntervall)
if err != nil {
@ -122,9 +109,9 @@ func triggerCheckout(repositoryName string, branchName string, checkoutConnectio
defer resp.Body.Close()
// workaround until golang version 1.16 is used
time.Sleep(1 * time.Second)
time.Sleep(100 * time.Millisecond)
log.Entry().WithField("StatusCode", resp.Status).WithField("ABAP Endpoint", checkoutConnectionDetails.URL).Info("Authentication on the ABAP system was successful")
log.Entry().WithField("StatusCode", resp.Status).WithField("ABAP Endpoint", checkoutConnectionDetails.URL).Debug("Authentication on the ABAP system was successful")
uriConnectionDetails.XCsrfToken = resp.Header.Get("X-Csrf-Token")
checkoutConnectionDetails.XCsrfToken = uriConnectionDetails.XCsrfToken
@ -139,7 +126,7 @@ func triggerCheckout(repositoryName string, branchName string, checkoutConnectio
return uriConnectionDetails, err
}
defer resp.Body.Close()
log.Entry().WithField("StatusCode", resp.StatusCode).WithField("repositoryName", repositoryName).WithField("branchName", branchName).Info("Triggered checkout of branch")
log.Entry().WithField("StatusCode", resp.StatusCode).WithField("repositoryName", repositoryName).WithField("branchName", branchName).Debug("Triggered checkout of branch")
// Parse Response
var body abaputils.PullEntity
@ -217,3 +204,17 @@ func finishCheckoutLogs(branchName string, repositoryName string) {
log.Entry().Infof("Checkout of branch %v on repository %v was successful", branchName, repositoryName)
log.Entry().Info("--------------------------------")
}
func convertCheckoutConfig(config *abapEnvironmentCheckoutBranchOptions) 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
}

View File

@ -30,10 +30,6 @@ func abapEnvironmentCloneGitRepo(config abapEnvironmentCloneGitRepoOptions, tele
client := piperhttp.Client{}
// for http calls import piperhttp "github.com/SAP/jenkins-library/pkg/http"
// and use a &piperhttp.Client{} in a custom system
// Example: step checkmarxExecuteScan.go
// error situations should stop execution through log.Entry().Fatal() call which leads to an os.Exit(1) in the end
err := runAbapEnvironmentCloneGitRepo(&config, telemetryData, &autils, &client)
if err != nil {
@ -43,7 +39,7 @@ func abapEnvironmentCloneGitRepo(config abapEnvironmentCloneGitRepoOptions, tele
func runAbapEnvironmentCloneGitRepo(config *abapEnvironmentCloneGitRepoOptions, telemetryData *telemetry.CustomData, com abaputils.Communication, client piperhttp.Sender) error {
// Mapping for options
subOptions := convertConfig(config)
subOptions := convertCloneConfig(config)
// Determine the host, user and password, either via the input parameters or via a cloud foundry service key
connectionDetails, errorGetInfo := com.GetAbapCommunicationArrangementInfo(subOptions, "/sap/opu/odata/sap/MANAGE_GIT_REPOSITORY/Clones")
@ -71,33 +67,39 @@ func runAbapEnvironmentCloneGitRepo(config *abapEnvironmentCloneGitRepoOptions,
log.Entry().Infof("Start cloning %v repositories", len(repositories))
for _, repo := range repositories {
commitString := ""
if repo.CommitID != "" {
commitString = ", commit '" + repo.CommitID + "'"
}
log.Entry().Info("-------------------------")
log.Entry().Info("Start cloning " + repo.Name + " with branch " + repo.Branch)
log.Entry().Info("Start cloning " + repo.Name + ", branch " + repo.Branch + commitString)
log.Entry().Info("-------------------------")
// Triggering the Clone of the repository into the ABAP Environment system
uriConnectionDetails, errorTriggerClone := triggerClone(repo.Name, repo.Branch, connectionDetails, client)
uriConnectionDetails, errorTriggerClone := triggerClone(repo, connectionDetails, client)
if errorTriggerClone != nil {
return errors.Wrapf(errorTriggerClone, "Clone of '%s' with branch '%s' failed on the ABAP System", repo.Name, repo.Branch)
return errors.Wrapf(errorTriggerClone, "Clone of '%s', branch '%s'%s failed on the ABAP System", repo.Name, repo.Branch, commitString)
}
// Polling the status of the repository import on the ABAP Environment system
status, errorPollEntity := abaputils.PollEntity(repo.Name, uriConnectionDetails, client, com.GetPollIntervall())
if errorPollEntity != nil {
return errors.Wrapf(errorPollEntity, "Clone of '%s' with branch '%s' failed on the ABAP System", repo.Name, repo.Branch)
return errors.Wrapf(errorPollEntity, "Clone of '%s', branch '%s'%s failed on the ABAP System", repo.Name, repo.Branch, commitString)
}
if status == "E" {
return errors.New("Clone of '" + repo.Name + "' with branch '" + repo.Branch + "' failed on the ABAP System")
return errors.New("Clone of '" + repo.Name + "', branch '" + repo.Branch + "'" + commitString + " failed on the ABAP System")
}
log.Entry().Info(repo.Name + " with branch " + repo.Branch + " was cloned successfully")
log.Entry().Info(repo.Name + ", branch " + repo.Branch + commitString + " was cloned successfully")
}
log.Entry().Info("-------------------------")
log.Entry().Info("All repositories were cloned successfully")
return nil
}
func triggerClone(repositoryName string, branchName string, cloneConnectionDetails abaputils.ConnectionDetailsHTTP, client piperhttp.Sender) (abaputils.ConnectionDetailsHTTP, error) {
func triggerClone(repo abaputils.Repository, cloneConnectionDetails abaputils.ConnectionDetailsHTTP, client piperhttp.Sender) (abaputils.ConnectionDetailsHTTP, error) {
uriConnectionDetails := cloneConnectionDetails
uriConnectionDetails.URL = ""
@ -112,24 +114,27 @@ func triggerClone(repositoryName string, branchName string, cloneConnectionDetai
defer resp.Body.Close()
// workaround until golang version 1.16 is used
time.Sleep(1 * time.Second)
time.Sleep(100 * time.Millisecond)
log.Entry().WithField("StatusCode", resp.Status).WithField("ABAP Endpoint", cloneConnectionDetails.URL).Info("Authentication on the ABAP system successful")
log.Entry().WithField("StatusCode", resp.Status).WithField("ABAP Endpoint", cloneConnectionDetails.URL).Debug("Authentication on the ABAP system successful")
uriConnectionDetails.XCsrfToken = resp.Header.Get("X-Csrf-Token")
cloneConnectionDetails.XCsrfToken = uriConnectionDetails.XCsrfToken
// Trigger the Clone of a Repository
if repositoryName == "" {
if repo.Name == "" {
return uriConnectionDetails, errors.New("An empty string was passed for the parameter 'repositoryName'")
}
jsonBody := []byte(`{"sc_name":"` + repositoryName + `", "branch_name":"` + branchName + `"}`)
commitQuery, commitString := abaputils.GetCommitStrings(repo.CommitID)
jsonBody := []byte(`{"sc_name":"` + repo.Name + `", "branch_name":"` + repo.Branch + `"` + commitQuery + `}`)
resp, err = abaputils.GetHTTPResponse("POST", cloneConnectionDetails, jsonBody, client)
if err != nil {
err = abaputils.HandleHTTPError(resp, err, "Could not clone the Repository / Software Component "+repositoryName+" with branch "+branchName, uriConnectionDetails)
err = abaputils.HandleHTTPError(resp, err, "Could not clone the Repository / Software Component "+repo.Name+", branch "+repo.Branch+commitString, uriConnectionDetails)
return uriConnectionDetails, err
}
defer resp.Body.Close()
log.Entry().WithField("StatusCode", resp.Status).WithField("repositoryName", repositoryName).WithField("branchName", branchName).Info("Triggered Clone of Repository / Software Component")
log.Entry().WithField("StatusCode", resp.Status).WithField("repositoryName", repo.Name).WithField("branchName", repo.Branch).WithField("commitID", repo.CommitID).Info("Triggered Clone of Repository / Software Component")
// Parse Response
var body abaputils.CloneEntity
@ -141,7 +146,7 @@ func triggerClone(repositoryName string, branchName string, cloneConnectionDetai
json.Unmarshal(bodyText, &abapResp)
json.Unmarshal(*abapResp["d"], &body)
if reflect.DeepEqual(abaputils.CloneEntity{}, body) {
log.Entry().WithField("StatusCode", resp.Status).WithField("repositoryName", repositoryName).WithField("branchName", branchName).Error("Could not Clone the Repository / Software Component")
log.Entry().WithField("StatusCode", resp.Status).WithField("repositoryName", repo.Name).WithField("branchName", repo.Branch).WithField("commitID", repo.CommitID).Error("Could not Clone the Repository / Software Component")
err := errors.New("Request to ABAP System not successful")
return uriConnectionDetails, err
}
@ -151,13 +156,13 @@ func triggerClone(repositoryName string, branchName string, cloneConnectionDetai
// 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
tempURI := strings.Replace(body.Metadata.URI, "/sap/opu/odata/sap/MANAGE_GIT_REPOSITORY/Clones", "/sap/opu/odata/sap/MANAGE_GIT_REPOSITORY/Pull", 1)
pollingURI := strings.Replace(tempURI, ",sc_name='"+repositoryName+"',branch_name='"+branchName+"'", "", 1)
pollingURI := strings.Replace(tempURI, ",sc_name='"+repo.Name+"',branch_name='"+repo.Branch+"'", "", 1)
uriConnectionDetails.URL = pollingURI + expandLog
return uriConnectionDetails, nil
}
func convertConfig(config *abapEnvironmentCloneGitRepoOptions) abaputils.AbapEnvironmentOptions {
func convertCloneConfig(config *abapEnvironmentCloneGitRepoOptions) abaputils.AbapEnvironmentOptions {
subOptions := abaputils.AbapEnvironmentOptions{}
subOptions.CfAPIEndpoint = config.CfAPIEndpoint

View File

@ -112,7 +112,7 @@ repositories:
err := runAbapEnvironmentCloneGitRepo(&config, nil, &autils, client)
if assert.Error(t, err, "Expected error") {
assert.Equal(t, "Clone of '"+config.RepositoryName+"' with branch '"+config.BranchName+"' failed on the ABAP System: Request to ABAP System not successful", err.Error(), "Expected different error message")
assert.Equal(t, "Clone of '"+config.RepositoryName+"', branch '"+config.BranchName+"' failed on the ABAP System: Request to ABAP System not successful", err.Error(), "Expected different error message")
}
})
@ -127,6 +127,29 @@ func TestCloneStepErrorMessages(t *testing.T) {
autils.ReturnedConnectionDetailsHTTP.URL = "https://example.com"
autils.ReturnedConnectionDetailsHTTP.XCsrfToken = "xcsrftoken"
dir, errDir := ioutil.TempDir("", "test read addon descriptor")
if errDir != nil {
t.Fatal("Failed to create temporary directory")
}
oldCWD, _ := os.Getwd()
_ = os.Chdir(dir)
// clean up tmp dir
defer func() {
_ = os.Chdir(oldCWD)
_ = os.RemoveAll(dir)
}()
body := `---
repositories:
- name: /DMO/REPO_A
tag: v-1.0.1-build-0001
branch: branchA
version: 1.0.1
commitID: ABCD1234
`
file, _ := os.Create("filename.yaml")
file.Write([]byte(body))
config := abapEnvironmentCloneGitRepoOptions{
CfAPIEndpoint: "https://api.endpoint.com",
CfOrg: "testOrg",
@ -135,8 +158,7 @@ func TestCloneStepErrorMessages(t *testing.T) {
CfServiceKeyName: "testServiceKey",
Username: "testUser",
Password: "testPassword",
RepositoryName: "testRepo1",
BranchName: "testBranch1",
Repositories: "filename.yaml",
}
client := &abaputils.ClientMock{
@ -151,7 +173,7 @@ func TestCloneStepErrorMessages(t *testing.T) {
err := runAbapEnvironmentCloneGitRepo(&config, nil, &autils, client)
if assert.Error(t, err, "Expected error") {
assert.Equal(t, "Clone of '"+config.RepositoryName+"' with branch '"+config.BranchName+"' failed on the ABAP System", err.Error(), "Expected different error message")
assert.Equal(t, "Clone of '/DMO/REPO_A', branch 'branchA', commit 'ABCD1234' failed on the ABAP System", err.Error(), "Expected different error message")
}
})
@ -187,7 +209,7 @@ func TestCloneStepErrorMessages(t *testing.T) {
err := runAbapEnvironmentCloneGitRepo(&config, nil, &autils, client)
if assert.Error(t, err, "Expected error") {
assert.Equal(t, "Clone of '"+config.RepositoryName+"' with branch '"+config.BranchName+"' failed on the ABAP System: Request to ABAP System not successful", err.Error(), "Expected different error message")
assert.Equal(t, "Clone of '"+config.RepositoryName+"', branch '"+config.BranchName+"' failed on the ABAP System: Request to ABAP System not successful", err.Error(), "Expected different error message")
}
})
@ -222,7 +244,7 @@ func TestCloneStepErrorMessages(t *testing.T) {
err := runAbapEnvironmentCloneGitRepo(&config, nil, &autils, client)
if assert.Error(t, err, "Expected error") {
assert.Equal(t, "Clone of '"+config.RepositoryName+"' with branch '"+config.BranchName+"' failed on the ABAP System: Request to ABAP System not successful", err.Error(), "Expected different error message")
assert.Equal(t, "Clone of '"+config.RepositoryName+"', branch '"+config.BranchName+"' failed on the ABAP System: Request to ABAP System not successful", err.Error(), "Expected different error message")
}
})

View File

@ -30,10 +30,6 @@ func abapEnvironmentPullGitRepo(options abapEnvironmentPullGitRepoOptions, telem
client := piperhttp.Client{}
// for http calls import piperhttp "github.com/SAP/jenkins-library/pkg/http"
// and use a &piperhttp.Client{} in a custom system
// Example: step checkmarxExecuteScan.go
// error situations should stop execution through log.Entry().Fatal() call which leads to an os.Exit(1) in the end
err := runAbapEnvironmentPullGitRepo(&options, telemetryData, &autils, &client)
if err != nil {
@ -42,16 +38,8 @@ func abapEnvironmentPullGitRepo(options abapEnvironmentPullGitRepoOptions, telem
}
func runAbapEnvironmentPullGitRepo(options *abapEnvironmentPullGitRepoOptions, telemetryData *telemetry.CustomData, com abaputils.Communication, client piperhttp.Sender) (err error) {
subOptions := abaputils.AbapEnvironmentOptions{}
subOptions.CfAPIEndpoint = options.CfAPIEndpoint
subOptions.CfServiceInstance = options.CfServiceInstance
subOptions.CfServiceKeyName = options.CfServiceKeyName
subOptions.CfOrg = options.CfOrg
subOptions.CfSpace = options.CfSpace
subOptions.Host = options.Host
subOptions.Password = options.Password
subOptions.Username = options.Username
subOptions := convertPullConfig(options)
// Determine the host, user and password, either via the input parameters or via a cloud foundry service key
connectionDetails, err := com.GetAbapCommunicationArrangementInfo(subOptions, "/sap/opu/odata/sap/MANAGE_GIT_REPOSITORY/Pull")
@ -77,6 +65,7 @@ func runAbapEnvironmentPullGitRepo(options *abapEnvironmentPullGitRepoOptions, t
if err == nil {
repositories, err = abaputils.GetRepositories(&abaputils.RepositoriesConfig{RepositoryNames: options.RepositoryNames, Repositories: options.Repositories})
handleIgnoreCommit(repositories, options.IgnoreCommit)
}
if err == nil {
@ -93,7 +82,7 @@ func runAbapEnvironmentPullGitRepo(options *abapEnvironmentPullGitRepoOptions, t
}
func pullRepositories(repositories []abaputils.Repository, pullConnectionDetails abaputils.ConnectionDetailsHTTP, client piperhttp.Sender, pollIntervall time.Duration) (err error) {
log.Entry().Infof("Start cloning %v repositories", len(repositories))
log.Entry().Infof("Start pulling %v repositories", len(repositories))
for _, repo := range repositories {
err = handlePull(repo, pullConnectionDetails, client, pollIntervall)
if err != nil {
@ -104,7 +93,30 @@ func pullRepositories(repositories []abaputils.Repository, pullConnectionDetails
return err
}
func triggerPull(repositoryName string, pullConnectionDetails abaputils.ConnectionDetailsHTTP, client piperhttp.Sender) (abaputils.ConnectionDetailsHTTP, error) {
func handlePull(repo abaputils.Repository, pullConnectionDetails abaputils.ConnectionDetailsHTTP, client piperhttp.Sender, pollIntervall time.Duration) (err error) {
startPullLogs(repo)
_, commitString := abaputils.GetCommitStrings(repo.CommitID)
uriConnectionDetails, err := triggerPull(repo, pullConnectionDetails, client)
if err != nil {
return errors.Wrapf(err, "Pull of '%s'%s failed on the ABAP System", repo.Name, commitString)
}
// Polling the status of the repository import on the ABAP Environment system
status, errorPollEntity := abaputils.PollEntity(repo.Name, uriConnectionDetails, client, pollIntervall)
if errorPollEntity != nil {
return errors.Wrapf(errorPollEntity, "Pull of '%s'%s failed on the ABAP System", repo.Name, commitString)
}
if status == "E" {
return errors.New("Pull of '" + repo.Name + "'" + commitString + " failed on the ABAP System")
}
log.Entry().Info(repo.Name + " was pulled successfully")
return err
}
func triggerPull(repo abaputils.Repository, pullConnectionDetails abaputils.ConnectionDetailsHTTP, client piperhttp.Sender) (abaputils.ConnectionDetailsHTTP, error) {
uriConnectionDetails := pullConnectionDetails
uriConnectionDetails.URL = ""
@ -119,24 +131,25 @@ func triggerPull(repositoryName string, pullConnectionDetails abaputils.Connecti
defer resp.Body.Close()
// workaround until golang version 1.16 is used
time.Sleep(1 * time.Second)
time.Sleep(100 * time.Millisecond)
log.Entry().WithField("StatusCode", resp.Status).WithField("ABAP Endpoint", pullConnectionDetails.URL).Info("Authentication on the ABAP system successful")
log.Entry().WithField("StatusCode", resp.Status).WithField("ABAP Endpoint", pullConnectionDetails.URL).Debug("Authentication on the ABAP system successful")
uriConnectionDetails.XCsrfToken = resp.Header.Get("X-Csrf-Token")
pullConnectionDetails.XCsrfToken = uriConnectionDetails.XCsrfToken
// Trigger the Pull of a Repository
if repositoryName == "" {
if repo.Name == "" {
return uriConnectionDetails, errors.New("An empty string was passed for the parameter 'repositoryName'")
}
jsonBody := []byte(`{"sc_name":"` + repositoryName + `"}`)
commitQuery, commitString := abaputils.GetCommitStrings(repo.CommitID)
jsonBody := []byte(`{"sc_name":"` + repo.Name + `"` + commitQuery + `}`)
resp, err = abaputils.GetHTTPResponse("POST", pullConnectionDetails, jsonBody, client)
if err != nil {
err = abaputils.HandleHTTPError(resp, err, "Could not pull the Repository / Software Component "+repositoryName, uriConnectionDetails)
err = abaputils.HandleHTTPError(resp, err, "Could not pull the Repository / Software Component '"+repo.Name+"'"+commitString, uriConnectionDetails)
return uriConnectionDetails, err
}
defer resp.Body.Close()
log.Entry().WithField("StatusCode", resp.Status).WithField("repositoryName", repositoryName).Info("Triggered Pull of Repository / Software Component")
log.Entry().WithField("StatusCode", resp.Status).WithField("repositoryName", repo.Name).WithField("commitID", repo.CommitID).Debug("Triggered Pull of Repository / Software Component")
// Parse Response
var body abaputils.PullEntity
@ -148,7 +161,7 @@ func triggerPull(repositoryName string, pullConnectionDetails abaputils.Connecti
json.Unmarshal(bodyText, &abapResp)
json.Unmarshal(*abapResp["d"], &body)
if reflect.DeepEqual(abaputils.PullEntity{}, body) {
log.Entry().WithField("StatusCode", resp.Status).WithField("repositoryName", repositoryName).Error("Could not pull the Repository / Software Component")
log.Entry().WithField("StatusCode", resp.Status).WithField("repositoryName", repo.Name).WithField("commitID", repo.CommitID).Error("Could not pull the Repository / Software Component")
err := errors.New("Request to ABAP System not successful")
return uriConnectionDetails, err
}
@ -168,29 +181,10 @@ func checkPullRepositoryConfiguration(options abapEnvironmentPullGitRepoOptions)
return nil
}
func handlePull(repo abaputils.Repository, pullConnectionDetails abaputils.ConnectionDetailsHTTP, client piperhttp.Sender, pollIntervall time.Duration) (err error) {
startPullLogs(repo.Branch)
uriConnectionDetails, err := triggerPull(repo.Name, pullConnectionDetails, client)
if err != nil {
return errors.Wrapf(err, "Pull of '%s' failed on the ABAP System", repo.Name)
}
// Polling the status of the repository import on the ABAP Environment system
status, errorPollEntity := abaputils.PollEntity(repo.Name, uriConnectionDetails, client, pollIntervall)
if errorPollEntity != nil {
return errors.Wrapf(errorPollEntity, "Pull of '%s' failed on the ABAP System", repo.Name)
}
if status == "E" {
return errors.New("Pull of " + repo.Name + " failed on the ABAP System")
}
log.Entry().Info(repo.Name + " was pulled successfully")
return err
}
func startPullLogs(repositoryName string) {
func startPullLogs(repo abaputils.Repository) {
_, commitString := abaputils.GetCommitStrings(repo.CommitID)
log.Entry().Info("-------------------------")
log.Entry().Info("Start pulling " + repositoryName)
log.Entry().Info("Start pulling '" + repo.Name + "'" + commitString)
log.Entry().Info("-------------------------")
}
@ -198,3 +192,25 @@ func finishPullLogs() {
log.Entry().Info("-------------------------")
log.Entry().Info("All repositories were pulled successfully")
}
func convertPullConfig(config *abapEnvironmentPullGitRepoOptions) 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
}
func handleIgnoreCommit(repositories []abaputils.Repository, ignoreCommit bool) {
for i := range repositories {
if ignoreCommit {
repositories[i].CommitID = ""
}
}
}

View File

@ -24,6 +24,7 @@ type abapEnvironmentPullGitRepoOptions struct {
CfSpace string `json:"cfSpace,omitempty"`
CfServiceInstance string `json:"cfServiceInstance,omitempty"`
CfServiceKeyName string `json:"cfServiceKeyName,omitempty"`
IgnoreCommit bool `json:"ignoreCommit,omitempty"`
}
// AbapEnvironmentPullGitRepoCommand Pulls a git repository to a SAP Cloud Platform ABAP Environment system
@ -100,6 +101,7 @@ func addAbapEnvironmentPullGitRepoFlags(cmd *cobra.Command, stepConfig *abapEnvi
cmd.Flags().StringVar(&stepConfig.CfSpace, "cfSpace", os.Getenv("PIPER_cfSpace"), "Cloud Foundry target space")
cmd.Flags().StringVar(&stepConfig.CfServiceInstance, "cfServiceInstance", os.Getenv("PIPER_cfServiceInstance"), "Cloud Foundry Service Instance")
cmd.Flags().StringVar(&stepConfig.CfServiceKeyName, "cfServiceKeyName", os.Getenv("PIPER_cfServiceKeyName"), "Cloud Foundry Service Key")
cmd.Flags().BoolVar(&stepConfig.IgnoreCommit, "ignoreCommit", false, "ingores a commit provided via the repositories file")
cmd.MarkFlagRequired("username")
cmd.MarkFlagRequired("password")
@ -207,6 +209,14 @@ func abapEnvironmentPullGitRepoMetadata() config.StepData {
Mandatory: false,
Aliases: []config.Alias{{Name: "cloudFoundry/serviceKey"}, {Name: "cloudFoundry/serviceKeyName"}, {Name: "cfServiceKey"}},
},
{
Name: "ignoreCommit",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS"},
Type: "bool",
Mandatory: false,
Aliases: []config.Alias{},
},
},
},
},

View File

@ -46,6 +46,7 @@ func TestPullStep(t *testing.T) {
err := runAbapEnvironmentPullGitRepo(&config, nil, &autils, client)
assert.NoError(t, err, "Did not expect error")
})
t.Run("Run Step Failure", func(t *testing.T) {
expectedErrorMessage := "Something failed during the pull of the repositories: Checking configuration failed: You have not specified any repository configuration to be pulled into the ABAP Environment System. Please make sure that you specified the repositories that should be pulled either in a dedicated file or via the parameter 'repositoryNames'. For more information please read the User documentation"
@ -69,6 +70,7 @@ func TestPullStep(t *testing.T) {
err := runAbapEnvironmentPullGitRepo(&config, nil, &autils, client)
assert.Equal(t, expectedErrorMessage, err.Error(), "Different error message expected")
})
t.Run("Success case: pull repos from file config", func(t *testing.T) {
var autils = abaputils.AUtilsMock{}
defer autils.Cleanup()
@ -101,6 +103,7 @@ func TestPullStep(t *testing.T) {
repositories:
- name: 'testRepo'
branch: 'testBranch'
commitID: '9caede7f31028cd52333eb496434275687fefb47'
- name: 'testRepo2'
branch: 'testBranch2'
- name: 'testRepo3'
@ -121,6 +124,124 @@ repositories:
err = runAbapEnvironmentPullGitRepo(&config, nil, &autils, client)
assert.NoError(t, err)
})
t.Run("Status Error", 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"
dir, errDir := ioutil.TempDir("", "test read addon descriptor")
if errDir != nil {
t.Fatal("Failed to create temporary directory")
}
oldCWD, _ := os.Getwd()
_ = os.Chdir(dir)
// clean up tmp dir
defer func() {
_ = os.Chdir(oldCWD)
_ = os.RemoveAll(dir)
}()
body := `---
repositories:
- name: /DMO/REPO_A
tag: v-1.0.1-build-0001
branch: branchA
version: 1.0.1
commitID: ABCD1234
`
file, _ := os.Create("filename.yaml")
file.Write([]byte(body))
config := abapEnvironmentPullGitRepoOptions{
CfAPIEndpoint: "https://api.endpoint.com",
CfOrg: "testOrg",
CfSpace: "testSpace",
CfServiceInstance: "testInstance",
CfServiceKeyName: "testServiceKey",
Username: "testUser",
Password: "testPassword",
Repositories: "filename.yaml",
}
client := &abaputils.ClientMock{
BodyList: []string{
`{"d" : { "status" : "E" } }`,
`{"d" : { "status" : "R" } }`,
`{"d" : { "status" : "R" } }`,
},
Token: "myToken",
StatusCode: 200,
}
err := runAbapEnvironmentPullGitRepo(&config, nil, &autils, client)
if assert.Error(t, err, "Expected error") {
assert.Equal(t, "Something failed during the pull of the repositories: Pull of '/DMO/REPO_A', commit 'ABCD1234' failed on the ABAP System", err.Error(), "Expected different error message")
}
})
t.Run("Status Error, Ignore Commit", 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"
dir, errDir := ioutil.TempDir("", "test read addon descriptor")
if errDir != nil {
t.Fatal("Failed to create temporary directory")
}
oldCWD, _ := os.Getwd()
_ = os.Chdir(dir)
// clean up tmp dir
defer func() {
_ = os.Chdir(oldCWD)
_ = os.RemoveAll(dir)
}()
body := `---
repositories:
- name: /DMO/REPO_A
tag: v-1.0.1-build-0001
branch: branchA
version: 1.0.1
commitID: ABCD1234
`
file, _ := os.Create("filename.yaml")
file.Write([]byte(body))
config := abapEnvironmentPullGitRepoOptions{
CfAPIEndpoint: "https://api.endpoint.com",
CfOrg: "testOrg",
CfSpace: "testSpace",
CfServiceInstance: "testInstance",
CfServiceKeyName: "testServiceKey",
Username: "testUser",
Password: "testPassword",
Repositories: "filename.yaml",
IgnoreCommit: true,
}
client := &abaputils.ClientMock{
BodyList: []string{
`{"d" : { "status" : "E" } }`,
`{"d" : { "status" : "R" } }`,
`{"d" : { "status" : "R" } }`,
},
Token: "myToken",
StatusCode: 200,
}
err := runAbapEnvironmentPullGitRepo(&config, nil, &autils, client)
if assert.Error(t, err, "Expected error") {
assert.Equal(t, "Something failed during the pull of the repositories: Pull of '/DMO/REPO_A' failed on the ABAP System", err.Error(), "Expected different error message")
}
})
t.Run("Failure case: pull repos from empty file config", func(t *testing.T) {
expectedErrorMessage := "Something failed during the pull of the repositories: Error in config file repositoriesTest.yml, AddonDescriptor doesn't contain any repositories"
@ -168,6 +289,7 @@ repositories:
err = runAbapEnvironmentPullGitRepo(&config, nil, &autils, client)
assert.EqualError(t, err, expectedErrorMessage)
})
t.Run("Failure case: pull repos from wrong file config", func(t *testing.T) {
expectedErrorMessage := "Something failed during the pull of the repositories: Could not unmarshal repositoriesTest.yml"
@ -235,23 +357,16 @@ func TestTriggerPull(t *testing.T) {
Token: tokenExpected,
StatusCode: 200,
}
config := abapEnvironmentPullGitRepoOptions{
CfAPIEndpoint: "https://api.endpoint.com",
CfOrg: "testOrg",
CfSpace: "testSpace",
CfServiceInstance: "testInstance",
CfServiceKeyName: "testServiceKey",
Username: "testUser",
Password: "testPassword",
RepositoryNames: []string{"testRepo1", "testRepo2"},
}
repoName := "testRepo1"
testCommit := "9caede7f31028cd52333eb496434275687fefb47"
con := abaputils.ConnectionDetailsHTTP{
User: "MY_USER",
Password: "MY_PW",
URL: "https://api.endpoint.com/Entity/",
}
entityConnection, err := triggerPull(config.RepositoryNames[0], con, client)
entityConnection, err := triggerPull(abaputils.Repository{Name: repoName, CommitID: testCommit}, con, client)
assert.Nil(t, err)
assert.Equal(t, uriExpected, entityConnection.URL)
assert.Equal(t, tokenExpected, entityConnection.XCsrfToken)
@ -270,23 +385,16 @@ func TestTriggerPull(t *testing.T) {
StatusCode: 400,
Error: errors.New(HTTPErrorMessage),
}
config := abapEnvironmentPullGitRepoOptions{
CfAPIEndpoint: "https://api.endpoint.com",
CfOrg: "testOrg",
CfSpace: "testSpace",
CfServiceInstance: "testInstance",
CfServiceKeyName: "testServiceKey",
Username: "testUser",
Password: "testPassword",
RepositoryNames: []string{"testRepo1", "testRepo2"},
}
repoName := "testRepo1"
testCommit := "9caede7f31028cd52333eb496434275687fefb47"
con := abaputils.ConnectionDetailsHTTP{
User: "MY_USER",
Password: "MY_PW",
URL: "https://api.endpoint.com/Entity/",
}
_, err := triggerPull(config.RepositoryNames[0], con, client)
_, err := triggerPull(abaputils.Repository{Name: repoName, CommitID: testCommit}, con, client)
assert.Equal(t, combinedErrorMessage, err.Error(), "Different error message expected")
})
}
@ -313,3 +421,38 @@ func TestPullConfigChecker(t *testing.T) {
assert.Equal(t, errorMessage, err.Error(), "Different error message expected")
})
}
func TestHelpFunctions(t *testing.T) {
t.Run("Ignore Commit", func(t *testing.T) {
repo1 := abaputils.Repository{
Name: "Repo1",
CommitID: "ABCD1234",
}
repo2 := abaputils.Repository{
Name: "Repo2",
}
repoList := []abaputils.Repository{repo1, repo2}
handleIgnoreCommit(repoList, true)
assert.Equal(t, "", repoList[0].CommitID, "Expected emtpy CommitID")
assert.Equal(t, "", repoList[1].CommitID, "Expected emtpy CommitID")
})
t.Run("Not Ignore Commit", func(t *testing.T) {
repo1 := abaputils.Repository{
Name: "Repo1",
CommitID: "ABCD1234",
}
repo2 := abaputils.Repository{
Name: "Repo2",
}
repoList := []abaputils.Repository{repo1, repo2}
handleIgnoreCommit(repoList, false)
assert.Equal(t, "ABCD1234", repoList[0].CommitID, "Expected CommitID")
assert.Equal(t, "", repoList[1].CommitID, "Expected emtpy CommitID")
})
}

View File

@ -28,15 +28,6 @@ func abapEnvironmentRunATCCheck(options abapEnvironmentRunATCCheckOptions, telem
// Mapping for options
subOptions := abaputils.AbapEnvironmentOptions{}
subOptions.CfAPIEndpoint = options.CfAPIEndpoint
subOptions.CfServiceInstance = options.CfServiceInstance
subOptions.CfServiceKeyName = options.CfServiceKeyName
subOptions.CfOrg = options.CfOrg
subOptions.CfSpace = options.CfSpace
subOptions.Host = options.Host
subOptions.Password = options.Password
subOptions.Username = options.Username
c := &command.Command{}
c.Stdout(log.Entry().Writer())
c.Stderr(log.Entry().Writer())
@ -131,6 +122,7 @@ func triggerATCrun(config abapEnvironmentRunATCCheckOptions, details abaputils.C
//Trigger ATC run
var resp *http.Response
var bodyString = `<?xml version="1.0" encoding="UTF-8"?><atc:runparameters xmlns:atc="http://www.sap.com/adt/atc" xmlns:obj="http://www.sap.com/adt/objectset"` + checkVariantString + `><obj:objectSet>` + softwareComponentString + packageString + `</obj:objectSet></atc:runparameters>`
log.Entry().Debugf("Request Body: %s", bodyString)
var body = []byte(bodyString)
if err == nil {
details.URL = abapEndpoint + "/sap/bc/adt/api/atc/runs?clientWait=false"
@ -150,6 +142,7 @@ func buildATCCheckBody(ATCConfig ATCconfig) (checkVariantString string, packageS
//Build Check Variant and Configuration XML Body
if len(ATCConfig.CheckVariant) != 0 {
checkVariantString += ` checkVariant="` + ATCConfig.CheckVariant + `"`
log.Entry().Infof("ATC Check Variant: %s", ATCConfig.CheckVariant)
if len(ATCConfig.Configuration) != 0 {
checkVariantString += ` configuration="` + ATCConfig.Configuration + `"`
}
@ -179,15 +172,19 @@ func parseATCResult(body []byte, atcResultFileName string) (err error) {
if len(body) == 0 {
return fmt.Errorf("Parsing ATC result failed: %w", errors.New("Body is empty, can't parse empty body"))
}
responseBody := string(body)
log.Entry().Debugf("Response body: %s", responseBody)
if strings.HasPrefix(responseBody, "<html>") {
return errors.New("The Software Component could not be checked. Please make sure the respective Software Component has been cloned successfully on the system")
}
parsedXML := new(Result)
xml.Unmarshal([]byte(body), &parsedXML)
if len(parsedXML.Files) == 0 {
log.Entry().Info("There were no results from this run, most likely the checked Software Components are empty or contain no ATC findings")
}
s := string(body)
if strings.HasPrefix(s, "<html>") {
return errors.New("The Software Component could not be checked. Please make sure the respective Software Component has been cloned successfully on the system")
}
err = ioutil.WriteFile(atcResultFileName, body, 0644)
if err == nil {
var reports []piperutils.Path
@ -223,7 +220,7 @@ func runATC(requestType string, details abaputils.ConnectionDetailsHTTP, body []
func fetchXcsrfToken(requestType string, details abaputils.ConnectionDetailsHTTP, body []byte, client piperhttp.Sender) (string, error) {
log.Entry().WithField("ABAP Endpoint: ", details.URL).Info("Fetching Xcrsf-Token")
log.Entry().WithField("ABAP Endpoint: ", details.URL).Debug("Fetching Xcrsf-Token")
details.URL += "/sap/bc/adt/api/atc/runs/00000000000000000000000000000000"
details.XCsrfToken = "fetch"
@ -303,6 +300,21 @@ func getResultATCRun(requestType string, details abaputils.ConnectionDetailsHTTP
return req, err
}
func convertATCOptions(options *abapEnvironmentRunATCCheckOptions) abaputils.AbapEnvironmentOptions {
subOptions := abaputils.AbapEnvironmentOptions{}
subOptions.CfAPIEndpoint = options.CfAPIEndpoint
subOptions.CfServiceInstance = options.CfServiceInstance
subOptions.CfServiceKeyName = options.CfServiceKeyName
subOptions.CfOrg = options.CfOrg
subOptions.CfSpace = options.CfSpace
subOptions.Host = options.Host
subOptions.Password = options.Password
subOptions.Username = options.Username
return subOptions
}
//ATCconfig object for parsing yaml config of software components and packages
type ATCconfig struct {
CheckVariant string `json:"checkvariant,omitempty"`

View File

@ -56,7 +56,7 @@ repositories:
```
Please note that you need to use the YAML data structure as in the example above when using the `repositories.yml` config file.
For this step it is mandatory to fill the branch values. You can also use this file for the abapEnvironmentPullGitRepo step.
For this step it is mandatory to fill the branch values. You can also use this file for the abapEnvironmentPullGitRepo step. Using this configuration file is the recommended approach.
If you want to read the host and credentials from the cloud foundry service key of the respective instance, the configuration could look as follows:

View File

@ -60,6 +60,11 @@ repositories:
branch: 'feature'
```
Using such a configuration file is the recommended approach. Please note that you need to use the YAML data structure as in the example above when using the `repositories.yml` config file.
!!! note "Commit IDs"
CommitIDs will also be supported in the future. While the step already includes the handling of commit IDs, the ABAP Environment system will support this not until a later release.
## Example: Configuration in the Jenkinsfile
It is also possible to call the steps - including all parameters - directly in the Jenkinsfile.

View File

@ -31,7 +31,7 @@ steps:
host: '1234-abcd-5678-efgh-ijk.abap.eu10.hana.ondemand.com'
```
Also you can specify a dedicated file, e.g. `repositories.yml` containing the repositories to be pulled:
However, we recommend to use a dedicated file, e.g. `repositories.yml` to specify the repositories to be pulled:
```yaml
steps:
@ -51,8 +51,10 @@ repositories:
branch: 'master'
```
Please note that you need to adapt the file structure according to the structure in this example in order to work.
It is possible to leave the branch value out. However if you also want to use this file for the abapEnvironmentCheckoutBranch step it is recommended to follow above structure.
It is optional to provide a branch. However, if you also want to use this file for the abapEnvironmentCheckoutBranch step it is recommended to follow the above structure.
!!! note "Commit IDs"
CommitIDs will also be supported in the future. While the step already includes the handling of commit IDs, the ABAP Environment system will support this not until a later release.
If you want to read the host and credentials from the cloud foundry service key of the respective instance, the configuration could look as follows:

View File

@ -29,6 +29,7 @@ type Repository struct {
Name string `json:"name"`
Tag string `json:"tag"`
Branch string `json:"branch"`
CommitID string `json:"commitID"`
VersionYAML string `json:"version"`
Version string `json:"versionAAK"`
PackageName string

View File

@ -44,7 +44,11 @@ func PollEntity(repositoryName string, connectionDetails ConnectionDetailsHTTP,
status = body.Status
log.Entry().WithField("StatusCode", resp.Status).Info("Pull Status: " + body.StatusDescription)
if body.Status != "R" {
PrintLogs(body)
if body.Status == "E" {
PrintLogs(body, true)
} else {
PrintLogs(body, false)
}
break
}
time.Sleep(pollIntervall)
@ -53,7 +57,7 @@ func PollEntity(repositoryName string, connectionDetails ConnectionDetailsHTTP,
}
// PrintLogs sorts and formats the received transport and execution log of an import
func PrintLogs(entity PullEntity) {
func PrintLogs(entity PullEntity, errorOnSystem bool) {
// Sort logs
sort.SliceStable(entity.ToExecutionLog.Results, func(i, j int) bool {
@ -64,21 +68,41 @@ func PrintLogs(entity PullEntity) {
return entity.ToTransportLog.Results[i].Index < entity.ToTransportLog.Results[j].Index
})
log.Entry().Info("-------------------------")
log.Entry().Info("Transport Log")
log.Entry().Info("-------------------------")
for _, logEntry := range entity.ToTransportLog.Results {
// Show transport and execution log if either the action was erroenous on the system or the log level is set to "debug" (verbose = true)
if errorOnSystem {
log.Entry().Info("-------------------------")
log.Entry().Info("Transport Log")
log.Entry().Info("-------------------------")
for _, logEntry := range entity.ToTransportLog.Results {
log.Entry().WithField("Timestamp", ConvertTime(logEntry.Timestamp)).Info(logEntry.Description)
log.Entry().WithField("Timestamp", ConvertTime(logEntry.Timestamp)).Info(logEntry.Description)
}
log.Entry().Info("-------------------------")
log.Entry().Info("Execution Log")
log.Entry().Info("-------------------------")
for _, logEntry := range entity.ToExecutionLog.Results {
log.Entry().WithField("Timestamp", ConvertTime(logEntry.Timestamp)).Info(logEntry.Description)
}
log.Entry().Info("-------------------------")
} else {
log.Entry().Debug("-------------------------")
log.Entry().Debug("Transport Log")
log.Entry().Debug("-------------------------")
for _, logEntry := range entity.ToTransportLog.Results {
log.Entry().WithField("Timestamp", ConvertTime(logEntry.Timestamp)).Debug(logEntry.Description)
}
log.Entry().Debug("-------------------------")
log.Entry().Debug("Execution Log")
log.Entry().Debug("-------------------------")
for _, logEntry := range entity.ToExecutionLog.Results {
log.Entry().WithField("Timestamp", ConvertTime(logEntry.Timestamp)).Debug(logEntry.Description)
}
log.Entry().Debug("-------------------------")
}
log.Entry().Info("-------------------------")
log.Entry().Info("Execution Log")
log.Entry().Info("-------------------------")
for _, logEntry := range entity.ToExecutionLog.Results {
log.Entry().WithField("Timestamp", ConvertTime(logEntry.Timestamp)).Info(logEntry.Description)
}
log.Entry().Info("-------------------------")
}
//GetRepositories for parsing one or multiple branches and repositories from repositories file or branchName and repositoryName configuration
@ -112,6 +136,15 @@ func GetRepositories(config *RepositoriesConfig) ([]Repository, error) {
return repositories, nil
}
//GetCommitStrings for getting the commit_id property for the http request and a string for logging output
func GetCommitStrings(commitID string) (commitQuery string, commitString string) {
if commitID != "" {
commitQuery = `, "commit_id":"` + commitID + `"`
commitString = ", commit '" + commitID + "'"
}
return commitQuery, commitString
}
/****************************************
* Structs for the A4C_A2G_GHA service *
****************************************/

View File

@ -215,3 +215,16 @@ repositories:
assert.EqualError(t, err, expectedErrorMessage)
})
}
func TestGetCommitStrings(t *testing.T) {
t.Run("CommitID available", func(t *testing.T) {
commitQuery, commitString := GetCommitStrings("ABCD1234")
assert.Equal(t, `, "commit_id":"ABCD1234"`, commitQuery, "Expected different query")
assert.Equal(t, `, commit 'ABCD1234'`, commitString, "Expected different string")
})
t.Run("CommitID available", func(t *testing.T) {
commitQuery, commitString := GetCommitStrings("")
assert.Equal(t, ``, commitQuery, "Expected empty query")
assert.Equal(t, ``, commitString, "Expected empty string")
})
}

View File

@ -66,9 +66,6 @@ general:
#Steps Specific Configuration
steps:
abapEnvironmentPullGitRepo:
dockerImage: 'ppiper/cf-cli'
dockerWorkspace: '/home/piper'
artifactSetVersion:
timestampTemplate: '%Y%m%d%H%M%S'
tagPrefix: 'build_'
@ -212,9 +209,6 @@ steps:
stashContent:
- 'tests'
testReportFilePath: 'cst-report.json'
cloudFoundryCreateServiceKey:
dockerImage: 'ppiper/cf-cli'
dockerWorkspace: '/home/piper'
debugReportArchive:
shareConfidentialInformation: false
dockerExecute:

View File

@ -120,6 +120,12 @@ spec:
- name: cloudFoundry/serviceKey
- name: cloudFoundry/serviceKeyName
- name: cfServiceKey
- name: ignoreCommit
type: bool
description: ingores a commit provided via the repositories file
scope:
- PARAMETERS
default: false
containers:
- name: cf
image: ppiper/cf-cli