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 
			
		
		
		
	feat(Gitops): Gitops update deployment with helm (#2247)
* makes containerImage not mandatory * Adds kubectl container * Adds log statement to debug * adds general to container image * removes GENERAL again Removes condition from Kubectl container * removes workDir * marks logs as debug * adds workingdir again * Adds author to commits * Adds commit time now * remove deprecated and reorder * adds deprecated again to containerRegistryUrl Adds GENERAL scope to containerImage * updates generated file * Renames containerImageNameTag * adds else case * adds debug log * code cleanup * adds debug log * revert * adds debug logs * revert * makes root path not hidden * revert * Read container properties * Removes debug message * Removes debug message * Removes general scope again * Fixes unit test * Adds helm capabilities to the gitopsUpdateDeployment step * Adds helm capabilities to gitopsUpdateDeployment step * Removes condition from input field * Adds test for invalid deploy tool * Fixes typo * Adds tests for git errors and file errors Simplifies test setup * Adds test for error on image name extraction * fixes URL variable name * adds workind directory to paths * Refactors too long method * Reverts refactoring method * Adds repository name as parameter * Adds glob method * Test glob method * Revert "Test glob method" This reverts commitac11b54c14. * Revert "Adds glob method" This reverts commitddf47ddebe. * Revert "Adds repository name as parameter" This reverts commit8fc471c909. * Removes getWd * Adds stash deployDescriptor * removes = from paramters * Revert "removes = from paramters" This reverts commit3ecb3665e2. * Adds " around parameters * adds logging of all files * Updates helm to version 3.3.4 * Clean up debug logs * Raise error if no branch name provided. Defaulting should be handled by step configuration. * clean code * Updates fields and adds checks for required field for certain deploy tools * Fixes default commit message * Update long description * Removes default parameter * Update resources/metadata/gitopsUpdateDeployment.yaml Co-authored-by: Christopher Fenner <26137398+CCFenner@users.noreply.github.com> * Updates yaml file * Add error category and removes too much wrapping * Update generated file * Checks all parameters before returning the error * Introduces constant * Renames constant * Fixes unit tests * unexpose constants * Makes tests thread safe and resilient to failed deletion * Remove methods that did not work properly with hash containers rather than tags. Co-authored-by: Stephan Aßmus <stephan.assmus@sap.com> Co-authored-by: Christopher Fenner <26137398+CCFenner@users.noreply.github.com> Co-authored-by: Oliver Nocon <33484802+OliverNocon@users.noreply.github.com>
This commit is contained in:
		| @@ -2,6 +2,7 @@ package cmd | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"fmt" | ||||
| 	"github.com/SAP/jenkins-library/pkg/command" | ||||
| 	"github.com/SAP/jenkins-library/pkg/docker" | ||||
| 	gitUtil "github.com/SAP/jenkins-library/pkg/git" | ||||
| @@ -14,8 +15,12 @@ import ( | ||||
| 	"io" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| const toolKubectl = "kubectl" | ||||
| const toolHelm = "helm" | ||||
|  | ||||
| type iGitopsUpdateDeploymentGitUtils interface { | ||||
| 	CommitSingleFile(filePath, commitMessage, author string) (plumbing.Hash, error) | ||||
| 	PushChangesToRepository(username, password string) error | ||||
| @@ -62,7 +67,7 @@ func (g *gitopsUpdateDeploymentGitUtils) ChangeBranch(branchName string) error { | ||||
| 	return gitUtil.ChangeBranch(branchName, g.worktree) | ||||
| } | ||||
|  | ||||
| func gitopsUpdateDeployment(config gitopsUpdateDeploymentOptions, telemetryData *telemetry.CustomData) { | ||||
| func gitopsUpdateDeployment(config gitopsUpdateDeploymentOptions, _ *telemetry.CustomData) { | ||||
| 	// for command execution use Command | ||||
| 	var c gitopsUpdateDeploymentExecRunner = &command.Command{} | ||||
| 	// reroute command output to logging framework | ||||
| @@ -81,37 +86,47 @@ func gitopsUpdateDeployment(config gitopsUpdateDeploymentOptions, telemetryData | ||||
| } | ||||
|  | ||||
| func runGitopsUpdateDeployment(config *gitopsUpdateDeploymentOptions, command gitopsUpdateDeploymentExecRunner, gitUtils iGitopsUpdateDeploymentGitUtils, fileUtils gitopsUpdateDeploymentFileUtils) error { | ||||
| 	err := checkRequiredFieldsForDeployTool(config) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	temporaryFolder, err := fileUtils.TempDir(".", "temp-") | ||||
| 	if err != nil { | ||||
| 		return errors.Wrap(err, "failed to create temporary directory") | ||||
| 	} | ||||
|  | ||||
| 	defer fileUtils.RemoveAll(temporaryFolder) | ||||
| 	defer func() { | ||||
| 		err = fileUtils.RemoveAll(temporaryFolder) | ||||
| 		if err != nil { | ||||
| 			log.Entry().WithError(err).Error("error during temporary directory deletion") | ||||
| 		} | ||||
| 	}() | ||||
|  | ||||
| 	err = gitUtils.PlainClone(config.Username, config.Password, config.ServerURL, temporaryFolder) | ||||
| 	err = cloneRepositoryAndChangeBranch(config, gitUtils, temporaryFolder) | ||||
| 	if err != nil { | ||||
| 		return errors.Wrap(err, "failed to plain clone repository") | ||||
| 		return errors.Wrap(err, "repository could not get prepared") | ||||
| 	} | ||||
|  | ||||
| 	err = gitUtils.ChangeBranch(config.BranchName) | ||||
| 	if err != nil { | ||||
| 		return errors.Wrap(err, "failed to change branch") | ||||
| 	} | ||||
|  | ||||
| 	registryImage, err := buildRegistryPlusImage(config) | ||||
| 	if err != nil { | ||||
| 		return errors.Wrap(err, "failed to apply kubectl command") | ||||
| 	} | ||||
| 	patchString := "{\"spec\":{\"template\":{\"spec\":{\"containers\":[{\"name\":\"" + config.ContainerName + "\",\"image\":\"" + registryImage + "\"}]}}}}" | ||||
|  | ||||
| 	filePath := filepath.Join(temporaryFolder, config.FilePath) | ||||
|  | ||||
| 	kubectlOutputBytes, err := runKubeCtlCommand(command, patchString, filePath) | ||||
| 	if err != nil { | ||||
| 		return errors.Wrap(err, "failed to apply kubectl command") | ||||
| 	var outputBytes []byte | ||||
| 	if config.Tool == toolKubectl { | ||||
| 		outputBytes, err = executeKubectl(config, command, outputBytes, filePath) | ||||
| 		if err != nil { | ||||
| 			return errors.Wrap(err, "error on kubectl execution") | ||||
| 		} | ||||
| 	} else if config.Tool == toolHelm { | ||||
| 		outputBytes, err = runHelmCommand(command, config) | ||||
| 		if err != nil { | ||||
| 			return errors.Wrap(err, "failed to apply helm command") | ||||
| 		} | ||||
| 	} else { | ||||
| 		log.SetErrorCategory(log.ErrorConfiguration) | ||||
| 		return errors.New("tool " + config.Tool + " is not supported") | ||||
| 	} | ||||
|  | ||||
| 	err = fileUtils.FileWrite(filePath, kubectlOutputBytes, 0755) | ||||
| 	err = fileUtils.FileWrite(filePath, outputBytes, 0755) | ||||
| 	if err != nil { | ||||
| 		return errors.Wrap(err, "failed to write file") | ||||
| 	} | ||||
| @@ -126,22 +141,94 @@ func runGitopsUpdateDeployment(config *gitopsUpdateDeploymentOptions, command gi | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func runKubeCtlCommand(command gitopsUpdateDeploymentExecRunner, patchString string, filePath string) ([]byte, error) { | ||||
| 	var kubectlOutput = bytes.Buffer{} | ||||
| 	command.Stdout(&kubectlOutput) | ||||
|  | ||||
| 	kubeParams := []string{ | ||||
| 		"patch", | ||||
| 		"--local", | ||||
| 		"--output=yaml", | ||||
| 		"--patch=" + patchString, | ||||
| 		"--filename=" + filePath, | ||||
| func checkRequiredFieldsForDeployTool(config *gitopsUpdateDeploymentOptions) error { | ||||
| 	if config.Tool == toolHelm { | ||||
| 		err := checkRequiredFieldsForHelm(config) | ||||
| 		if err != nil { | ||||
| 			return errors.Wrap(err, "missing required fields for helm") | ||||
| 		} | ||||
| 		logNotRequiredButFilledFieldForHelm(config) | ||||
| 	} else if config.Tool == toolKubectl { | ||||
| 		err := checkRequiredFieldsForKubectl(config) | ||||
| 		if err != nil { | ||||
| 			return errors.Wrap(err, "missing required fields for kubectl") | ||||
| 		} | ||||
| 		logNotRequiredButFilledFieldForKubectl(config) | ||||
| 	} | ||||
| 	err := command.RunExecutable("kubectl", kubeParams...) | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func checkRequiredFieldsForHelm(config *gitopsUpdateDeploymentOptions) error { | ||||
| 	var missingParameters []string | ||||
| 	if config.ChartPath == "" { | ||||
| 		missingParameters = append(missingParameters, "chartPath") | ||||
| 	} | ||||
| 	if config.DeploymentName == "" { | ||||
| 		missingParameters = append(missingParameters, "deploymentName") | ||||
| 	} | ||||
| 	if len(missingParameters) > 0 { | ||||
| 		log.SetErrorCategory(log.ErrorConfiguration) | ||||
| 		return errors.Errorf("the following parameters are necessary for helm: %v", missingParameters) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func checkRequiredFieldsForKubectl(config *gitopsUpdateDeploymentOptions) error { | ||||
| 	var missingParameters []string | ||||
| 	if config.ContainerName == "" { | ||||
| 		missingParameters = append(missingParameters, "containerName") | ||||
| 	} | ||||
| 	if len(missingParameters) > 0 { | ||||
| 		log.SetErrorCategory(log.ErrorConfiguration) | ||||
| 		return errors.Errorf("the following parameters are necessary for kubectl: %v", missingParameters) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func logNotRequiredButFilledFieldForHelm(config *gitopsUpdateDeploymentOptions) { | ||||
| 	if config.ContainerName != "" { | ||||
| 		log.Entry().Info("containerName is not used for helm and can be removed") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func logNotRequiredButFilledFieldForKubectl(config *gitopsUpdateDeploymentOptions) { | ||||
| 	if config.ChartPath != "" { | ||||
| 		log.Entry().Info("chartPath is not used for kubectl and can be removed") | ||||
| 	} | ||||
| 	if len(config.HelmValues) > 0 { | ||||
| 		log.Entry().Info("helmValues is not used for kubectl and can be removed") | ||||
| 	} | ||||
| 	if len(config.DeploymentName) > 0 { | ||||
| 		log.Entry().Info("deploymentName is not used for kubectl and can be removed") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func cloneRepositoryAndChangeBranch(config *gitopsUpdateDeploymentOptions, gitUtils iGitopsUpdateDeploymentGitUtils, temporaryFolder string) error { | ||||
| 	err := gitUtils.PlainClone(config.Username, config.Password, config.ServerURL, temporaryFolder) | ||||
| 	if err != nil { | ||||
| 		return errors.Wrap(err, "failed to plain clone repository") | ||||
| 	} | ||||
|  | ||||
| 	err = gitUtils.ChangeBranch(config.BranchName) | ||||
| 	if err != nil { | ||||
| 		return errors.Wrap(err, "failed to change branch") | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func executeKubectl(config *gitopsUpdateDeploymentOptions, command gitopsUpdateDeploymentExecRunner, outputBytes []byte, filePath string) ([]byte, error) { | ||||
| 	registryImage, err := buildRegistryPlusImage(config) | ||||
| 	if err != nil { | ||||
| 		return nil, errors.Wrap(err, "failed to apply kubectl command") | ||||
| 	} | ||||
| 	return kubectlOutput.Bytes(), nil | ||||
| 	patchString := "{\"spec\":{\"template\":{\"spec\":{\"containers\":[{\"name\":\"" + config.ContainerName + "\",\"image\":\"" + registryImage + "\"}]}}}}" | ||||
|  | ||||
| 	outputBytes, err = runKubeCtlCommand(command, patchString, filePath) | ||||
| 	if err != nil { | ||||
| 		return nil, errors.Wrap(err, "failed to apply kubectl command") | ||||
| 	} | ||||
| 	return outputBytes, nil | ||||
| } | ||||
|  | ||||
| func buildRegistryPlusImage(config *gitopsUpdateDeploymentOptions) (string, error) { | ||||
| @@ -160,8 +247,97 @@ func buildRegistryPlusImage(config *gitopsUpdateDeploymentOptions) (string, erro | ||||
| 	return url + config.ContainerImageNameTag, nil | ||||
| } | ||||
|  | ||||
| func runKubeCtlCommand(command gitopsUpdateDeploymentExecRunner, patchString string, filePath string) ([]byte, error) { | ||||
| 	var kubectlOutput = bytes.Buffer{} | ||||
| 	command.Stdout(&kubectlOutput) | ||||
|  | ||||
| 	kubeParams := []string{ | ||||
| 		"patch", | ||||
| 		"--local", | ||||
| 		"--output=yaml", | ||||
| 		"--patch=" + patchString, | ||||
| 		"--filename=" + filePath, | ||||
| 	} | ||||
| 	err := command.RunExecutable(toolKubectl, kubeParams...) | ||||
| 	if err != nil { | ||||
| 		return nil, errors.Wrap(err, "failed to apply kubectl command") | ||||
| 	} | ||||
| 	return kubectlOutput.Bytes(), nil | ||||
| } | ||||
|  | ||||
| func runHelmCommand(runner gitopsUpdateDeploymentExecRunner, config *gitopsUpdateDeploymentOptions) ([]byte, error) { | ||||
| 	var helmOutput = bytes.Buffer{} | ||||
| 	runner.Stdout(&helmOutput) | ||||
|  | ||||
| 	registryImage, imageTag, err := buildRegistryPlusImageAndTagSeparately(config) | ||||
| 	if err != nil { | ||||
| 		return nil, errors.Wrap(err, "failed to extract registry URL, image name, and image tag") | ||||
| 	} | ||||
| 	helmParams := []string{ | ||||
| 		"template", | ||||
| 		config.DeploymentName, | ||||
| 		filepath.Join(".", config.ChartPath), | ||||
| 		"--set=image.repository=" + registryImage, | ||||
| 		"--set=image.tag=" + imageTag, | ||||
| 	} | ||||
|  | ||||
| 	for _, value := range config.HelmValues { | ||||
| 		helmParams = append(helmParams, "--values", value) | ||||
| 	} | ||||
|  | ||||
| 	err = runner.RunExecutable(toolHelm, helmParams...) | ||||
| 	if err != nil { | ||||
| 		return nil, errors.Wrap(err, "failed to execute helm command") | ||||
| 	} | ||||
| 	return helmOutput.Bytes(), nil | ||||
| } | ||||
|  | ||||
| // buildRegistryPlusImageAndTagSeparately combines the registry together with the image name. Handles the tag separately. | ||||
| // Tag is defined by everything on the right hand side of the colon sign. This looks weird for sha container versions but works for helm. | ||||
| func buildRegistryPlusImageAndTagSeparately(config *gitopsUpdateDeploymentOptions) (string, string, error) { | ||||
| 	registryURL := config.ContainerRegistryURL | ||||
| 	url := "" | ||||
| 	if registryURL != "" { | ||||
| 		containerURL, err := docker.ContainerRegistryFromURL(registryURL) | ||||
| 		if err != nil { | ||||
| 			return "", "", errors.Wrap(err, "registry URL could not be extracted") | ||||
| 		} | ||||
| 		if containerURL != "" { | ||||
| 			containerURL = containerURL + "/" | ||||
| 		} | ||||
| 		url = containerURL | ||||
| 	} | ||||
|  | ||||
| 	imageNameTag := config.ContainerImageNameTag | ||||
| 	var imageName, imageTag string | ||||
| 	if strings.Contains(imageNameTag, ":") { | ||||
| 		split := strings.Split(imageNameTag, ":") | ||||
| 		if split[0] == "" { | ||||
| 			log.SetErrorCategory(log.ErrorConfiguration) | ||||
| 			return "", "", errors.New("image name could not be extracted") | ||||
| 		} | ||||
| 		if split[1] == "" { | ||||
| 			log.SetErrorCategory(log.ErrorConfiguration) | ||||
| 			return "", "", errors.New("tag could not be extracted") | ||||
| 		} | ||||
| 		imageName = split[0] | ||||
| 		imageTag = split[1] | ||||
| 		return url + imageName, imageTag, nil | ||||
| 	} | ||||
|  | ||||
| 	log.SetErrorCategory(log.ErrorConfiguration) | ||||
| 	return "", "", errors.New("image name and tag could not be extracted") | ||||
|  | ||||
| } | ||||
|  | ||||
| func commitAndPushChanges(config *gitopsUpdateDeploymentOptions, gitUtils iGitopsUpdateDeploymentGitUtils) (plumbing.Hash, error) { | ||||
| 	commit, err := gitUtils.CommitSingleFile(config.FilePath, config.CommitMessage, config.Username) | ||||
| 	commitMessage := config.CommitMessage | ||||
|  | ||||
| 	if commitMessage == "" { | ||||
| 		commitMessage = defaultCommitMessage(config) | ||||
| 	} | ||||
|  | ||||
| 	commit, err := gitUtils.CommitSingleFile(config.FilePath, commitMessage, config.Username) | ||||
| 	if err != nil { | ||||
| 		return [20]byte{}, errors.Wrap(err, "committing changes failed") | ||||
| 	} | ||||
| @@ -173,3 +349,9 @@ func commitAndPushChanges(config *gitopsUpdateDeploymentOptions, gitUtils iGitop | ||||
|  | ||||
| 	return commit, nil | ||||
| } | ||||
|  | ||||
| func defaultCommitMessage(config *gitopsUpdateDeploymentOptions) string { | ||||
| 	image, tag, _ := buildRegistryPlusImageAndTagSeparately(config) | ||||
| 	commitMessage := fmt.Sprintf("Updated %v to version %v", image, tag) | ||||
| 	return commitMessage | ||||
| } | ||||
|   | ||||
| @@ -14,15 +14,19 @@ import ( | ||||
| ) | ||||
|  | ||||
| type gitopsUpdateDeploymentOptions struct { | ||||
| 	BranchName            string `json:"branchName,omitempty"` | ||||
| 	CommitMessage         string `json:"commitMessage,omitempty"` | ||||
| 	ServerURL             string `json:"serverUrl,omitempty"` | ||||
| 	Username              string `json:"username,omitempty"` | ||||
| 	Password              string `json:"password,omitempty"` | ||||
| 	FilePath              string `json:"filePath,omitempty"` | ||||
| 	ContainerName         string `json:"containerName,omitempty"` | ||||
| 	ContainerRegistryURL  string `json:"containerRegistryUrl,omitempty"` | ||||
| 	ContainerImageNameTag string `json:"containerImageNameTag,omitempty"` | ||||
| 	BranchName            string   `json:"branchName,omitempty"` | ||||
| 	CommitMessage         string   `json:"commitMessage,omitempty"` | ||||
| 	ServerURL             string   `json:"serverUrl,omitempty"` | ||||
| 	Username              string   `json:"username,omitempty"` | ||||
| 	Password              string   `json:"password,omitempty"` | ||||
| 	FilePath              string   `json:"filePath,omitempty"` | ||||
| 	ContainerName         string   `json:"containerName,omitempty"` | ||||
| 	ContainerRegistryURL  string   `json:"containerRegistryUrl,omitempty"` | ||||
| 	ContainerImageNameTag string   `json:"containerImageNameTag,omitempty"` | ||||
| 	ChartPath             string   `json:"chartPath,omitempty"` | ||||
| 	HelmValues            []string `json:"helmValues,omitempty"` | ||||
| 	DeploymentName        string   `json:"deploymentName,omitempty"` | ||||
| 	Tool                  string   `json:"tool,omitempty"` | ||||
| } | ||||
|  | ||||
| // GitopsUpdateDeploymentCommand Updates Kubernetes Deployment Manifest in an Infrastructure Git Repository | ||||
| @@ -40,7 +44,9 @@ func GitopsUpdateDeploymentCommand() *cobra.Command { | ||||
|  | ||||
| It can for example be used for GitOps scenarios where the update of the manifests triggers an update of the corresponding deployment in Kubernetes. | ||||
|  | ||||
| As of today, it supports the update of deployment yaml files via kubectl patch. The container inside the yaml must be described within the following hierarchy: {"spec":{"template":{"spec":{"containers":[{...}]}}}}`, | ||||
| As of today, it supports the update of deployment yaml files via kubectl patch and update a whole helm template. | ||||
| For kubectl the container inside the yaml must be described within the following hierarchy: ` + "`" + `{"spec":{"template":{"spec":{"containers":[{...}]}}}}` + "`" + ` | ||||
| For helm the whole template is generated into a file and uploaded into the repository.`, | ||||
| 		PreRunE: func(cmd *cobra.Command, _ []string) error { | ||||
| 			startTime = time.Now() | ||||
| 			log.SetStepName(STEP_NAME) | ||||
| @@ -89,7 +95,7 @@ As of today, it supports the update of deployment yaml files via kubectl patch. | ||||
|  | ||||
| func addGitopsUpdateDeploymentFlags(cmd *cobra.Command, stepConfig *gitopsUpdateDeploymentOptions) { | ||||
| 	cmd.Flags().StringVar(&stepConfig.BranchName, "branchName", `master`, "The name of the branch where the changes should get pushed into.") | ||||
| 	cmd.Flags().StringVar(&stepConfig.CommitMessage, "commitMessage", `Updated {{containerName}} to version {{containerImage}}`, "The commit message of the commit that will be done to do the changes.") | ||||
| 	cmd.Flags().StringVar(&stepConfig.CommitMessage, "commitMessage", os.Getenv("PIPER_commitMessage"), "The commit message of the commit that will be done to do the changes.") | ||||
| 	cmd.Flags().StringVar(&stepConfig.ServerURL, "serverUrl", `https://github.com`, "GitHub server url to the repository.") | ||||
| 	cmd.Flags().StringVar(&stepConfig.Username, "username", os.Getenv("PIPER_username"), "User name for git authentication") | ||||
| 	cmd.Flags().StringVar(&stepConfig.Password, "password", os.Getenv("PIPER_password"), "Password/token for git authentication.") | ||||
| @@ -97,13 +103,19 @@ func addGitopsUpdateDeploymentFlags(cmd *cobra.Command, stepConfig *gitopsUpdate | ||||
| 	cmd.Flags().StringVar(&stepConfig.ContainerName, "containerName", os.Getenv("PIPER_containerName"), "The name of the container to update") | ||||
| 	cmd.Flags().StringVar(&stepConfig.ContainerRegistryURL, "containerRegistryUrl", os.Getenv("PIPER_containerRegistryUrl"), "http(s) url of the Container registry where the image is located") | ||||
| 	cmd.Flags().StringVar(&stepConfig.ContainerImageNameTag, "containerImageNameTag", os.Getenv("PIPER_containerImageNameTag"), "Container image name with version tag to annotate in the deployment configuration.") | ||||
| 	cmd.Flags().StringVar(&stepConfig.ChartPath, "chartPath", os.Getenv("PIPER_chartPath"), "Defines the chart path for deployments using helm.") | ||||
| 	cmd.Flags().StringSliceVar(&stepConfig.HelmValues, "helmValues", []string{}, "List of helm values as YAML file reference or URL (as per helm parameter description for `-f` / `--values`)") | ||||
| 	cmd.Flags().StringVar(&stepConfig.DeploymentName, "deploymentName", os.Getenv("PIPER_deploymentName"), "Defines the name of the deployment.") | ||||
| 	cmd.Flags().StringVar(&stepConfig.Tool, "tool", `kubectl`, "Defines the tool which should be used to update the deployment description.") | ||||
|  | ||||
| 	cmd.MarkFlagRequired("commitMessage") | ||||
| 	cmd.MarkFlagRequired("branchName") | ||||
| 	cmd.MarkFlagRequired("serverUrl") | ||||
| 	cmd.MarkFlagRequired("username") | ||||
| 	cmd.MarkFlagRequired("password") | ||||
| 	cmd.MarkFlagRequired("filePath") | ||||
| 	cmd.MarkFlagRequired("containerName") | ||||
| 	cmd.MarkFlagRequired("containerRegistryUrl") | ||||
| 	cmd.MarkFlagRequired("containerImageNameTag") | ||||
| 	cmd.MarkFlagRequired("tool") | ||||
| } | ||||
|  | ||||
| // retrieve step metadata | ||||
| @@ -121,7 +133,7 @@ func gitopsUpdateDeploymentMetadata() config.StepData { | ||||
| 						ResourceRef: []config.ResourceReference{}, | ||||
| 						Scope:       []string{"PARAMETERS", "STAGES", "STEPS"}, | ||||
| 						Type:        "string", | ||||
| 						Mandatory:   false, | ||||
| 						Mandatory:   true, | ||||
| 						Aliases:     []config.Alias{}, | ||||
| 					}, | ||||
| 					{ | ||||
| @@ -129,7 +141,7 @@ func gitopsUpdateDeploymentMetadata() config.StepData { | ||||
| 						ResourceRef: []config.ResourceReference{}, | ||||
| 						Scope:       []string{"PARAMETERS", "STAGES", "STEPS"}, | ||||
| 						Type:        "string", | ||||
| 						Mandatory:   true, | ||||
| 						Mandatory:   false, | ||||
| 						Aliases:     []config.Alias{}, | ||||
| 					}, | ||||
| 					{ | ||||
| @@ -181,7 +193,7 @@ func gitopsUpdateDeploymentMetadata() config.StepData { | ||||
| 						ResourceRef: []config.ResourceReference{}, | ||||
| 						Scope:       []string{"PARAMETERS", "STAGES", "STEPS"}, | ||||
| 						Type:        "string", | ||||
| 						Mandatory:   true, | ||||
| 						Mandatory:   false, | ||||
| 						Aliases:     []config.Alias{}, | ||||
| 					}, | ||||
| 					{ | ||||
| @@ -194,7 +206,7 @@ func gitopsUpdateDeploymentMetadata() config.StepData { | ||||
| 						}, | ||||
| 						Scope:     []string{"GENERAL", "PARAMETERS", "STAGES", "STEPS"}, | ||||
| 						Type:      "string", | ||||
| 						Mandatory: false, | ||||
| 						Mandatory: true, | ||||
| 						Aliases:   []config.Alias{{Name: "dockerRegistryUrl"}}, | ||||
| 					}, | ||||
| 					{ | ||||
| @@ -207,9 +219,41 @@ func gitopsUpdateDeploymentMetadata() config.StepData { | ||||
| 						}, | ||||
| 						Scope:     []string{"PARAMETERS", "STAGES", "STEPS"}, | ||||
| 						Type:      "string", | ||||
| 						Mandatory: false, | ||||
| 						Mandatory: true, | ||||
| 						Aliases:   []config.Alias{{Name: "image"}, {Name: "containerImage"}}, | ||||
| 					}, | ||||
| 					{ | ||||
| 						Name:        "chartPath", | ||||
| 						ResourceRef: []config.ResourceReference{}, | ||||
| 						Scope:       []string{"PARAMETERS", "STAGES", "STEPS"}, | ||||
| 						Type:        "string", | ||||
| 						Mandatory:   false, | ||||
| 						Aliases:     []config.Alias{{Name: "helmChartPath"}}, | ||||
| 					}, | ||||
| 					{ | ||||
| 						Name:        "helmValues", | ||||
| 						ResourceRef: []config.ResourceReference{}, | ||||
| 						Scope:       []string{"PARAMETERS", "STAGES", "STEPS"}, | ||||
| 						Type:        "[]string", | ||||
| 						Mandatory:   false, | ||||
| 						Aliases:     []config.Alias{}, | ||||
| 					}, | ||||
| 					{ | ||||
| 						Name:        "deploymentName", | ||||
| 						ResourceRef: []config.ResourceReference{}, | ||||
| 						Scope:       []string{"PARAMETERS", "STAGES", "STEPS"}, | ||||
| 						Type:        "string", | ||||
| 						Mandatory:   false, | ||||
| 						Aliases:     []config.Alias{{Name: "helmDeploymentName"}}, | ||||
| 					}, | ||||
| 					{ | ||||
| 						Name:        "tool", | ||||
| 						ResourceRef: []config.ResourceReference{}, | ||||
| 						Scope:       []string{"PARAMETERS", "STAGES", "STEPS"}, | ||||
| 						Type:        "string", | ||||
| 						Mandatory:   true, | ||||
| 						Aliases:     []config.Alias{}, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
|   | ||||
| @@ -42,75 +42,227 @@ func TestBuildRegistryPlusImage(t *testing.T) { | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func TestRunGitopsUpdateDeployment(t *testing.T) { | ||||
| func TestBuildRegistryPlusImageWithoutTag(t *testing.T) { | ||||
| 	t.Parallel() | ||||
| 	t.Run("successful run", func(t *testing.T) { | ||||
| 		var configuration = &gitopsUpdateDeploymentOptions{ | ||||
| 			BranchName:            "main", | ||||
| 			CommitMessage:         "This is the commit message", | ||||
| 			ServerURL:             "https://github.com", | ||||
| 			Username:              "admin3", | ||||
| 			Password:              "validAccessToken", | ||||
| 			FilePath:              "dir1/dir2/depl.yaml", | ||||
| 			ContainerName:         "myContainer", | ||||
| 	t.Run("build full image", func(t *testing.T) { | ||||
| 		registryImage, tag, err := buildRegistryPlusImageAndTagSeparately(&gitopsUpdateDeploymentOptions{ | ||||
| 			ContainerRegistryURL:  "https://myregistry.com/registry/containers", | ||||
| 			ContainerImageNameTag: "myFancyContainer:1337", | ||||
| 		} | ||||
| 		}) | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Equal(t, "myregistry.com/myFancyContainer", registryImage) | ||||
| 		assert.Equal(t, "1337", tag) | ||||
| 	}) | ||||
|  | ||||
| 		gitUtilsMock := &validGitUtilsMock{} | ||||
| 	t.Run("without registry", func(t *testing.T) { | ||||
| 		registryImage, tag, err := buildRegistryPlusImageAndTagSeparately(&gitopsUpdateDeploymentOptions{ | ||||
| 			ContainerRegistryURL:  "", | ||||
| 			ContainerImageNameTag: "myFancyContainer:1337", | ||||
| 		}) | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Equal(t, "myFancyContainer", registryImage) | ||||
| 		assert.Equal(t, "1337", tag) | ||||
| 	}) | ||||
| 	t.Run("without faulty URL", func(t *testing.T) { | ||||
| 		_, _, err := buildRegistryPlusImageAndTagSeparately(&gitopsUpdateDeploymentOptions{ | ||||
| 			ContainerRegistryURL:  "//myregistry.com/registry/containers", | ||||
| 			ContainerImageNameTag: "myFancyContainer:1337", | ||||
| 		}) | ||||
| 		assert.Error(t, err) | ||||
| 		assert.EqualError(t, err, "registry URL could not be extracted: invalid registry url") | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| 		runnerMock := gitOpsExecRunnerMock{} | ||||
| 		var c gitopsUpdateDeploymentExecRunner = &runnerMock | ||||
| func TestRunGitopsUpdateDeploymentWithKubectl(t *testing.T) { | ||||
| 	var validConfiguration = &gitopsUpdateDeploymentOptions{ | ||||
| 		BranchName:            "main", | ||||
| 		CommitMessage:         "This is the commit message", | ||||
| 		ServerURL:             "https://github.com", | ||||
| 		Username:              "admin3", | ||||
| 		Password:              "validAccessToken", | ||||
| 		FilePath:              "dir1/dir2/depl.yaml", | ||||
| 		ContainerName:         "myContainer", | ||||
| 		ContainerRegistryURL:  "https://myregistry.com/registry/containers", | ||||
| 		ContainerImageNameTag: "myFancyContainer:1337", | ||||
| 		Tool:                  "kubectl", | ||||
| 	} | ||||
|  | ||||
| 		err := runGitopsUpdateDeployment(configuration, c, gitUtilsMock, piperutils.Files{}) | ||||
| 	t.Parallel() | ||||
| 	t.Run("successful run", func(t *testing.T) { | ||||
| 		gitUtilsMock := &gitUtilsMock{} | ||||
| 		runnerMock := &gitOpsExecRunnerMock{} | ||||
|  | ||||
| 		err := runGitopsUpdateDeployment(validConfiguration, runnerMock, gitUtilsMock, &filesMock{}) | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Equal(t, validConfiguration.BranchName, gitUtilsMock.changedBranch) | ||||
| 		assert.Equal(t, expectedYaml, gitUtilsMock.savedFile) | ||||
| 		assert.Equal(t, "This is the commit message", gitUtilsMock.commitMessage) | ||||
| 		assert.Equal(t, "kubectl", runnerMock.executable) | ||||
| 		assert.Equal(t, "patch", runnerMock.params[0]) | ||||
| 		assert.Equal(t, "--local", runnerMock.params[1]) | ||||
| 		assert.Equal(t, "--output=yaml", runnerMock.params[2]) | ||||
| 		assert.Equal(t, `--patch={"spec":{"template":{"spec":{"containers":[{"name":"myContainer","image":"myregistry.com/myFancyContainer:1337"}]}}}}`, runnerMock.params[3]) | ||||
| 		assert.True(t, strings.Contains(runnerMock.params[4], filepath.Join("dir1/dir2/depl.yaml"))) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("default commit message", func(t *testing.T) { | ||||
| 		var configuration = *validConfiguration | ||||
| 		configuration.CommitMessage = "" | ||||
|  | ||||
| 		gitUtilsMock := &gitUtilsMock{} | ||||
| 		runnerMock := &gitOpsExecRunnerMock{} | ||||
|  | ||||
| 		err := runGitopsUpdateDeployment(&configuration, runnerMock, gitUtilsMock, &filesMock{}) | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Equal(t, validConfiguration.BranchName, gitUtilsMock.changedBranch) | ||||
| 		assert.Equal(t, expectedYaml, gitUtilsMock.savedFile) | ||||
| 		assert.Equal(t, "Updated myregistry.com/myFancyContainer to version 1337", gitUtilsMock.commitMessage) | ||||
| 		assert.Equal(t, "kubectl", runnerMock.executable) | ||||
| 		assert.Equal(t, "patch", runnerMock.params[0]) | ||||
| 		assert.Equal(t, "--local", runnerMock.params[1]) | ||||
| 		assert.Equal(t, "--output=yaml", runnerMock.params[2]) | ||||
| 		assert.Equal(t, `--patch={"spec":{"template":{"spec":{"containers":[{"name":"myContainer","image":"myregistry.com/myFancyContainer:1337"}]}}}}`, runnerMock.params[3]) | ||||
| 		assert.True(t, strings.Contains(runnerMock.params[4], filepath.Join("dir1/dir2/depl.yaml"))) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("ChartPath not used for kubectl", func(t *testing.T) { | ||||
| 		var configuration = *validConfiguration | ||||
| 		configuration.ChartPath = "chartPath" | ||||
|  | ||||
| 		gitUtilsMock := &gitUtilsMock{} | ||||
| 		runnerMock := &gitOpsExecRunnerMock{} | ||||
|  | ||||
| 		err := runGitopsUpdateDeployment(&configuration, runnerMock, gitUtilsMock, &filesMock{}) | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Equal(t, configuration.BranchName, gitUtilsMock.changedBranch) | ||||
| 		assert.Equal(t, expectedYaml, gitUtilsMock.savedFile) | ||||
| 		assert.Equal(t, "kubectl", runnerMock.executable) | ||||
| 		assert.Equal(t, "patch", runnerMock.kubectlParams[0]) | ||||
| 		assert.Equal(t, "--local", runnerMock.kubectlParams[1]) | ||||
| 		assert.Equal(t, "--output=yaml", runnerMock.kubectlParams[2]) | ||||
| 		assert.Equal(t, `--patch={"spec":{"template":{"spec":{"containers":[{"name":"myContainer","image":"myregistry.com/myFancyContainer:1337"}]}}}}`, runnerMock.kubectlParams[3]) | ||||
| 		assert.True(t, strings.Contains(runnerMock.kubectlParams[4], filepath.Join("dir1/dir2/depl.yaml"))) | ||||
| 		assert.Equal(t, "patch", runnerMock.params[0]) | ||||
| 		assert.Equal(t, "--local", runnerMock.params[1]) | ||||
| 		assert.Equal(t, "--output=yaml", runnerMock.params[2]) | ||||
| 		assert.Equal(t, `--patch={"spec":{"template":{"spec":{"containers":[{"name":"myContainer","image":"myregistry.com/myFancyContainer:1337"}]}}}}`, runnerMock.params[3]) | ||||
| 		assert.True(t, strings.Contains(runnerMock.params[4], filepath.Join("dir1/dir2/depl.yaml"))) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("HelmValues not used for kubectl", func(t *testing.T) { | ||||
| 		var configuration = *validConfiguration | ||||
| 		configuration.HelmValues = []string{"HelmValues"} | ||||
|  | ||||
| 		gitUtilsMock := &gitUtilsMock{} | ||||
| 		runnerMock := &gitOpsExecRunnerMock{} | ||||
|  | ||||
| 		err := runGitopsUpdateDeployment(&configuration, runnerMock, gitUtilsMock, &filesMock{}) | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Equal(t, configuration.BranchName, gitUtilsMock.changedBranch) | ||||
| 		assert.Equal(t, expectedYaml, gitUtilsMock.savedFile) | ||||
| 		assert.Equal(t, "kubectl", runnerMock.executable) | ||||
| 		assert.Equal(t, "patch", runnerMock.params[0]) | ||||
| 		assert.Equal(t, "--local", runnerMock.params[1]) | ||||
| 		assert.Equal(t, "--output=yaml", runnerMock.params[2]) | ||||
| 		assert.Equal(t, `--patch={"spec":{"template":{"spec":{"containers":[{"name":"myContainer","image":"myregistry.com/myFancyContainer:1337"}]}}}}`, runnerMock.params[3]) | ||||
| 		assert.True(t, strings.Contains(runnerMock.params[4], filepath.Join("dir1/dir2/depl.yaml"))) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("DeploymentName not used for kubectl", func(t *testing.T) { | ||||
| 		var configuration = *validConfiguration | ||||
| 		configuration.DeploymentName = "DeploymentName" | ||||
|  | ||||
| 		gitUtilsMock := &gitUtilsMock{} | ||||
| 		runnerMock := &gitOpsExecRunnerMock{} | ||||
|  | ||||
| 		err := runGitopsUpdateDeployment(&configuration, runnerMock, gitUtilsMock, &filesMock{}) | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Equal(t, configuration.BranchName, gitUtilsMock.changedBranch) | ||||
| 		assert.Equal(t, expectedYaml, gitUtilsMock.savedFile) | ||||
| 		assert.Equal(t, "kubectl", runnerMock.executable) | ||||
| 		assert.Equal(t, "patch", runnerMock.params[0]) | ||||
| 		assert.Equal(t, "--local", runnerMock.params[1]) | ||||
| 		assert.Equal(t, "--output=yaml", runnerMock.params[2]) | ||||
| 		assert.Equal(t, `--patch={"spec":{"template":{"spec":{"containers":[{"name":"myContainer","image":"myregistry.com/myFancyContainer:1337"}]}}}}`, runnerMock.params[3]) | ||||
| 		assert.True(t, strings.Contains(runnerMock.params[4], filepath.Join("dir1/dir2/depl.yaml"))) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("missing ContainerName", func(t *testing.T) { | ||||
| 		var configuration = *validConfiguration | ||||
| 		configuration.ContainerName = "" | ||||
|  | ||||
| 		gitUtilsMock := &gitUtilsMock{} | ||||
| 		runnerMock := &gitOpsExecRunnerMock{} | ||||
|  | ||||
| 		err := runGitopsUpdateDeployment(&configuration, runnerMock, gitUtilsMock, &filesMock{}) | ||||
| 		assert.Error(t, err) | ||||
| 		assert.EqualError(t, err, "missing required fields for kubectl: the following parameters are necessary for kubectl: [containerName]") | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("error on kubectl execution", func(t *testing.T) { | ||||
| 		runner := &gitOpsExecRunnerMock{failOnRunExecutable: true} | ||||
|  | ||||
| 		err := runGitopsUpdateDeployment(validConfiguration, runner, &gitUtilsMock{}, &filesMock{}) | ||||
| 		assert.Error(t, err) | ||||
| 		assert.EqualError(t, err, "error on kubectl execution: failed to apply kubectl command: failed to apply kubectl command: error happened") | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("invalid URL", func(t *testing.T) { | ||||
| 		var configuration = &gitopsUpdateDeploymentOptions{ | ||||
| 			BranchName:            "main", | ||||
| 			CommitMessage:         "This is the commit message", | ||||
| 			ServerURL:             "https://github.com", | ||||
| 			Username:              "admin3", | ||||
| 			Password:              "validAccessToken", | ||||
| 			FilePath:              "dir1/dir2/depl.yaml", | ||||
| 			ContainerName:         "myContainer", | ||||
| 			ContainerRegistryURL:  "//myregistry.com/registry/containers", | ||||
| 			ContainerImageNameTag: "myFancyContainer:1337", | ||||
| 		} | ||||
| 		var configuration = *validConfiguration | ||||
| 		configuration.ContainerRegistryURL = "//myregistry.com/registry/containers" | ||||
|  | ||||
| 		gitUtilsMock := &validGitUtilsMock{} | ||||
|  | ||||
| 		err := runGitopsUpdateDeployment(configuration, nil, gitUtilsMock, piperutils.Files{}) | ||||
| 		assert.EqualError(t, err, "failed to apply kubectl command: registry URL could not be extracted: invalid registry url") | ||||
| 		err := runGitopsUpdateDeployment(&configuration, &gitOpsExecRunnerMock{}, &gitUtilsMock{}, &filesMock{}) | ||||
| 		assert.EqualError(t, err, "error on kubectl execution: failed to apply kubectl command: registry URL could not be extracted: invalid registry url") | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("error on plane clone", func(t *testing.T) { | ||||
| 		var configuration = &gitopsUpdateDeploymentOptions{ | ||||
| 			BranchName:            "main", | ||||
| 			CommitMessage:         "This is the commit message", | ||||
| 			ServerURL:             "https://github.com", | ||||
| 			Username:              "admin3", | ||||
| 			Password:              "validAccessToken", | ||||
| 			FilePath:              "dir1/dir2/depl.yaml", | ||||
| 			ContainerName:         "myContainer", | ||||
| 			ContainerRegistryURL:  "https://myregistry.com/registry/containers", | ||||
| 			ContainerImageNameTag: "myFancyContainer:1337", | ||||
| 		} | ||||
| 	t.Run("error on plain clone", func(t *testing.T) { | ||||
| 		gitUtils := &gitUtilsMock{failOnClone: true} | ||||
|  | ||||
| 		err := runGitopsUpdateDeployment(configuration, nil, &gitUtilsMockErrorClone{}, piperutils.Files{}) | ||||
| 		assert.EqualError(t, err, "failed to plain clone repository: error on clone") | ||||
| 		err := runGitopsUpdateDeployment(validConfiguration, &gitOpsExecRunnerMock{}, gitUtils, &filesMock{}) | ||||
| 		assert.EqualError(t, err, "repository could not get prepared: failed to plain clone repository: error on clone") | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("error on change branch", func(t *testing.T) { | ||||
| 		gitUtils := &gitUtilsMock{failOnChangeBranch: true} | ||||
|  | ||||
| 		err := runGitopsUpdateDeployment(validConfiguration, &gitOpsExecRunnerMock{}, gitUtils, &filesMock{}) | ||||
| 		assert.EqualError(t, err, "repository could not get prepared: failed to change branch: error on change branch") | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("error on commit changes", func(t *testing.T) { | ||||
| 		gitUtils := &gitUtilsMock{failOnCommit: true} | ||||
|  | ||||
| 		err := runGitopsUpdateDeployment(validConfiguration, &gitOpsExecRunnerMock{}, gitUtils, &filesMock{}) | ||||
| 		assert.EqualError(t, err, "failed to commit and push changes: committing changes failed: error on commit") | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("error on push commits", func(t *testing.T) { | ||||
| 		gitUtils := &gitUtilsMock{failOnPush: true} | ||||
|  | ||||
| 		err := runGitopsUpdateDeployment(validConfiguration, &gitOpsExecRunnerMock{}, gitUtils, &filesMock{}) | ||||
| 		assert.EqualError(t, err, "failed to commit and push changes: pushing changes failed: error on push") | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("error on temp dir creation", func(t *testing.T) { | ||||
| 		fileUtils := &filesMock{failOnCreation: true} | ||||
|  | ||||
| 		err := runGitopsUpdateDeployment(validConfiguration, &gitOpsExecRunnerMock{}, &gitUtilsMock{}, fileUtils) | ||||
| 		assert.EqualError(t, err, "failed to create temporary directory: error appeared") | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("error on file write", func(t *testing.T) { | ||||
| 		fileUtils := &filesMock{failOnWrite: true} | ||||
|  | ||||
| 		err := runGitopsUpdateDeployment(validConfiguration, &gitOpsExecRunnerMock{}, &gitUtilsMock{}, fileUtils) | ||||
| 		assert.EqualError(t, err, "failed to write file: error appeared") | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("error on temp dir deletion", func(t *testing.T) { | ||||
| 		fileUtils := &filesMock{failOnDeletion: true} | ||||
|  | ||||
| 		err := runGitopsUpdateDeployment(validConfiguration, &gitOpsExecRunnerMock{}, &gitUtilsMock{}, fileUtils) | ||||
| 		assert.NoError(t, err) | ||||
| 		_ = piperutils.Files{}.RemoveAll(fileUtils.path) | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func TestRunGitopsUpdateDeploymentWithInvalid(t *testing.T) { | ||||
| 	t.Run("invalid deploy tool is not supported", func(t *testing.T) { | ||||
| 		var configuration = &gitopsUpdateDeploymentOptions{ | ||||
| 			BranchName:            "main", | ||||
| 			CommitMessage:         "This is the commit message", | ||||
| @@ -119,19 +271,237 @@ func TestRunGitopsUpdateDeployment(t *testing.T) { | ||||
| 			Password:              "validAccessToken", | ||||
| 			FilePath:              "dir1/dir2/depl.yaml", | ||||
| 			ContainerName:         "myContainer", | ||||
| 			ContainerRegistryURL:  "https://myregistry.com/registry/containers", | ||||
| 			ContainerImageNameTag: "myFancyContainer:1337", | ||||
| 			ContainerRegistryURL:  "https://myregistry.com", | ||||
| 			ContainerImageNameTag: "registry/containers/myFancyContainer:1337", | ||||
| 			Tool:                  "invalid", | ||||
| 			ChartPath:             "./helm", | ||||
| 			DeploymentName:        "myFancyDeployment", | ||||
| 			HelmValues:            []string{"./helm/additionalValues.yaml"}, | ||||
| 		} | ||||
|  | ||||
| 		err := runGitopsUpdateDeployment(configuration, nil, &gitopsUpdateDeploymentGitUtils{}, filesMockErrorTempDirCreation{}) | ||||
| 		err := runGitopsUpdateDeployment(configuration, &gitOpsExecRunnerMock{}, &gitUtilsMock{}, &filesMock{}) | ||||
| 		assert.Error(t, err) | ||||
| 		assert.EqualError(t, err, "tool invalid is not supported") | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func TestRunGitopsUpdateDeploymentWithHelm(t *testing.T) { | ||||
| 	var validConfiguration = &gitopsUpdateDeploymentOptions{ | ||||
| 		BranchName:            "main", | ||||
| 		CommitMessage:         "This is the commit message", | ||||
| 		ServerURL:             "https://github.com", | ||||
| 		Username:              "admin3", | ||||
| 		Password:              "validAccessToken", | ||||
| 		FilePath:              "dir1/dir2/depl.yaml", | ||||
| 		ContainerRegistryURL:  "https://myregistry.com", | ||||
| 		ContainerImageNameTag: "registry/containers/myFancyContainer:1337", | ||||
| 		Tool:                  "helm", | ||||
| 		ChartPath:             "./helm", | ||||
| 		DeploymentName:        "myFancyDeployment", | ||||
| 		HelmValues:            []string{"./helm/additionalValues.yaml"}, | ||||
| 	} | ||||
|  | ||||
| 	t.Parallel() | ||||
| 	t.Run("successful run", func(t *testing.T) { | ||||
| 		gitUtilsMock := &gitUtilsMock{} | ||||
| 		runnerMock := &gitOpsExecRunnerMock{} | ||||
|  | ||||
| 		err := runGitopsUpdateDeployment(validConfiguration, runnerMock, gitUtilsMock, &filesMock{}) | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Equal(t, validConfiguration.BranchName, gitUtilsMock.changedBranch) | ||||
| 		assert.Equal(t, expectedYaml, gitUtilsMock.savedFile) | ||||
| 		assert.Equal(t, "This is the commit message", gitUtilsMock.commitMessage) | ||||
| 		assert.Equal(t, "helm", runnerMock.executable) | ||||
| 		assert.Equal(t, "template", runnerMock.params[0]) | ||||
| 		assert.Equal(t, "myFancyDeployment", runnerMock.params[1]) | ||||
| 		assert.Equal(t, filepath.Join(".", "helm"), runnerMock.params[2]) | ||||
| 		assert.Equal(t, "--set=image.repository=myregistry.com/registry/containers/myFancyContainer", runnerMock.params[3]) | ||||
| 		assert.Equal(t, "--set=image.tag=1337", runnerMock.params[4]) | ||||
| 		assert.Equal(t, "--values", runnerMock.params[5]) | ||||
| 		assert.Equal(t, "./helm/additionalValues.yaml", runnerMock.params[6]) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("default commit message", func(t *testing.T) { | ||||
| 		var configuration = *validConfiguration | ||||
| 		configuration.CommitMessage = "" | ||||
|  | ||||
| 		gitUtilsMock := &gitUtilsMock{} | ||||
| 		runnerMock := &gitOpsExecRunnerMock{} | ||||
|  | ||||
| 		err := runGitopsUpdateDeployment(&configuration, runnerMock, gitUtilsMock, &filesMock{}) | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Equal(t, configuration.BranchName, gitUtilsMock.changedBranch) | ||||
| 		assert.Equal(t, expectedYaml, gitUtilsMock.savedFile) | ||||
| 		assert.Equal(t, "Updated myregistry.com/registry/containers/myFancyContainer to version 1337", gitUtilsMock.commitMessage) | ||||
| 		assert.Equal(t, "helm", runnerMock.executable) | ||||
| 		assert.Equal(t, "template", runnerMock.params[0]) | ||||
| 		assert.Equal(t, "myFancyDeployment", runnerMock.params[1]) | ||||
| 		assert.Equal(t, filepath.Join(".", "helm"), runnerMock.params[2]) | ||||
| 		assert.Equal(t, "--set=image.repository=myregistry.com/registry/containers/myFancyContainer", runnerMock.params[3]) | ||||
| 		assert.Equal(t, "--set=image.tag=1337", runnerMock.params[4]) | ||||
| 		assert.Equal(t, "--values", runnerMock.params[5]) | ||||
| 		assert.Equal(t, "./helm/additionalValues.yaml", runnerMock.params[6]) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("ContainerName not used for helm", func(t *testing.T) { | ||||
| 		var configuration = *validConfiguration | ||||
| 		configuration.ContainerName = "containerName" | ||||
|  | ||||
| 		gitUtilsMock := &gitUtilsMock{} | ||||
| 		runnerMock := &gitOpsExecRunnerMock{} | ||||
|  | ||||
| 		err := runGitopsUpdateDeployment(&configuration, runnerMock, gitUtilsMock, &filesMock{}) | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Equal(t, configuration.BranchName, gitUtilsMock.changedBranch) | ||||
| 		assert.Equal(t, expectedYaml, gitUtilsMock.savedFile) | ||||
| 		assert.Equal(t, "helm", runnerMock.executable) | ||||
| 		assert.Equal(t, "template", runnerMock.params[0]) | ||||
| 		assert.Equal(t, "myFancyDeployment", runnerMock.params[1]) | ||||
| 		assert.Equal(t, filepath.Join(".", "helm"), runnerMock.params[2]) | ||||
| 		assert.Equal(t, "--set=image.repository=myregistry.com/registry/containers/myFancyContainer", runnerMock.params[3]) | ||||
| 		assert.Equal(t, "--set=image.tag=1337", runnerMock.params[4]) | ||||
| 		assert.Equal(t, "--values", runnerMock.params[5]) | ||||
| 		assert.Equal(t, "./helm/additionalValues.yaml", runnerMock.params[6]) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("HelmValues is optional", func(t *testing.T) { | ||||
| 		var configuration = *validConfiguration | ||||
| 		configuration.HelmValues = nil | ||||
|  | ||||
| 		gitUtilsMock := &gitUtilsMock{} | ||||
| 		runnerMock := &gitOpsExecRunnerMock{} | ||||
|  | ||||
| 		err := runGitopsUpdateDeployment(&configuration, runnerMock, gitUtilsMock, &filesMock{}) | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Equal(t, configuration.BranchName, gitUtilsMock.changedBranch) | ||||
| 		assert.Equal(t, expectedYaml, gitUtilsMock.savedFile) | ||||
| 		assert.Equal(t, "helm", runnerMock.executable) | ||||
| 		assert.Equal(t, "template", runnerMock.params[0]) | ||||
| 		assert.Equal(t, "myFancyDeployment", runnerMock.params[1]) | ||||
| 		assert.Equal(t, filepath.Join(".", "helm"), runnerMock.params[2]) | ||||
| 		assert.Equal(t, "--set=image.repository=myregistry.com/registry/containers/myFancyContainer", runnerMock.params[3]) | ||||
| 		assert.Equal(t, "--set=image.tag=1337", runnerMock.params[4]) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("erroneous URL", func(t *testing.T) { | ||||
| 		var configuration = *validConfiguration | ||||
| 		configuration.ContainerRegistryURL = "://myregistry.com" | ||||
|  | ||||
| 		err := runGitopsUpdateDeployment(&configuration, &gitOpsExecRunnerMock{}, &gitUtilsMock{}, &filesMock{}) | ||||
| 		assert.Error(t, err) | ||||
| 		assert.EqualError(t, err, `failed to apply helm command: failed to extract registry URL, image name, and image tag: registry URL could not be extracted: invalid registry url: parse "://myregistry.com": missing protocol scheme`) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("missing ChartPath", func(t *testing.T) { | ||||
| 		var configuration = *validConfiguration | ||||
| 		configuration.ChartPath = "" | ||||
|  | ||||
| 		err := runGitopsUpdateDeployment(&configuration, &gitOpsExecRunnerMock{}, &gitUtilsMock{}, &filesMock{}) | ||||
| 		assert.Error(t, err) | ||||
| 		assert.EqualError(t, err, "missing required fields for helm: the following parameters are necessary for helm: [chartPath]") | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("missing DeploymentName", func(t *testing.T) { | ||||
| 		var configuration = *validConfiguration | ||||
| 		configuration.DeploymentName = "" | ||||
|  | ||||
| 		err := runGitopsUpdateDeployment(&configuration, &gitOpsExecRunnerMock{}, &gitUtilsMock{}, &filesMock{}) | ||||
| 		assert.Error(t, err) | ||||
| 		assert.EqualError(t, err, "missing required fields for helm: the following parameters are necessary for helm: [deploymentName]") | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("missing DeploymentName and ChartPath", func(t *testing.T) { | ||||
| 		var configuration = *validConfiguration | ||||
| 		configuration.DeploymentName = "" | ||||
| 		configuration.ChartPath = "" | ||||
|  | ||||
| 		err := runGitopsUpdateDeployment(&configuration, &gitOpsExecRunnerMock{}, &gitUtilsMock{}, &filesMock{}) | ||||
| 		assert.Error(t, err) | ||||
| 		assert.EqualError(t, err, "missing required fields for helm: the following parameters are necessary for helm: [chartPath deploymentName]") | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("erroneous tag", func(t *testing.T) { | ||||
| 		var configuration = *validConfiguration | ||||
| 		configuration.ContainerImageNameTag = "registry/containers/myFancyContainer:" | ||||
|  | ||||
| 		err := runGitopsUpdateDeployment(&configuration, &gitOpsExecRunnerMock{}, &gitUtilsMock{}, &filesMock{}) | ||||
| 		assert.Error(t, err) | ||||
| 		assert.EqualError(t, err, "failed to apply helm command: failed to extract registry URL, image name, and image tag: tag could not be extracted") | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("erroneous image name", func(t *testing.T) { | ||||
| 		var configuration = *validConfiguration | ||||
| 		configuration.ContainerImageNameTag = ":1.0.1" | ||||
|  | ||||
| 		err := runGitopsUpdateDeployment(&configuration, &gitOpsExecRunnerMock{}, &gitUtilsMock{}, &filesMock{}) | ||||
| 		assert.Error(t, err) | ||||
| 		assert.EqualError(t, err, "failed to apply helm command: failed to extract registry URL, image name, and image tag: image name could not be extracted") | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("error on helm execution", func(t *testing.T) { | ||||
| 		runner := &gitOpsExecRunnerMock{failOnRunExecutable: true} | ||||
|  | ||||
| 		err := runGitopsUpdateDeployment(validConfiguration, runner, &gitUtilsMock{}, &filesMock{}) | ||||
| 		assert.Error(t, err) | ||||
| 		assert.EqualError(t, err, "failed to apply helm command: failed to execute helm command: error happened") | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("error on plain clone", func(t *testing.T) { | ||||
| 		gitUtils := &gitUtilsMock{failOnClone: true} | ||||
|  | ||||
| 		err := runGitopsUpdateDeployment(validConfiguration, &gitOpsExecRunnerMock{}, gitUtils, &filesMock{}) | ||||
| 		assert.EqualError(t, err, "repository could not get prepared: failed to plain clone repository: error on clone") | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("error on change branch", func(t *testing.T) { | ||||
| 		gitUtils := &gitUtilsMock{failOnChangeBranch: true} | ||||
|  | ||||
| 		err := runGitopsUpdateDeployment(validConfiguration, &gitOpsExecRunnerMock{}, gitUtils, &filesMock{}) | ||||
| 		assert.EqualError(t, err, "repository could not get prepared: failed to change branch: error on change branch") | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("error on commit changes", func(t *testing.T) { | ||||
| 		gitUtils := &gitUtilsMock{failOnCommit: true} | ||||
|  | ||||
| 		err := runGitopsUpdateDeployment(validConfiguration, &gitOpsExecRunnerMock{}, gitUtils, &filesMock{}) | ||||
| 		assert.EqualError(t, err, "failed to commit and push changes: committing changes failed: error on commit") | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("error on push commits", func(t *testing.T) { | ||||
| 		gitUtils := &gitUtilsMock{failOnPush: true} | ||||
|  | ||||
| 		err := runGitopsUpdateDeployment(validConfiguration, &gitOpsExecRunnerMock{}, gitUtils, &filesMock{}) | ||||
| 		assert.EqualError(t, err, "failed to commit and push changes: pushing changes failed: error on push") | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("error on temp dir creation", func(t *testing.T) { | ||||
| 		fileUtils := &filesMock{failOnCreation: true} | ||||
|  | ||||
| 		err := runGitopsUpdateDeployment(validConfiguration, &gitOpsExecRunnerMock{}, &gitUtilsMock{}, fileUtils) | ||||
| 		assert.EqualError(t, err, "failed to create temporary directory: error appeared") | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("error on file write", func(t *testing.T) { | ||||
| 		fileUtils := &filesMock{failOnWrite: true} | ||||
|  | ||||
| 		err := runGitopsUpdateDeployment(validConfiguration, &gitOpsExecRunnerMock{}, &gitUtilsMock{}, fileUtils) | ||||
| 		assert.EqualError(t, err, "failed to write file: error appeared") | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("error on temp dir deletion", func(t *testing.T) { | ||||
| 		fileUtils := &filesMock{failOnDeletion: true} | ||||
|  | ||||
| 		err := runGitopsUpdateDeployment(validConfiguration, &gitOpsExecRunnerMock{}, &gitUtilsMock{}, fileUtils) | ||||
| 		assert.NoError(t, err) | ||||
| 		_ = piperutils.Files{}.RemoveAll(fileUtils.path) | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| type gitOpsExecRunnerMock struct { | ||||
| 	out           io.Writer | ||||
| 	kubectlParams []string | ||||
| 	executable    string | ||||
| 	out                 io.Writer | ||||
| 	params              []string | ||||
| 	executable          string | ||||
| 	failOnRunExecutable bool | ||||
| } | ||||
|  | ||||
| func (e *gitOpsExecRunnerMock) Stdout(out io.Writer) { | ||||
| @@ -143,74 +513,95 @@ func (gitOpsExecRunnerMock) Stderr(io.Writer) { | ||||
| } | ||||
|  | ||||
| func (e *gitOpsExecRunnerMock) RunExecutable(executable string, params ...string) error { | ||||
| 	if e.failOnRunExecutable { | ||||
| 		return errors.New("error happened") | ||||
| 	} | ||||
| 	e.executable = executable | ||||
| 	e.kubectlParams = params | ||||
| 	e.params = params | ||||
| 	_, err := e.out.Write([]byte(expectedYaml)) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| type filesMockErrorTempDirCreation struct{} | ||||
|  | ||||
| func (c filesMockErrorTempDirCreation) FileWrite(string, []byte, os.FileMode) error { | ||||
| 	panic("implement me") | ||||
| type filesMock struct { | ||||
| 	failOnCreation bool | ||||
| 	failOnDeletion bool | ||||
| 	failOnWrite    bool | ||||
| 	path           string | ||||
| } | ||||
|  | ||||
| func (filesMockErrorTempDirCreation) TempDir(string, string) (name string, err error) { | ||||
| 	return "", errors.New("error appeared") | ||||
| func (f filesMock) FileWrite(path string, content []byte, perm os.FileMode) error { | ||||
| 	if f.failOnWrite { | ||||
| 		return errors.New("error appeared") | ||||
| 	} | ||||
| 	return piperutils.Files{}.FileWrite(path, content, perm) | ||||
| } | ||||
|  | ||||
| func (filesMockErrorTempDirCreation) RemoveAll(string) error { | ||||
| 	panic("implement me") | ||||
| func (f filesMock) TempDir(dir string, pattern string) (name string, err error) { | ||||
| 	if f.failOnCreation { | ||||
| 		return "", errors.New("error appeared") | ||||
| 	} | ||||
| 	return piperutils.Files{}.TempDir(dir, pattern) | ||||
| } | ||||
|  | ||||
| type gitUtilsMockErrorClone struct{} | ||||
|  | ||||
| func (gitUtilsMockErrorClone) CommitSingleFile(string, string, string) (plumbing.Hash, error) { | ||||
| 	panic("implement me") | ||||
| func (f *filesMock) RemoveAll(path string) error { | ||||
| 	if f.failOnDeletion { | ||||
| 		f.path = path | ||||
| 		return errors.New("error appeared") | ||||
| 	} | ||||
| 	return piperutils.Files{}.RemoveAll(path) | ||||
| } | ||||
|  | ||||
| func (gitUtilsMockErrorClone) PushChangesToRepository(string, string) error { | ||||
| 	panic("implement me") | ||||
| type gitUtilsMock struct { | ||||
| 	savedFile          string | ||||
| 	changedBranch      string | ||||
| 	commitMessage      string | ||||
| 	temporaryDirectory string | ||||
| 	failOnClone        bool | ||||
| 	failOnChangeBranch bool | ||||
| 	failOnCommit       bool | ||||
| 	failOnPush         bool | ||||
| } | ||||
|  | ||||
| func (gitUtilsMockErrorClone) PlainClone(string, string, string, string) error { | ||||
| 	return errors.New("error on clone") | ||||
| } | ||||
|  | ||||
| func (gitUtilsMockErrorClone) ChangeBranch(string) error { | ||||
| 	panic("implement me") | ||||
| } | ||||
|  | ||||
| func (gitUtilsMockErrorClone) GetWorktree() (*git.Worktree, error) { | ||||
| 	panic("implement me") | ||||
| } | ||||
|  | ||||
| type validGitUtilsMock struct { | ||||
| 	savedFile     string | ||||
| 	changedBranch string | ||||
| } | ||||
|  | ||||
| func (validGitUtilsMock) GetWorktree() (*git.Worktree, error) { | ||||
| func (gitUtilsMock) GetWorktree() (*git.Worktree, error) { | ||||
| 	return nil, nil | ||||
| } | ||||
|  | ||||
| func (v *validGitUtilsMock) ChangeBranch(branchName string) error { | ||||
| func (v *gitUtilsMock) ChangeBranch(branchName string) error { | ||||
| 	if v.failOnChangeBranch { | ||||
| 		return errors.New("error on change branch") | ||||
| 	} | ||||
| 	v.changedBranch = branchName | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (v *validGitUtilsMock) CommitSingleFile(string, string, string) (plumbing.Hash, error) { | ||||
| 	matches, _ := piperutils.Files{}.Glob("*/dir1/dir2/depl.yaml") | ||||
| func (v *gitUtilsMock) CommitSingleFile(_ string, commitMessage string, _ string) (plumbing.Hash, error) { | ||||
| 	if v.failOnCommit { | ||||
| 		return [20]byte{}, errors.New("error on commit") | ||||
| 	} | ||||
|  | ||||
| 	v.commitMessage = commitMessage | ||||
|  | ||||
| 	matches, _ := piperutils.Files{}.Glob(v.temporaryDirectory + "/dir1/dir2/depl.yaml") | ||||
| 	if len(matches) < 1 { | ||||
| 		return [20]byte{}, errors.New("could not find file") | ||||
| 	} | ||||
| 	fileRead, _ := piperutils.Files{}.FileRead(matches[0]) | ||||
| 	v.savedFile = string(fileRead) | ||||
| 	return [20]byte{123}, nil | ||||
| } | ||||
|  | ||||
| func (validGitUtilsMock) PushChangesToRepository(string, string) error { | ||||
| func (v gitUtilsMock) PushChangesToRepository(string, string) error { | ||||
| 	if v.failOnPush { | ||||
| 		return errors.New("error on push") | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (validGitUtilsMock) PlainClone(_, _, _, directory string) error { | ||||
| func (v *gitUtilsMock) PlainClone(_, _, _, directory string) error { | ||||
| 	if v.failOnClone { | ||||
| 		return errors.New("error on clone") | ||||
| 	} | ||||
| 	v.temporaryDirectory = directory | ||||
| 	filePath := filepath.Join(directory, "dir1/dir2/depl.yaml") | ||||
| 	err := piperutils.Files{}.MkdirAll(filepath.Join(directory, "dir1/dir2"), 0755) | ||||
| 	if err != nil { | ||||
|   | ||||
| @@ -86,14 +86,14 @@ func plainClone(username, password, serverURL, directory string, abstractionGit | ||||
|  | ||||
| // ChangeBranch checkout the provided branch. | ||||
| // It will create a new branch if the branch does not exist yet. | ||||
| // It will checkout "master" if no branch name if provided | ||||
| // It will return an error if no branch name if provided | ||||
| func ChangeBranch(branchName string, worktree *git.Worktree) error { | ||||
| 	return changeBranch(branchName, worktree) | ||||
| } | ||||
|  | ||||
| func changeBranch(branchName string, worktree utilsWorkTree) error { | ||||
| 	if branchName == "" { | ||||
| 		branchName = "master" | ||||
| 		return errors.New("no branch name provided") | ||||
| 	} | ||||
|  | ||||
| 	var checkoutOptions = &git.CheckoutOptions{} | ||||
|   | ||||
| @@ -82,12 +82,11 @@ func TestChangeBranch(t *testing.T) { | ||||
| 		assert.False(t, worktreeMock.create) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("empty branch defaulted to master", func(t *testing.T) { | ||||
| 	t.Run("empty branch raises error", func(t *testing.T) { | ||||
| 		worktreeMock := &WorktreeMock{} | ||||
| 		err := changeBranch("", worktreeMock) | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Equal(t, string(plumbing.NewBranchReferenceName("master")), worktreeMock.checkedOutBranch) | ||||
| 		assert.False(t, worktreeMock.create) | ||||
| 		assert.Error(t, err) | ||||
| 		assert.EqualError(t, err, "no branch name provided") | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("create new branch", func(t *testing.T) { | ||||
|   | ||||
| @@ -6,13 +6,20 @@ metadata: | ||||
|  | ||||
|     It can for example be used for GitOps scenarios where the update of the manifests triggers an update of the corresponding deployment in Kubernetes. | ||||
|  | ||||
|     As of today, it supports the update of deployment yaml files via kubectl patch. The container inside the yaml must be described within the following hierarchy: {"spec":{"template":{"spec":{"containers":[{...}]}}}} | ||||
|     As of today, it supports the update of deployment yaml files via kubectl patch and update a whole helm template. | ||||
|     For kubectl the container inside the yaml must be described within the following hierarchy: `{"spec":{"template":{"spec":{"containers":[{...}]}}}}` | ||||
|     For helm the whole template is generated into a file and uploaded into the repository. | ||||
|  | ||||
|  | ||||
| spec: | ||||
|   inputs: | ||||
|     secrets: | ||||
|       - name: gitHttpsCredentialsId | ||||
|         description: Jenkins 'Username with password' credentials ID containing username/password for http access to your git repository. | ||||
|         type: jenkins | ||||
|     resources: | ||||
|       - name: deployDescriptor | ||||
|         type: stash | ||||
|     params: | ||||
|       - name: branchName | ||||
|         description: The name of the branch where the changes should get pushed into. | ||||
| @@ -22,15 +29,15 @@ spec: | ||||
|           - STEPS | ||||
|         type: string | ||||
|         default: master | ||||
|         mandatory: true | ||||
|       - name: commitMessage | ||||
|         description: The commit message of the commit that will be done to do the changes. | ||||
|         longDescription: If the commit message is empty a default message in the form "Updated _containerName_ to version _containerImage_" will be used. | ||||
|         scope: | ||||
|           - PARAMETERS | ||||
|           - STAGES | ||||
|           - STEPS | ||||
|         type: string | ||||
|         mandatory: true | ||||
|         default: Updated {{containerName}} to version {{containerImage}} | ||||
|       - name: serverUrl | ||||
|         aliases: | ||||
|           - name: githubServerUrl | ||||
| @@ -84,11 +91,11 @@ spec: | ||||
|           - STAGES | ||||
|           - STEPS | ||||
|         type: string | ||||
|         mandatory: true | ||||
|       - name: containerRegistryUrl | ||||
|         aliases: | ||||
|           - name: dockerRegistryUrl | ||||
|         type: string | ||||
|         mandatory: true | ||||
|         description: http(s) url of the Container registry where the image is located | ||||
|         scope: | ||||
|           - GENERAL | ||||
| @@ -104,6 +111,7 @@ spec: | ||||
|             deprecated: true | ||||
|           - name: containerImage | ||||
|         type: string | ||||
|         mandatory: true | ||||
|         description: Container image name with version tag to annotate in the deployment configuration. | ||||
|         scope: | ||||
|           - PARAMETERS | ||||
| @@ -112,9 +120,62 @@ spec: | ||||
|         resourceRef: | ||||
|           - name: commonPipelineEnvironment | ||||
|             param: container/imageNameTag | ||||
|       - name: chartPath | ||||
|         aliases: | ||||
|           - name: helmChartPath | ||||
|         type: string | ||||
|         description: Defines the chart path for deployments using helm. | ||||
|         scope: | ||||
|           - PARAMETERS | ||||
|           - STAGES | ||||
|           - STEPS | ||||
|       - name: helmValues | ||||
|         type: "[]string" | ||||
|         description: List of helm values as YAML file reference or URL (as per helm parameter description for `-f` / `--values`) | ||||
|         scope: | ||||
|           - PARAMETERS | ||||
|           - STAGES | ||||
|           - STEPS | ||||
|       - name: deploymentName | ||||
|         aliases: | ||||
|           - name: helmDeploymentName | ||||
|         type: string | ||||
|         description: Defines the name of the deployment. | ||||
|         scope: | ||||
|           - PARAMETERS | ||||
|           - STAGES | ||||
|           - STEPS | ||||
|       #        default: deployment | ||||
|       - name: tool | ||||
|         type: string | ||||
|         description: Defines the tool which should be used to update the deployment description. | ||||
|         mandatory: true | ||||
|         scope: | ||||
|           - PARAMETERS | ||||
|           - STAGES | ||||
|           - STEPS | ||||
|         default: kubectl | ||||
|         possibleValues: | ||||
|           - kubectl | ||||
|           - helm | ||||
|   containers: | ||||
|     - image: dtzar/helm-kubectl:3.3.4 | ||||
|       workingDir: /config | ||||
|       options: | ||||
|         - name: -u | ||||
|           value: "0" | ||||
|       conditions: | ||||
|         - conditionRef: strings-equal | ||||
|           params: | ||||
|             - name: tool | ||||
|               value: helm | ||||
|     - image: dtzar/helm-kubectl:2.12.1 | ||||
|       workingDir: /config | ||||
|       options: | ||||
|         - name: -u | ||||
|           value: "0" | ||||
|       conditions: | ||||
|         - conditionRef: strings-equal | ||||
|           params: | ||||
|             - name: tool | ||||
|               value: kubectl | ||||
|   | ||||
		Reference in New Issue
	
	Block a user