You've already forked sap-jenkins-library
							
							
				mirror of
				https://github.com/SAP/jenkins-library.git
				synced 2025-10-30 23:57:50 +02:00 
			
		
		
		
	Add ABAP step: createTag (#3633)
* Cloud Platform -> BTP * Initial generation of new step * add flag * wip * Fix warnings * Add command * Added Tag Decription * Add status check * Improve handling * Improve handling * Add test for happy path * Add test reports to gitignore * Add second test * Improve createTag * Add testcase * Adaptions * Add test * Update cmd/abapEnvironmentCreateTag.go Co-authored-by: tiloKo <70266685+tiloKo@users.noreply.github.com> * Update cmd/abapEnvironmentCreateTag.go Co-authored-by: tiloKo <70266685+tiloKo@users.noreply.github.com> * Adapt error handling * Improve coding * Add info * Disallow repositories and repositoryName at the same time * Regenerate * Adapt to feedback * Update cmd/abapEnvironmentCreateTag.go Co-authored-by: tiloKo <70266685+tiloKo@users.noreply.github.com> * Update cmd/abapEnvironmentCreateTag.go Co-authored-by: tiloKo <70266685+tiloKo@users.noreply.github.com> Co-authored-by: tiloKo <70266685+tiloKo@users.noreply.github.com>
This commit is contained in:
		
							
								
								
									
										5
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -45,3 +45,8 @@ ATCResults.xml | ||||
| AUnitResults.xml | ||||
| ATCResults.html | ||||
| AUnitResults.html | ||||
| cmd/checkmarx/piper_checkmarx_report.json | ||||
| cmd/fortify/piper_fortify_report.html | ||||
| cmd/fortify/piper_fortify_report.json | ||||
| cmd/toolruns/toolrun_malwarescan_20220519143229.json | ||||
| cmd/toolruns/toolrun_protecode_20220519143230.json | ||||
|   | ||||
							
								
								
									
										259
									
								
								cmd/abapEnvironmentCreateTag.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										259
									
								
								cmd/abapEnvironmentCreateTag.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,259 @@ | ||||
| package cmd | ||||
|  | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"io/ioutil" | ||||
| 	"net/http/cookiejar" | ||||
| 	"strings" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/SAP/jenkins-library/pkg/abaputils" | ||||
| 	"github.com/SAP/jenkins-library/pkg/command" | ||||
| 	piperhttp "github.com/SAP/jenkins-library/pkg/http" | ||||
| 	"github.com/SAP/jenkins-library/pkg/log" | ||||
| 	"github.com/SAP/jenkins-library/pkg/telemetry" | ||||
| 	"github.com/pkg/errors" | ||||
| ) | ||||
|  | ||||
| func abapEnvironmentCreateTag(config abapEnvironmentCreateTagOptions, telemetryData *telemetry.CustomData) { | ||||
|  | ||||
| 	c := command.Command{} | ||||
|  | ||||
| 	c.Stdout(log.Writer()) | ||||
| 	c.Stderr(log.Writer()) | ||||
|  | ||||
| 	var autils = abaputils.AbapUtils{ | ||||
| 		Exec: &c, | ||||
| 	} | ||||
|  | ||||
| 	client := piperhttp.Client{} | ||||
|  | ||||
| 	if err := runAbapEnvironmentCreateTag(&config, telemetryData, &autils, &client); err != nil { | ||||
| 		log.Entry().WithError(err).Fatal("step execution failed") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func runAbapEnvironmentCreateTag(config *abapEnvironmentCreateTagOptions, telemetryData *telemetry.CustomData, com abaputils.Communication, client piperhttp.Sender) error { | ||||
|  | ||||
| 	connectionDetails, errorGetInfo := com.GetAbapCommunicationArrangementInfo(convertTagConfig(config), "") | ||||
| 	if errorGetInfo != nil { | ||||
| 		return errors.Wrap(errorGetInfo, "Parameters for the ABAP Connection not available") | ||||
| 	} | ||||
|  | ||||
| 	// Configuring the HTTP Client and CookieJar | ||||
| 	cookieJar, errorCookieJar := cookiejar.New(nil) | ||||
| 	if errorCookieJar != nil { | ||||
| 		return errors.Wrap(errorCookieJar, "Could not create a Cookie Jar") | ||||
| 	} | ||||
|  | ||||
| 	client.SetOptions(piperhttp.ClientOptions{ | ||||
| 		MaxRequestDuration: 180 * time.Second, | ||||
| 		CookieJar:          cookieJar, | ||||
| 		Username:           connectionDetails.User, | ||||
| 		Password:           connectionDetails.Password, | ||||
| 	}) | ||||
|  | ||||
| 	backlog, errorPrepare := prepareBacklog(config) | ||||
| 	if errorPrepare != nil { | ||||
| 		return fmt.Errorf("Something failed during the tag creation: %w", errorPrepare) | ||||
| 	} | ||||
|  | ||||
| 	return createTags(backlog, telemetryData, connectionDetails, client, com) | ||||
| } | ||||
|  | ||||
| func createTags(backlog []CreateTagBacklog, telemetryData *telemetry.CustomData, con abaputils.ConnectionDetailsHTTP, client piperhttp.Sender, com abaputils.Communication) (err error) { | ||||
|  | ||||
| 	connection := con | ||||
| 	connection.XCsrfToken = "fetch" | ||||
| 	connection.URL = con.URL + "/sap/opu/odata/sap/MANAGE_GIT_REPOSITORY/Tags" | ||||
| 	resp, err := abaputils.GetHTTPResponse("HEAD", connection, nil, client) | ||||
| 	if err != nil { | ||||
| 		return abaputils.HandleHTTPError(resp, err, "Authentication on the ABAP system failed", con) | ||||
| 	} | ||||
| 	defer resp.Body.Close() | ||||
|  | ||||
| 	log.Entry().WithField("StatusCode", resp.Status).WithField("ABAP Endpoint", connection.URL).Debug("Authentication on the ABAP system successful") | ||||
| 	connection.XCsrfToken = resp.Header.Get("X-Csrf-Token") | ||||
|  | ||||
| 	errorOccurred := false | ||||
| 	for _, item := range backlog { | ||||
| 		err = createTagsForSingleItem(item, telemetryData, connection, client, com) | ||||
| 		if err != nil { | ||||
| 			errorOccurred = true | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if errorOccurred { | ||||
| 		message := "At least one tag has not been created" | ||||
| 		log.Entry().Errorf(message) | ||||
| 		return errors.New(message) | ||||
| 	} | ||||
| 	return nil | ||||
|  | ||||
| } | ||||
|  | ||||
| func createTagsForSingleItem(item CreateTagBacklog, telemetryData *telemetry.CustomData, con abaputils.ConnectionDetailsHTTP, client piperhttp.Sender, com abaputils.Communication) (err error) { | ||||
|  | ||||
| 	errorOccurred := false | ||||
| 	for index := range item.tags { | ||||
| 		err = createSingleTag(item, index, telemetryData, con, client, com) | ||||
| 		if err != nil { | ||||
| 			errorOccurred = true | ||||
| 		} | ||||
| 	} | ||||
| 	if errorOccurred { | ||||
| 		message := "At least one tag has not been created" | ||||
| 		err = errors.New(message) | ||||
| 	} | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| func createSingleTag(item CreateTagBacklog, index int, telemetryData *telemetry.CustomData, con abaputils.ConnectionDetailsHTTP, client piperhttp.Sender, com abaputils.Communication) (err error) { | ||||
|  | ||||
| 	requestBodyStruct := CreateTagBody{RepositoryName: item.repositoryName, CommitID: item.commitID, Tag: item.tags[index].tagName, Description: item.tags[index].tagDescription} | ||||
| 	requestBodyJson, err := json.Marshal(&requestBodyStruct) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	log.Entry().Debugf("Request body: %s", requestBodyJson) | ||||
| 	resp, err := abaputils.GetHTTPResponse("POST", con, requestBodyJson, client) | ||||
| 	if err != nil { | ||||
| 		errorMessage := "Could not create tag " + requestBodyStruct.Tag + " for repository " + requestBodyStruct.RepositoryName + " with commitID " + requestBodyStruct.CommitID | ||||
| 		err = abaputils.HandleHTTPError(resp, err, errorMessage, con) | ||||
| 		return err | ||||
| 	} | ||||
| 	defer resp.Body.Close() | ||||
|  | ||||
| 	// Parse response | ||||
| 	var createTagResponse CreateTagResponse | ||||
| 	var abapResp map[string]*json.RawMessage | ||||
| 	bodyText, _ := ioutil.ReadAll(resp.Body) | ||||
|  | ||||
| 	if err = json.Unmarshal(bodyText, &abapResp); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if err = json.Unmarshal(*abapResp["d"], &createTagResponse); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	con.URL = con.Host + "/sap/opu/odata/sap/MANAGE_GIT_REPOSITORY/Pull(guid'" + createTagResponse.UUID + "')" | ||||
| 	err = checkStatus(con, client, com) | ||||
|  | ||||
| 	if err == nil { | ||||
| 		log.Entry().Info("Created tag " + requestBodyStruct.Tag + " for repository " + requestBodyStruct.RepositoryName + " with commitID " + requestBodyStruct.CommitID) | ||||
| 	} else { | ||||
| 		log.Entry().Error("NOT created: Tag " + requestBodyStruct.Tag + " for repository " + requestBodyStruct.RepositoryName + " with commitID " + requestBodyStruct.CommitID) | ||||
| 	} | ||||
|  | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| func checkStatus(con abaputils.ConnectionDetailsHTTP, client piperhttp.Sender, com abaputils.Communication) (err error) { | ||||
| 	status := "R" | ||||
| 	pollIntervall := com.GetPollIntervall() | ||||
| 	count := 0 | ||||
| 	for { | ||||
| 		count += 1 | ||||
| 		entity, _, err := abaputils.GetStatus("Could not create Tag", con, client) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		status = entity.Status | ||||
| 		if status != "R" { | ||||
| 			if status == "E" { | ||||
| 				err = errors.New("Could not create Tag") | ||||
| 			} | ||||
| 			return err | ||||
| 		} | ||||
| 		if count >= 200 { | ||||
| 			return errors.New("Could not create Tag (Timeout)") | ||||
| 		} | ||||
| 		time.Sleep(pollIntervall) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func prepareBacklog(config *abapEnvironmentCreateTagOptions) (backlog []CreateTagBacklog, err error) { | ||||
|  | ||||
| 	if config.Repositories != "" && config.RepositoryName != "" { | ||||
| 		return nil, errors.New("Configuring the parameter repositories and the parameter repositoryName at the same time is not allowed") | ||||
| 	} | ||||
|  | ||||
| 	if config.RepositoryName != "" && config.CommitID != "" { | ||||
| 		backlog = append(backlog, CreateTagBacklog{repositoryName: config.RepositoryName, commitID: config.CommitID}) | ||||
| 	} | ||||
|  | ||||
| 	if config.Repositories != "" { | ||||
| 		descriptor, err := abaputils.ReadAddonDescriptor(config.Repositories) //config.Repositories should contain a file name | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		for _, repo := range descriptor.Repositories { | ||||
| 			backlogInstance := CreateTagBacklog{repositoryName: repo.Name, commitID: repo.CommitID} | ||||
| 			if config.GenerateTagForAddonComponentVersion && repo.VersionYAML != "" { | ||||
| 				tag := Tag{tagName: "v" + repo.VersionYAML, tagDescription: "Generated by the ABAP Environment Pipeline"} | ||||
| 				backlogInstance.tags = append(backlogInstance.tags, tag) | ||||
| 			} | ||||
| 			backlog = append(backlog, backlogInstance) | ||||
| 		} | ||||
| 		if config.GenerateTagForAddonProductVersion { | ||||
| 			if descriptor.AddonProduct != "" && descriptor.AddonVersionYAML != "" { | ||||
| 				addonProductDash := strings.Replace(descriptor.AddonProduct, "/", "-", 2) | ||||
| 				backlog = addTagToList(backlog, addonProductDash+"-"+descriptor.AddonVersionYAML, "Generated by the ABAP Environment Pipeline") | ||||
| 			} else { | ||||
| 				log.Entry().WithField("generateTagForAddonProductVersion", config.GenerateTagForAddonProductVersion).WithField("AddonProduct", descriptor.AddonProduct).WithField("AddonVersion", descriptor.AddonVersionYAML).Infof("Not all required values are provided to create an addon product version tag") | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	if config.TagName != "" { | ||||
| 		backlog = addTagToList(backlog, config.TagName, config.TagDescription) | ||||
| 	} | ||||
| 	return backlog, nil | ||||
| } | ||||
|  | ||||
| func addTagToList(backlog []CreateTagBacklog, tag string, description string) []CreateTagBacklog { | ||||
|  | ||||
| 	for i, item := range backlog { | ||||
| 		tag := Tag{tagName: tag, tagDescription: description} | ||||
| 		backlog[i].tags = append(item.tags, tag) | ||||
| 	} | ||||
| 	return backlog | ||||
| } | ||||
|  | ||||
| func convertTagConfig(config *abapEnvironmentCreateTagOptions) 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 | ||||
| } | ||||
|  | ||||
| type CreateTagBacklog struct { | ||||
| 	repositoryName string | ||||
| 	commitID       string | ||||
| 	tags           []Tag | ||||
| } | ||||
|  | ||||
| type Tag struct { | ||||
| 	tagName        string | ||||
| 	tagDescription string | ||||
| } | ||||
|  | ||||
| type CreateTagBody struct { | ||||
| 	RepositoryName string `json:"sc_name"` | ||||
| 	CommitID       string `json:"commit_id"` | ||||
| 	Tag            string `json:"tag_name"` | ||||
| 	Description    string `json:"tag_description"` | ||||
| } | ||||
|  | ||||
| type CreateTagResponse struct { | ||||
| 	UUID string `json:"uuid"` | ||||
| } | ||||
							
								
								
									
										321
									
								
								cmd/abapEnvironmentCreateTag_generated.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										321
									
								
								cmd/abapEnvironmentCreateTag_generated.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,321 @@ | ||||
| // Code generated by piper's step-generator. DO NOT EDIT. | ||||
|  | ||||
| package cmd | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/SAP/jenkins-library/pkg/config" | ||||
| 	"github.com/SAP/jenkins-library/pkg/log" | ||||
| 	"github.com/SAP/jenkins-library/pkg/splunk" | ||||
| 	"github.com/SAP/jenkins-library/pkg/telemetry" | ||||
| 	"github.com/SAP/jenkins-library/pkg/validation" | ||||
| 	"github.com/spf13/cobra" | ||||
| ) | ||||
|  | ||||
| type abapEnvironmentCreateTagOptions struct { | ||||
| 	Username                            string `json:"username,omitempty"` | ||||
| 	Password                            string `json:"password,omitempty"` | ||||
| 	Repositories                        string `json:"repositories,omitempty"` | ||||
| 	RepositoryName                      string `json:"repositoryName,omitempty"` | ||||
| 	CommitID                            string `json:"commitID,omitempty"` | ||||
| 	TagName                             string `json:"tagName,omitempty"` | ||||
| 	TagDescription                      string `json:"tagDescription,omitempty"` | ||||
| 	GenerateTagForAddonProductVersion   bool   `json:"generateTagForAddonProductVersion,omitempty"` | ||||
| 	GenerateTagForAddonComponentVersion bool   `json:"generateTagForAddonComponentVersion,omitempty"` | ||||
| 	Host                                string `json:"host,omitempty"` | ||||
| 	CfAPIEndpoint                       string `json:"cfApiEndpoint,omitempty"` | ||||
| 	CfOrg                               string `json:"cfOrg,omitempty"` | ||||
| 	CfSpace                             string `json:"cfSpace,omitempty"` | ||||
| 	CfServiceInstance                   string `json:"cfServiceInstance,omitempty"` | ||||
| 	CfServiceKeyName                    string `json:"cfServiceKeyName,omitempty"` | ||||
| } | ||||
|  | ||||
| // AbapEnvironmentCreateTagCommand Creates a tag for a git repository to a SAP BTP ABAP Environment system | ||||
| func AbapEnvironmentCreateTagCommand() *cobra.Command { | ||||
| 	const STEP_NAME = "abapEnvironmentCreateTag" | ||||
|  | ||||
| 	metadata := abapEnvironmentCreateTagMetadata() | ||||
| 	var stepConfig abapEnvironmentCreateTagOptions | ||||
| 	var startTime time.Time | ||||
| 	var logCollector *log.CollectorHook | ||||
| 	var splunkClient *splunk.Splunk | ||||
| 	telemetryClient := &telemetry.Telemetry{} | ||||
|  | ||||
| 	var createAbapEnvironmentCreateTagCmd = &cobra.Command{ | ||||
| 		Use:   STEP_NAME, | ||||
| 		Short: "Creates a tag for a git repository to a SAP BTP ABAP Environment system", | ||||
| 		Long: `Creates tags for specific commits of one or multiple repositories / software components. The tag can be specified explicitly as well as being generated by an addon product version or an addon component version. | ||||
| 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). | ||||
| * The Cloud Foundry parameters (API endpoint, organization, space), credentials, the service instance for the ABAP service and the service key for the Communication Scenario SAP_COM_0510. | ||||
| * Only provide one of those options with the respective credentials. If all values are provided, the direct communication (via host) has priority.`, | ||||
| 		PreRunE: func(cmd *cobra.Command, _ []string) error { | ||||
| 			startTime = time.Now() | ||||
| 			log.SetStepName(STEP_NAME) | ||||
| 			log.SetVerbose(GeneralConfig.Verbose) | ||||
|  | ||||
| 			GeneralConfig.GitHubAccessTokens = ResolveAccessTokens(GeneralConfig.GitHubTokens) | ||||
|  | ||||
| 			path, _ := os.Getwd() | ||||
| 			fatalHook := &log.FatalHook{CorrelationID: GeneralConfig.CorrelationID, Path: path} | ||||
| 			log.RegisterHook(fatalHook) | ||||
|  | ||||
| 			err := PrepareConfig(cmd, &metadata, STEP_NAME, &stepConfig, config.OpenPiperFile) | ||||
| 			if err != nil { | ||||
| 				log.SetErrorCategory(log.ErrorConfiguration) | ||||
| 				return err | ||||
| 			} | ||||
| 			log.RegisterSecret(stepConfig.Username) | ||||
| 			log.RegisterSecret(stepConfig.Password) | ||||
|  | ||||
| 			if len(GeneralConfig.HookConfig.SentryConfig.Dsn) > 0 { | ||||
| 				sentryHook := log.NewSentryHook(GeneralConfig.HookConfig.SentryConfig.Dsn, GeneralConfig.CorrelationID) | ||||
| 				log.RegisterHook(&sentryHook) | ||||
| 			} | ||||
|  | ||||
| 			if len(GeneralConfig.HookConfig.SplunkConfig.Dsn) > 0 { | ||||
| 				splunkClient = &splunk.Splunk{} | ||||
| 				logCollector = &log.CollectorHook{CorrelationID: GeneralConfig.CorrelationID} | ||||
| 				log.RegisterHook(logCollector) | ||||
| 			} | ||||
|  | ||||
| 			validation, err := validation.New(validation.WithJSONNamesForStructFields(), validation.WithPredefinedErrorMessages()) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 			if err = validation.ValidateStruct(stepConfig); err != nil { | ||||
| 				log.SetErrorCategory(log.ErrorConfiguration) | ||||
| 				return err | ||||
| 			} | ||||
|  | ||||
| 			return nil | ||||
| 		}, | ||||
| 		Run: func(_ *cobra.Command, _ []string) { | ||||
| 			stepTelemetryData := telemetry.CustomData{} | ||||
| 			stepTelemetryData.ErrorCode = "1" | ||||
| 			handler := func() { | ||||
| 				config.RemoveVaultSecretFiles() | ||||
| 				stepTelemetryData.Duration = fmt.Sprintf("%v", time.Since(startTime).Milliseconds()) | ||||
| 				stepTelemetryData.ErrorCategory = log.GetErrorCategory().String() | ||||
| 				stepTelemetryData.PiperCommitHash = GitCommit | ||||
| 				telemetryClient.SetData(&stepTelemetryData) | ||||
| 				telemetryClient.Send() | ||||
| 				if len(GeneralConfig.HookConfig.SplunkConfig.Dsn) > 0 { | ||||
| 					splunkClient.Send(telemetryClient.GetData(), logCollector) | ||||
| 				} | ||||
| 			} | ||||
| 			log.DeferExitHandler(handler) | ||||
| 			defer handler() | ||||
| 			telemetryClient.Initialize(GeneralConfig.NoTelemetry, STEP_NAME) | ||||
| 			if len(GeneralConfig.HookConfig.SplunkConfig.Dsn) > 0 { | ||||
| 				splunkClient.Initialize(GeneralConfig.CorrelationID, | ||||
| 					GeneralConfig.HookConfig.SplunkConfig.Dsn, | ||||
| 					GeneralConfig.HookConfig.SplunkConfig.Token, | ||||
| 					GeneralConfig.HookConfig.SplunkConfig.Index, | ||||
| 					GeneralConfig.HookConfig.SplunkConfig.SendLogs) | ||||
| 			} | ||||
| 			abapEnvironmentCreateTag(stepConfig, &stepTelemetryData) | ||||
| 			stepTelemetryData.ErrorCode = "0" | ||||
| 			log.Entry().Info("SUCCESS") | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	addAbapEnvironmentCreateTagFlags(createAbapEnvironmentCreateTagCmd, &stepConfig) | ||||
| 	return createAbapEnvironmentCreateTagCmd | ||||
| } | ||||
|  | ||||
| func addAbapEnvironmentCreateTagFlags(cmd *cobra.Command, stepConfig *abapEnvironmentCreateTagOptions) { | ||||
| 	cmd.Flags().StringVar(&stepConfig.Username, "username", os.Getenv("PIPER_username"), "User for either the Cloud Foundry API or the Communication Arrangement for SAP_COM_0510") | ||||
| 	cmd.Flags().StringVar(&stepConfig.Password, "password", os.Getenv("PIPER_password"), "Password for either the Cloud Foundry API or the Communication Arrangement for SAP_COM_0510") | ||||
| 	cmd.Flags().StringVar(&stepConfig.Repositories, "repositories", os.Getenv("PIPER_repositories"), "Specifies a YAML file containing the repositories configuration") | ||||
| 	cmd.Flags().StringVar(&stepConfig.RepositoryName, "repositoryName", os.Getenv("PIPER_repositoryName"), "Specifies a repository (Software Components) on the SAP BTP ABAP Environment system") | ||||
| 	cmd.Flags().StringVar(&stepConfig.CommitID, "commitID", os.Getenv("PIPER_commitID"), "Specifies a commitID, for which a tag will be created") | ||||
| 	cmd.Flags().StringVar(&stepConfig.TagName, "tagName", os.Getenv("PIPER_tagName"), "Specifies a tagName that will be created for the repositories on the SAP BTP ABAP Environment system") | ||||
| 	cmd.Flags().StringVar(&stepConfig.TagDescription, "tagDescription", os.Getenv("PIPER_tagDescription"), "Specifies a description for the created tag") | ||||
| 	cmd.Flags().BoolVar(&stepConfig.GenerateTagForAddonProductVersion, "generateTagForAddonProductVersion", false, "Specifies if a tag will be created for the repositories on the SAP BTP ABAP Environment system") | ||||
| 	cmd.Flags().BoolVar(&stepConfig.GenerateTagForAddonComponentVersion, "generateTagForAddonComponentVersion", false, "Specifies if a tag will be created for the repositories on the SAP BTP ABAP Environment system") | ||||
| 	cmd.Flags().StringVar(&stepConfig.Host, "host", os.Getenv("PIPER_host"), "Specifies the host address of the SAP BTP ABAP Environment system") | ||||
| 	cmd.Flags().StringVar(&stepConfig.CfAPIEndpoint, "cfApiEndpoint", os.Getenv("PIPER_cfApiEndpoint"), "Cloud Foundry API Enpoint") | ||||
| 	cmd.Flags().StringVar(&stepConfig.CfOrg, "cfOrg", os.Getenv("PIPER_cfOrg"), "Cloud Foundry target organization") | ||||
| 	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.MarkFlagRequired("username") | ||||
| 	cmd.MarkFlagRequired("password") | ||||
| } | ||||
|  | ||||
| // retrieve step metadata | ||||
| func abapEnvironmentCreateTagMetadata() config.StepData { | ||||
| 	var theMetaData = config.StepData{ | ||||
| 		Metadata: config.StepMetadata{ | ||||
| 			Name:        "abapEnvironmentCreateTag", | ||||
| 			Aliases:     []config.Alias{}, | ||||
| 			Description: "Creates a tag for a git repository to a SAP BTP ABAP Environment system", | ||||
| 		}, | ||||
| 		Spec: config.StepSpec{ | ||||
| 			Inputs: config.StepInputs{ | ||||
| 				Secrets: []config.StepSecrets{ | ||||
| 					{Name: "abapCredentialsId", Description: "Jenkins credentials ID containing user and password to authenticate to the BTP ABAP Environment system or the Cloud Foundry API", Type: "jenkins", Aliases: []config.Alias{{Name: "cfCredentialsId", Deprecated: false}, {Name: "credentialsId", Deprecated: false}}}, | ||||
| 				}, | ||||
| 				Parameters: []config.StepParameters{ | ||||
| 					{ | ||||
| 						Name: "username", | ||||
| 						ResourceRef: []config.ResourceReference{ | ||||
| 							{ | ||||
| 								Name:  "abapCredentialsId", | ||||
| 								Param: "username", | ||||
| 								Type:  "secret", | ||||
| 							}, | ||||
| 						}, | ||||
| 						Scope:     []string{"PARAMETERS", "STAGES", "STEPS"}, | ||||
| 						Type:      "string", | ||||
| 						Mandatory: true, | ||||
| 						Aliases:   []config.Alias{}, | ||||
| 						Default:   os.Getenv("PIPER_username"), | ||||
| 					}, | ||||
| 					{ | ||||
| 						Name: "password", | ||||
| 						ResourceRef: []config.ResourceReference{ | ||||
| 							{ | ||||
| 								Name:  "abapCredentialsId", | ||||
| 								Param: "password", | ||||
| 								Type:  "secret", | ||||
| 							}, | ||||
| 						}, | ||||
| 						Scope:     []string{"PARAMETERS", "STAGES", "STEPS"}, | ||||
| 						Type:      "string", | ||||
| 						Mandatory: true, | ||||
| 						Aliases:   []config.Alias{}, | ||||
| 						Default:   os.Getenv("PIPER_password"), | ||||
| 					}, | ||||
| 					{ | ||||
| 						Name:        "repositories", | ||||
| 						ResourceRef: []config.ResourceReference{}, | ||||
| 						Scope:       []string{"GENERAL", "PARAMETERS", "STAGES", "STEPS"}, | ||||
| 						Type:        "string", | ||||
| 						Mandatory:   false, | ||||
| 						Aliases:     []config.Alias{}, | ||||
| 						Default:     os.Getenv("PIPER_repositories"), | ||||
| 					}, | ||||
| 					{ | ||||
| 						Name:        "repositoryName", | ||||
| 						ResourceRef: []config.ResourceReference{}, | ||||
| 						Scope:       []string{"PARAMETERS", "STAGES", "STEPS"}, | ||||
| 						Type:        "string", | ||||
| 						Mandatory:   false, | ||||
| 						Aliases:     []config.Alias{}, | ||||
| 						Default:     os.Getenv("PIPER_repositoryName"), | ||||
| 					}, | ||||
| 					{ | ||||
| 						Name:        "commitID", | ||||
| 						ResourceRef: []config.ResourceReference{}, | ||||
| 						Scope:       []string{"PARAMETERS", "STAGES", "STEPS"}, | ||||
| 						Type:        "string", | ||||
| 						Mandatory:   false, | ||||
| 						Aliases:     []config.Alias{}, | ||||
| 						Default:     os.Getenv("PIPER_commitID"), | ||||
| 					}, | ||||
| 					{ | ||||
| 						Name:        "tagName", | ||||
| 						ResourceRef: []config.ResourceReference{}, | ||||
| 						Scope:       []string{"PARAMETERS", "STAGES", "STEPS"}, | ||||
| 						Type:        "string", | ||||
| 						Mandatory:   false, | ||||
| 						Aliases:     []config.Alias{}, | ||||
| 						Default:     os.Getenv("PIPER_tagName"), | ||||
| 					}, | ||||
| 					{ | ||||
| 						Name:        "tagDescription", | ||||
| 						ResourceRef: []config.ResourceReference{}, | ||||
| 						Scope:       []string{"PARAMETERS", "STAGES", "STEPS"}, | ||||
| 						Type:        "string", | ||||
| 						Mandatory:   false, | ||||
| 						Aliases:     []config.Alias{}, | ||||
| 						Default:     os.Getenv("PIPER_tagDescription"), | ||||
| 					}, | ||||
| 					{ | ||||
| 						Name:        "generateTagForAddonProductVersion", | ||||
| 						ResourceRef: []config.ResourceReference{}, | ||||
| 						Scope:       []string{"PARAMETERS", "STAGES", "STEPS"}, | ||||
| 						Type:        "bool", | ||||
| 						Mandatory:   false, | ||||
| 						Aliases:     []config.Alias{}, | ||||
| 						Default:     false, | ||||
| 					}, | ||||
| 					{ | ||||
| 						Name:        "generateTagForAddonComponentVersion", | ||||
| 						ResourceRef: []config.ResourceReference{}, | ||||
| 						Scope:       []string{"PARAMETERS", "STAGES", "STEPS"}, | ||||
| 						Type:        "bool", | ||||
| 						Mandatory:   false, | ||||
| 						Aliases:     []config.Alias{}, | ||||
| 						Default:     false, | ||||
| 					}, | ||||
| 					{ | ||||
| 						Name:        "host", | ||||
| 						ResourceRef: []config.ResourceReference{}, | ||||
| 						Scope:       []string{"PARAMETERS", "STAGES", "STEPS", "GENERAL"}, | ||||
| 						Type:        "string", | ||||
| 						Mandatory:   false, | ||||
| 						Aliases:     []config.Alias{}, | ||||
| 						Default:     os.Getenv("PIPER_host"), | ||||
| 					}, | ||||
| 					{ | ||||
| 						Name:        "cfApiEndpoint", | ||||
| 						ResourceRef: []config.ResourceReference{}, | ||||
| 						Scope:       []string{"PARAMETERS", "STAGES", "STEPS", "GENERAL"}, | ||||
| 						Type:        "string", | ||||
| 						Mandatory:   false, | ||||
| 						Aliases:     []config.Alias{{Name: "cloudFoundry/apiEndpoint"}}, | ||||
| 						Default:     os.Getenv("PIPER_cfApiEndpoint"), | ||||
| 					}, | ||||
| 					{ | ||||
| 						Name:        "cfOrg", | ||||
| 						ResourceRef: []config.ResourceReference{}, | ||||
| 						Scope:       []string{"PARAMETERS", "STAGES", "STEPS", "GENERAL"}, | ||||
| 						Type:        "string", | ||||
| 						Mandatory:   false, | ||||
| 						Aliases:     []config.Alias{{Name: "cloudFoundry/org"}}, | ||||
| 						Default:     os.Getenv("PIPER_cfOrg"), | ||||
| 					}, | ||||
| 					{ | ||||
| 						Name:        "cfSpace", | ||||
| 						ResourceRef: []config.ResourceReference{}, | ||||
| 						Scope:       []string{"PARAMETERS", "STAGES", "STEPS", "GENERAL"}, | ||||
| 						Type:        "string", | ||||
| 						Mandatory:   false, | ||||
| 						Aliases:     []config.Alias{{Name: "cloudFoundry/space"}}, | ||||
| 						Default:     os.Getenv("PIPER_cfSpace"), | ||||
| 					}, | ||||
| 					{ | ||||
| 						Name:        "cfServiceInstance", | ||||
| 						ResourceRef: []config.ResourceReference{}, | ||||
| 						Scope:       []string{"PARAMETERS", "STAGES", "STEPS", "GENERAL"}, | ||||
| 						Type:        "string", | ||||
| 						Mandatory:   false, | ||||
| 						Aliases:     []config.Alias{{Name: "cloudFoundry/serviceInstance"}}, | ||||
| 						Default:     os.Getenv("PIPER_cfServiceInstance"), | ||||
| 					}, | ||||
| 					{ | ||||
| 						Name:        "cfServiceKeyName", | ||||
| 						ResourceRef: []config.ResourceReference{}, | ||||
| 						Scope:       []string{"PARAMETERS", "STAGES", "STEPS", "GENERAL"}, | ||||
| 						Type:        "string", | ||||
| 						Mandatory:   false, | ||||
| 						Aliases:     []config.Alias{{Name: "cloudFoundry/serviceKey"}, {Name: "cloudFoundry/serviceKeyName"}, {Name: "cfServiceKey"}}, | ||||
| 						Default:     os.Getenv("PIPER_cfServiceKeyName"), | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 			Containers: []config.Container{ | ||||
| 				{Name: "cf", Image: "ppiper/cf-cli:7"}, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| 	return theMetaData | ||||
| } | ||||
							
								
								
									
										17
									
								
								cmd/abapEnvironmentCreateTag_generated_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								cmd/abapEnvironmentCreateTag_generated_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | ||||
| package cmd | ||||
|  | ||||
| import ( | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| ) | ||||
|  | ||||
| func TestAbapEnvironmentCreateTagCommand(t *testing.T) { | ||||
| 	t.Parallel() | ||||
|  | ||||
| 	testCmd := AbapEnvironmentCreateTagCommand() | ||||
|  | ||||
| 	// only high level testing performed - details are tested in step generation procedure | ||||
| 	assert.Equal(t, "abapEnvironmentCreateTag", testCmd.Use, "command name incorrect") | ||||
|  | ||||
| } | ||||
							
								
								
									
										349
									
								
								cmd/abapEnvironmentCreateTag_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										349
									
								
								cmd/abapEnvironmentCreateTag_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,349 @@ | ||||
| package cmd | ||||
|  | ||||
| import ( | ||||
| 	"io/ioutil" | ||||
| 	"os" | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/SAP/jenkins-library/pkg/abaputils" | ||||
| 	"github.com/SAP/jenkins-library/pkg/log" | ||||
| 	"github.com/SAP/jenkins-library/pkg/mock" | ||||
| 	"github.com/sirupsen/logrus/hooks/test" | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| ) | ||||
|  | ||||
| type abapEnvironmentCreateTagMockUtils struct { | ||||
| 	*mock.ExecMockRunner | ||||
| 	*mock.FilesMock | ||||
| } | ||||
|  | ||||
| func newAbapEnvironmentCreateTagTestsUtils() abapEnvironmentCreateTagMockUtils { | ||||
| 	utils := abapEnvironmentCreateTagMockUtils{ | ||||
| 		ExecMockRunner: &mock.ExecMockRunner{}, | ||||
| 		FilesMock:      &mock.FilesMock{}, | ||||
| 	} | ||||
| 	return utils | ||||
| } | ||||
|  | ||||
| func TestRunAbapEnvironmentCreateTag(t *testing.T) { | ||||
|  | ||||
| 	t.Run("happy path", 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 := `--- | ||||
| addonVersion: "1.2.3" | ||||
| addonProduct: "/DMO/PRODUCT" | ||||
| repositories: | ||||
|   - name: /DMO/SWC | ||||
|     branch: main | ||||
|     commitID: 1234abcd | ||||
|     version: "4.5.6" | ||||
| ` | ||||
| 		file, _ := os.Create("repo.yml") | ||||
| 		file.Write([]byte(body)) | ||||
| 		config := &abapEnvironmentCreateTagOptions{ | ||||
| 			Username:                            "dummy", | ||||
| 			Password:                            "dummy", | ||||
| 			Host:                                "https://test.com", | ||||
| 			Repositories:                        "repo.yml", | ||||
| 			TagName:                             "tag", | ||||
| 			TagDescription:                      "desc", | ||||
| 			GenerateTagForAddonProductVersion:   true, | ||||
| 			GenerateTagForAddonComponentVersion: true, | ||||
| 		} | ||||
| 		client := &abaputils.ClientMock{ | ||||
| 			BodyList: []string{ | ||||
| 				`{"d" : { "Status" : "S" } }`, | ||||
| 				`{"d" : { "uuid" : "abc" } }`, | ||||
| 				`{"d" : { "Status" : "S" } }`, | ||||
| 				`{"d" : { "uuid" : "abc" } }`, | ||||
| 				`{"d" : { "Status" : "S" } }`, | ||||
| 				`{"d" : { "uuid" : "abc" } }`, | ||||
| 				`{"d" : { "empty" : "body" } }`, | ||||
| 			}, | ||||
| 			Token:      "myToken", | ||||
| 			StatusCode: 200, | ||||
| 		} | ||||
|  | ||||
| 		_, hook := test.NewNullLogger() | ||||
| 		log.RegisterHook(hook) | ||||
|  | ||||
| 		err := runAbapEnvironmentCreateTag(config, nil, autils, client) | ||||
|  | ||||
| 		assert.NoError(t, err, "Did not expect error") | ||||
| 		assert.Equal(t, 3, len(hook.Entries), "Expected a different number of entries") | ||||
| 		assert.Equal(t, `Created tag v4.5.6 for repository /DMO/SWC with commitID 1234abcd`, hook.AllEntries()[0].Message, "Expected a different message") | ||||
| 		assert.Equal(t, `Created tag -DMO-PRODUCT-1.2.3 for repository /DMO/SWC with commitID 1234abcd`, hook.AllEntries()[1].Message, "Expected a different message") | ||||
| 		assert.Equal(t, `Created tag tag for repository /DMO/SWC with commitID 1234abcd`, hook.AllEntries()[2].Message, "Expected a different message") | ||||
| 		hook.Reset() | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("backend 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 := `--- | ||||
| addonVersion: "1.2.3" | ||||
| addonProduct: "/DMO/PRODUCT" | ||||
| repositories: | ||||
|   - name: /DMO/SWC | ||||
|     branch: main | ||||
|     commitID: 1234abcd | ||||
|     version: "4.5.6" | ||||
| ` | ||||
| 		file, _ := os.Create("repo.yml") | ||||
| 		file.Write([]byte(body)) | ||||
| 		config := &abapEnvironmentCreateTagOptions{ | ||||
| 			Username:                            "dummy", | ||||
| 			Password:                            "dummy", | ||||
| 			Host:                                "https://test.com", | ||||
| 			Repositories:                        "repo.yml", | ||||
| 			TagName:                             "tag", | ||||
| 			TagDescription:                      "desc", | ||||
| 			GenerateTagForAddonProductVersion:   true, | ||||
| 			GenerateTagForAddonComponentVersion: true, | ||||
| 		} | ||||
| 		client := &abaputils.ClientMock{ | ||||
| 			BodyList: []string{ | ||||
| 				`{"d" : { "Status" : "E" } }`, | ||||
| 				`{"d" : { "uuid" : "abc" } }`, | ||||
| 				`{"d" : { "Status" : "E" } }`, | ||||
| 				`{"d" : { "uuid" : "abc" } }`, | ||||
| 				`{"d" : { "Status" : "E" } }`, | ||||
| 				`{"d" : { "uuid" : "abc" } }`, | ||||
| 				`{"d" : { "empty" : "body" } }`, | ||||
| 			}, | ||||
| 			Token:      "myToken", | ||||
| 			StatusCode: 200, | ||||
| 		} | ||||
|  | ||||
| 		_, hook := test.NewNullLogger() | ||||
| 		log.RegisterHook(hook) | ||||
|  | ||||
| 		err := runAbapEnvironmentCreateTag(config, nil, autils, client) | ||||
|  | ||||
| 		assert.Error(t, err, "Did expect error") | ||||
| 		assert.Equal(t, 4, len(hook.Entries), "Expected a different number of entries") | ||||
| 		assert.Equal(t, `NOT created: Tag v4.5.6 for repository /DMO/SWC with commitID 1234abcd`, hook.AllEntries()[0].Message, "Expected a different message") | ||||
| 		assert.Equal(t, `NOT created: Tag -DMO-PRODUCT-1.2.3 for repository /DMO/SWC with commitID 1234abcd`, hook.AllEntries()[1].Message, "Expected a different message") | ||||
| 		assert.Equal(t, `NOT created: Tag tag for repository /DMO/SWC with commitID 1234abcd`, hook.AllEntries()[2].Message, "Expected a different message") | ||||
| 		assert.Equal(t, `At least one tag has not been created`, hook.AllEntries()[3].Message, "Expected a different message") | ||||
| 		hook.Reset() | ||||
|  | ||||
| 	}) | ||||
|  | ||||
| } | ||||
|  | ||||
| func TestRunAbapEnvironmentCreateTagConfigurations(t *testing.T) { | ||||
|  | ||||
| 	t.Run("no repo.yml", 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 := &abapEnvironmentCreateTagOptions{ | ||||
| 			Username:                            "dummy", | ||||
| 			Password:                            "dummy", | ||||
| 			Host:                                "https://test.com", | ||||
| 			RepositoryName:                      "/DMO/SWC", | ||||
| 			CommitID:                            "1234abcd", | ||||
| 			TagName:                             "tag", | ||||
| 			TagDescription:                      "desc", | ||||
| 			GenerateTagForAddonProductVersion:   true, | ||||
| 			GenerateTagForAddonComponentVersion: true, | ||||
| 		} | ||||
| 		client := &abaputils.ClientMock{ | ||||
| 			BodyList: []string{ | ||||
| 				`{"d" : { "Status" : "S" } }`, | ||||
| 				`{"d" : { "uuid" : "abc" } }`, | ||||
| 				`{"d" : { "empty" : "body" } }`, | ||||
| 			}, | ||||
| 			Token:      "myToken", | ||||
| 			StatusCode: 200, | ||||
| 		} | ||||
|  | ||||
| 		_, hook := test.NewNullLogger() | ||||
| 		log.RegisterHook(hook) | ||||
|  | ||||
| 		err := runAbapEnvironmentCreateTag(config, nil, autils, client) | ||||
|  | ||||
| 		assert.NoError(t, err, "Did not expect error") | ||||
| 		assert.Equal(t, 1, len(hook.Entries), "Expected a different number of entries") | ||||
| 		assert.Equal(t, `Created tag tag for repository /DMO/SWC with commitID 1234abcd`, hook.AllEntries()[0].Message, "Expected a different message") | ||||
| 		hook.Reset() | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("backend 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 := `--- | ||||
| addonVersion: "1.2.3" | ||||
| addonProduct: "/DMO/PRODUCT" | ||||
| repositories: | ||||
|   - name: /DMO/SWC | ||||
|     branch: main | ||||
|     commitID: 1234abcd | ||||
|     version: "4.5.6" | ||||
| ` | ||||
| 		file, _ := os.Create("repo.yml") | ||||
| 		file.Write([]byte(body)) | ||||
| 		config := &abapEnvironmentCreateTagOptions{ | ||||
| 			Username:                            "dummy", | ||||
| 			Password:                            "dummy", | ||||
| 			Host:                                "https://test.com", | ||||
| 			Repositories:                        "repo.yml", | ||||
| 			RepositoryName:                      "/DMO/SWC2", | ||||
| 			CommitID:                            "1234abcde", | ||||
| 			TagName:                             "tag", | ||||
| 			TagDescription:                      "desc", | ||||
| 			GenerateTagForAddonProductVersion:   true, | ||||
| 			GenerateTagForAddonComponentVersion: true, | ||||
| 		} | ||||
| 		client := &abaputils.ClientMock{ | ||||
| 			BodyList: []string{ | ||||
| 				`{"d" : { "Status" : "S" } }`, | ||||
| 				`{"d" : { "uuid" : "abc" } }`, | ||||
| 				`{"d" : { "Status" : "S" } }`, | ||||
| 				`{"d" : { "uuid" : "abc" } }`, | ||||
| 				`{"d" : { "Status" : "S" } }`, | ||||
| 				`{"d" : { "uuid" : "abc" } }`, | ||||
| 				`{"d" : { "Status" : "S" } }`, | ||||
| 				`{"d" : { "uuid" : "abc" } }`, | ||||
| 				`{"d" : { "Status" : "S" } }`, | ||||
| 				`{"d" : { "uuid" : "abc" } }`, | ||||
| 				`{"d" : { "empty" : "body" } }`, | ||||
| 			}, | ||||
| 			Token:      "myToken", | ||||
| 			StatusCode: 200, | ||||
| 		} | ||||
|  | ||||
| 		err := runAbapEnvironmentCreateTag(config, nil, autils, client) | ||||
|  | ||||
| 		assert.Error(t, err, "Did expect error") | ||||
| 		assert.Equal(t, "Something failed during the tag creation: Configuring the parameter repositories and the parameter repositoryName at the same time is not allowed", err.Error(), "Expected different error message") | ||||
|  | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("flags false", 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 := `--- | ||||
| addonVersion: "1.2.3" | ||||
| addonProduct: "/DMO/PRODUCT" | ||||
| repositories: | ||||
|   - name: /DMO/SWC | ||||
|     branch: main | ||||
|     commitID: 1234abcd | ||||
|     version: "4.5.6" | ||||
| ` | ||||
| 		file, _ := os.Create("repo.yml") | ||||
| 		file.Write([]byte(body)) | ||||
| 		config := &abapEnvironmentCreateTagOptions{ | ||||
| 			Username:                            "dummy", | ||||
| 			Password:                            "dummy", | ||||
| 			Host:                                "https://test.com", | ||||
| 			Repositories:                        "repo.yml", | ||||
| 			TagName:                             "tag", | ||||
| 			TagDescription:                      "desc", | ||||
| 			GenerateTagForAddonProductVersion:   false, | ||||
| 			GenerateTagForAddonComponentVersion: false, | ||||
| 		} | ||||
| 		client := &abaputils.ClientMock{ | ||||
| 			BodyList: []string{ | ||||
| 				`{"d" : { "Status" : "S" } }`, | ||||
| 				`{"d" : { "uuid" : "abc" } }`, | ||||
| 				`{"d" : { "Status" : "S" } }`, | ||||
| 				`{"d" : { "uuid" : "abc" } }`, | ||||
| 				`{"d" : { "empty" : "body" } }`, | ||||
| 			}, | ||||
| 			Token:      "myToken", | ||||
| 			StatusCode: 200, | ||||
| 		} | ||||
|  | ||||
| 		_, hook := test.NewNullLogger() | ||||
| 		log.RegisterHook(hook) | ||||
|  | ||||
| 		err := runAbapEnvironmentCreateTag(config, nil, autils, client) | ||||
|  | ||||
| 		assert.NoError(t, err, "Did not expect error") | ||||
| 		assert.Equal(t, 1, len(hook.Entries), "Expected a different number of entries") | ||||
| 		assert.Equal(t, `Created tag tag for repository /DMO/SWC with commitID 1234abcd`, hook.AllEntries()[0].Message, "Expected a different message") | ||||
| 		hook.Reset() | ||||
|  | ||||
| 	}) | ||||
| } | ||||
| @@ -20,6 +20,7 @@ func GetAllStepMetadata() map[string]config.StepData { | ||||
| 		"abapEnvironmentCheckoutBranch":             abapEnvironmentCheckoutBranchMetadata(), | ||||
| 		"abapEnvironmentCloneGitRepo":               abapEnvironmentCloneGitRepoMetadata(), | ||||
| 		"abapEnvironmentCreateSystem":               abapEnvironmentCreateSystemMetadata(), | ||||
| 		"abapEnvironmentCreateTag":                  abapEnvironmentCreateTagMetadata(), | ||||
| 		"abapEnvironmentPullGitRepo":                abapEnvironmentPullGitRepoMetadata(), | ||||
| 		"abapEnvironmentPushATCSystemConfig":        abapEnvironmentPushATCSystemConfigMetadata(), | ||||
| 		"abapEnvironmentRunATCCheck":                abapEnvironmentRunATCCheckMetadata(), | ||||
|   | ||||
| @@ -108,6 +108,7 @@ func Execute() { | ||||
| 	rootCmd.AddCommand(AbapEnvironmentPullGitRepoCommand()) | ||||
| 	rootCmd.AddCommand(AbapEnvironmentCloneGitRepoCommand()) | ||||
| 	rootCmd.AddCommand(AbapEnvironmentCheckoutBranchCommand()) | ||||
| 	rootCmd.AddCommand(AbapEnvironmentCreateTagCommand()) | ||||
| 	rootCmd.AddCommand(AbapEnvironmentCreateSystemCommand()) | ||||
| 	rootCmd.AddCommand(CheckmarxExecuteScanCommand()) | ||||
| 	rootCmd.AddCommand(FortifyExecuteScanCommand()) | ||||
|   | ||||
| @@ -14,6 +14,8 @@ import ( | ||||
| 	"github.com/pkg/errors" | ||||
| ) | ||||
|  | ||||
| const failureMessageClonePull = "Could not pull the Repository / Software Component " | ||||
|  | ||||
| // PollEntity periodically polls the pull/import entity to get the status. Check if the import is still running | ||||
| func PollEntity(repositoryName string, connectionDetails ConnectionDetailsHTTP, client piperhttp.Sender, pollIntervall time.Duration) (string, error) { | ||||
|  | ||||
| @@ -21,7 +23,7 @@ func PollEntity(repositoryName string, connectionDetails ConnectionDetailsHTTP, | ||||
| 	var status string = "R" | ||||
|  | ||||
| 	for { | ||||
| 		pullEntity, responseStatus, err := GetPullStatus(repositoryName, connectionDetails, client) | ||||
| 		pullEntity, responseStatus, err := GetStatus(failureMessageClonePull+repositoryName, connectionDetails, client) | ||||
| 		if err != nil { | ||||
| 			return status, err | ||||
| 		} | ||||
| @@ -78,7 +80,7 @@ func serviceContainsNewLogEntities(connectionDetails ConnectionDetailsHTTP, clie | ||||
|  | ||||
| func PrintLogs(repositoryName string, connectionDetails ConnectionDetailsHTTP, client piperhttp.Sender) { | ||||
| 	connectionDetails.URL = connectionDetails.URL + "?$expand=to_Log_Overview,to_Log_Overview/to_Log_Protocol" | ||||
| 	entity, _, err := GetPullStatus(repositoryName, connectionDetails, client) | ||||
| 	entity, _, err := GetStatus(failureMessageClonePull+repositoryName, connectionDetails, client) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| @@ -162,7 +164,7 @@ func printLog(logEntry LogResultsV2) { | ||||
| func PrintLegacyLogs(repositoryName string, connectionDetails ConnectionDetailsHTTP, client piperhttp.Sender, errorOnSystem bool) { | ||||
|  | ||||
| 	connectionDetails.URL = connectionDetails.URL + "?$expand=to_Transport_log,to_Execution_log" | ||||
| 	entity, _, err := GetPullStatus(repositoryName, connectionDetails, client) | ||||
| 	entity, _, err := GetStatus(failureMessageClonePull+repositoryName, connectionDetails, client) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| @@ -212,11 +214,11 @@ func PrintLegacyLogs(repositoryName string, connectionDetails ConnectionDetailsH | ||||
|  | ||||
| } | ||||
|  | ||||
| func GetPullStatus(repositoryName string, connectionDetails ConnectionDetailsHTTP, client piperhttp.Sender) (body PullEntity, status string, err error) { | ||||
| func GetStatus(failureMessage string, connectionDetails ConnectionDetailsHTTP, client piperhttp.Sender) (body PullEntity, status string, err error) { | ||||
| 	resp, err := GetHTTPResponse("GET", connectionDetails, nil, client) | ||||
| 	if err != nil { | ||||
| 		log.SetErrorCategory(log.ErrorInfrastructure) | ||||
| 		err = HandleHTTPError(resp, err, "Could not pull the Repository / Software Component "+repositoryName, connectionDetails) | ||||
| 		err = HandleHTTPError(resp, err, failureMessage, connectionDetails) | ||||
| 		return body, resp.Status, err | ||||
| 	} | ||||
| 	defer resp.Body.Close() | ||||
| @@ -229,7 +231,7 @@ func GetPullStatus(repositoryName string, connectionDetails ConnectionDetailsHTT | ||||
| 	json.Unmarshal(*abapResp["d"], &body) | ||||
|  | ||||
| 	if reflect.DeepEqual(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).Error(failureMessage) | ||||
| 		log.SetErrorCategory(log.ErrorInfrastructure) | ||||
| 		var err = errors.New("Request to ABAP System not successful") | ||||
| 		return body, resp.Status, err | ||||
|   | ||||
							
								
								
									
										160
									
								
								resources/metadata/abapEnvironmentCreateTag.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										160
									
								
								resources/metadata/abapEnvironmentCreateTag.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,160 @@ | ||||
| metadata: | ||||
|   name: abapEnvironmentCreateTag | ||||
|   description: Creates a tag for a git repository to a SAP BTP ABAP Environment system | ||||
|   longDescription: | | ||||
|     Creates tags for specific commits of one or multiple repositories / software components. The tag can be specified explicitly as well as being generated by an addon product version or an addon component version. | ||||
|     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). | ||||
|     * The Cloud Foundry parameters (API endpoint, organization, space), credentials, the service instance for the ABAP service and the service key for the Communication Scenario SAP_COM_0510. | ||||
|     * Only provide one of those options with the respective credentials. If all values are provided, the direct communication (via host) has priority. | ||||
|  | ||||
| spec: | ||||
|   inputs: | ||||
|     secrets: | ||||
|       - name: abapCredentialsId | ||||
|         description: Jenkins credentials ID containing user and password to authenticate to the BTP ABAP Environment system or the Cloud Foundry API | ||||
|         type: jenkins | ||||
|         aliases: | ||||
|           - name: cfCredentialsId | ||||
|           - name: credentialsId | ||||
|     params: | ||||
|       - name: username | ||||
|         type: string | ||||
|         description: User for either the Cloud Foundry API or the Communication Arrangement for SAP_COM_0510 | ||||
|         scope: | ||||
|           - PARAMETERS | ||||
|           - STAGES | ||||
|           - STEPS | ||||
|         mandatory: true | ||||
|         secret: true | ||||
|         resourceRef: | ||||
|           - name: abapCredentialsId | ||||
|             type: secret | ||||
|             param: username | ||||
|       - name: password | ||||
|         type: string | ||||
|         description: Password for either the Cloud Foundry API or the Communication Arrangement for SAP_COM_0510 | ||||
|         scope: | ||||
|           - PARAMETERS | ||||
|           - STAGES | ||||
|           - STEPS | ||||
|         mandatory: true | ||||
|         secret: true | ||||
|         resourceRef: | ||||
|           - name: abapCredentialsId | ||||
|             type: secret | ||||
|             param: password | ||||
|       - name: repositories | ||||
|         type: string | ||||
|         description: Specifies a YAML file containing the repositories configuration | ||||
|         scope: | ||||
|           - GENERAL | ||||
|           - PARAMETERS | ||||
|           - STAGES | ||||
|           - STEPS | ||||
|       - name: repositoryName | ||||
|         type: string | ||||
|         description: Specifies a repository (Software Components) on the SAP BTP ABAP Environment system | ||||
|         scope: | ||||
|           - PARAMETERS | ||||
|           - STAGES | ||||
|           - STEPS | ||||
|       - name: commitID | ||||
|         type: string | ||||
|         description: Specifies a commitID, for which a tag will be created | ||||
|         scope: | ||||
|           - PARAMETERS | ||||
|           - STAGES | ||||
|           - STEPS | ||||
|       - name: tagName | ||||
|         type: string | ||||
|         description: Specifies a tagName that will be created for the repositories on the SAP BTP ABAP Environment system | ||||
|         scope: | ||||
|           - PARAMETERS | ||||
|           - STAGES | ||||
|           - STEPS | ||||
|       - name: tagDescription | ||||
|         type: string | ||||
|         description: Specifies a description for the created tag | ||||
|         scope: | ||||
|           - PARAMETERS | ||||
|           - STAGES | ||||
|           - STEPS | ||||
|       - name: generateTagForAddonProductVersion | ||||
|         type: bool | ||||
|         description: Specifies if a tag will be created for the repositories on the SAP BTP ABAP Environment system | ||||
|         scope: | ||||
|           - PARAMETERS | ||||
|           - STAGES | ||||
|           - STEPS | ||||
|       - name: generateTagForAddonComponentVersion | ||||
|         type: bool | ||||
|         description: Specifies if a tag will be created for the repositories on the SAP BTP ABAP Environment system | ||||
|         scope: | ||||
|           - PARAMETERS | ||||
|           - STAGES | ||||
|           - STEPS | ||||
|       - name: host | ||||
|         type: string | ||||
|         description: Specifies the host address of the SAP BTP ABAP Environment system | ||||
|         scope: | ||||
|           - PARAMETERS | ||||
|           - STAGES | ||||
|           - STEPS | ||||
|           - GENERAL | ||||
|       - name: cfApiEndpoint | ||||
|         type: string | ||||
|         description: Cloud Foundry API Enpoint | ||||
|         scope: | ||||
|           - PARAMETERS | ||||
|           - STAGES | ||||
|           - STEPS | ||||
|           - GENERAL | ||||
|         aliases: | ||||
|           - name: cloudFoundry/apiEndpoint | ||||
|       - name: cfOrg | ||||
|         type: string | ||||
|         description: Cloud Foundry target organization | ||||
|         scope: | ||||
|           - PARAMETERS | ||||
|           - STAGES | ||||
|           - STEPS | ||||
|           - GENERAL | ||||
|         aliases: | ||||
|           - name: cloudFoundry/org | ||||
|       - name: cfSpace | ||||
|         type: string | ||||
|         description: Cloud Foundry target space | ||||
|         scope: | ||||
|           - PARAMETERS | ||||
|           - STAGES | ||||
|           - STEPS | ||||
|           - GENERAL | ||||
|         aliases: | ||||
|           - name: cloudFoundry/space | ||||
|       - name: cfServiceInstance | ||||
|         type: string | ||||
|         description: Cloud Foundry Service Instance | ||||
|         scope: | ||||
|           - PARAMETERS | ||||
|           - STAGES | ||||
|           - STEPS | ||||
|           - GENERAL | ||||
|         aliases: | ||||
|           - name: cloudFoundry/serviceInstance | ||||
|       - name: cfServiceKeyName | ||||
|         type: string | ||||
|         description: Cloud Foundry Service Key | ||||
|         scope: | ||||
|           - PARAMETERS | ||||
|           - STAGES | ||||
|           - STEPS | ||||
|           - GENERAL | ||||
|         aliases: | ||||
|           - name: cloudFoundry/serviceKey | ||||
|           - name: cloudFoundry/serviceKeyName | ||||
|           - name: cfServiceKey | ||||
|   containers: | ||||
|     - name: cf | ||||
|       image: ppiper/cf-cli:7 | ||||
		Reference in New Issue
	
	Block a user