1
0
mirror of https://github.com/SAP/jenkins-library.git synced 2025-01-18 05:18:24 +02:00

Add helm dependency command (#3669)

* Add helm dependency command

* Change name of flag for package command

Co-authored-by: “Vitalii <“vitalii.sidorov@sap.com”>
Co-authored-by: Oliver Nocon <33484802+OliverNocon@users.noreply.github.com>
This commit is contained in:
Vitalii Sidorov 2022-03-30 10:18:51 +04:00 committed by GitHub
parent b6a5ceaa03
commit d62c3d73a0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 153 additions and 67 deletions

View File

@ -17,7 +17,8 @@ func helmExecute(config helmExecuteOptions, telemetryData *telemetry.CustomData)
KubeConfig: config.KubeConfig,
HelmDeployWaitSeconds: config.HelmDeployWaitSeconds,
AppVersion: config.AppVersion,
DependencyUpdate: config.DependencyUpdate,
Dependency: config.Dependency,
PackageDependencyUpdate: config.PackageDependencyUpdate,
HelmValues: config.HelmValues,
FilterTest: config.FilterTest,
DumpLogs: config.DumpLogs,
@ -69,9 +70,9 @@ func runHelmExecute(config helmExecuteOptions, helmExecutor kubernetes.HelmExecu
if err := helmExecutor.RunHelmUninstall(); err != nil {
return fmt.Errorf("failed to execute helm uninstall: %v", err)
}
case "package":
if err := helmExecutor.RunHelmPackage(); err != nil {
return fmt.Errorf("failed to execute helm package: %v", err)
case "dependency":
if err := helmExecutor.RunHelmDependency(); err != nil {
return fmt.Errorf("failed to execute helm dependency: %v", err)
}
case "publish":
if err := helmExecutor.RunHelmPublish(); err != nil {
@ -91,8 +92,10 @@ func runHelmExecuteDefault(config helmExecuteOptions, helmExecutor kubernetes.He
return fmt.Errorf("failed to execute helm lint: %v", err)
}
if err := helmExecutor.RunHelmPackage(); err != nil {
return fmt.Errorf("failed to execute helm package: %v", err)
if len(config.Dependency) > 0 {
if err := helmExecutor.RunHelmDependency(); err != nil {
return fmt.Errorf("failed to execute helm dependency: %v", err)
}
}
if config.Publish {

View File

@ -30,9 +30,10 @@ type helmExecuteOptions struct {
KubeContext string `json:"kubeContext,omitempty"`
Namespace string `json:"namespace,omitempty"`
DockerConfigJSON string `json:"dockerConfigJSON,omitempty"`
HelmCommand string `json:"helmCommand,omitempty" validate:"possible-values=upgrade install lint test uninstall package publish"`
HelmCommand string `json:"helmCommand,omitempty" validate:"possible-values=upgrade lint install test uninstall dependency publish"`
AppVersion string `json:"appVersion,omitempty"`
DependencyUpdate bool `json:"dependencyUpdate,omitempty"`
Dependency string `json:"dependency,omitempty" validate:"possible-values=build list update"`
PackageDependencyUpdate bool `json:"packageDependencyUpdate,omitempty"`
DumpLogs bool `json:"dumpLogs,omitempty"`
FilterTest string `json:"filterTest,omitempty"`
CustomTLSCertificateLinks []string `json:"customTlsCertificateLinks,omitempty"`
@ -62,15 +63,15 @@ Executes helm functionality as the package manager for Kubernetes.
* [Helm Charts] (https://artifacthub.io/)
` + "`" + `` + "`" + `` + "`" + `
Available Commands:
install install a chart
lint examine a chart for possible issues
package package a chart directory into a chart archive
repo add, list, remove, update, and index chart repositories
test run tests for a release
uninstall uninstall a release
upgrade upgrade a release
verify verify that a chart at the given path has been signed and is valid
push upload a chart to a registry
` + "`" + `upgrade` + "`" + `, ` + "`" + `lint` + "`" + `, ` + "`" + `install` + "`" + `, ` + "`" + `test` + "`" + `, ` + "`" + `uninstall` + "`" + `, ` + "`" + `dependency` + "`" + `, ` + "`" + `publish` + "`" + `
upgrade upgrade a release
lint examine a chart for possible issues
install install a chart
test run tests for a release
uninstall uninstall a release
dependency package a chart directory into a chart archive
publish package and puslish a release
` + "`" + `` + "`" + `` + "`" + `
@ -167,9 +168,10 @@ func addHelmExecuteFlags(cmd *cobra.Command, stepConfig *helmExecuteOptions) {
cmd.Flags().StringVar(&stepConfig.KubeContext, "kubeContext", os.Getenv("PIPER_kubeContext"), "Defines the context to use from the \"kubeconfig\" file.")
cmd.Flags().StringVar(&stepConfig.Namespace, "namespace", `default`, "Defines the target Kubernetes namespace for the deployment.")
cmd.Flags().StringVar(&stepConfig.DockerConfigJSON, "dockerConfigJSON", os.Getenv("PIPER_dockerConfigJSON"), "Path to the file `.docker/config.json` - this is typically provided by your CI/CD system. You can find more details about the Docker credentials in the [Docker documentation](https://docs.docker.com/engine/reference/commandline/login/).")
cmd.Flags().StringVar(&stepConfig.HelmCommand, "helmCommand", os.Getenv("PIPER_helmCommand"), "Helm: defines the command `install`, `lint`, `package`, `test`, `upgrade` and etc.")
cmd.Flags().StringVar(&stepConfig.HelmCommand, "helmCommand", os.Getenv("PIPER_helmCommand"), "Helm: defines the command `upgrade`, `lint`, `install`, `test`, `uninstall`, `dependency`, `publish`.")
cmd.Flags().StringVar(&stepConfig.AppVersion, "appVersion", os.Getenv("PIPER_appVersion"), "set the appVersion on the chart to this version")
cmd.Flags().BoolVar(&stepConfig.DependencyUpdate, "dependencyUpdate", false, "set the appVersion on the chart to this version")
cmd.Flags().StringVar(&stepConfig.Dependency, "dependency", os.Getenv("PIPER_dependency"), "manage a chart's dependencies")
cmd.Flags().BoolVar(&stepConfig.PackageDependencyUpdate, "packageDependencyUpdate", false, "update dependencies from \"Chart.yaml\" to dir \"charts/\" before packaging")
cmd.Flags().BoolVar(&stepConfig.DumpLogs, "dumpLogs", false, "dump the logs from test pods (this runs after all tests are complete, but before any cleanup)")
cmd.Flags().StringVar(&stepConfig.FilterTest, "filterTest", os.Getenv("PIPER_filterTest"), "specify tests by attribute (currently `name`) using attribute=value syntax or `!attribute=value` to exclude a test (can specify multiple or separate values with commas `name=test1,name=test2`)")
cmd.Flags().StringSliceVar(&stepConfig.CustomTLSCertificateLinks, "customTlsCertificateLinks", []string{}, "List of download links to custom TLS certificates. This is required to ensure trusted connections to instances with repositories (like nexus) when publish flag is set to true.")
@ -399,7 +401,16 @@ func helmExecuteMetadata() config.StepData {
Default: os.Getenv("PIPER_appVersion"),
},
{
Name: "dependencyUpdate",
Name: "dependency",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "string",
Mandatory: false,
Aliases: []config.Alias{},
Default: os.Getenv("PIPER_dependency"),
},
{
Name: "packageDependencyUpdate",
ResourceRef: []config.ResourceReference{},
Scope: []string{"GENERAL", "PARAMETERS", "STAGES", "STEPS"},
Type: "bool",

View File

@ -196,7 +196,7 @@ func TestRunHelmUninstall(t *testing.T) {
}
}
func TestRunHelmPackage(t *testing.T) {
func TestRunHelmDependency(t *testing.T) {
t.Parallel()
testTable := []struct {
@ -206,23 +206,23 @@ func TestRunHelmPackage(t *testing.T) {
}{
{
config: helmExecuteOptions{
HelmCommand: "package",
HelmCommand: "dependency",
},
methodError: nil,
},
{
config: helmExecuteOptions{
HelmCommand: "package",
HelmCommand: "dependency",
},
methodError: errors.New("some error"),
expectedErrStr: "failed to execute helm package: some error",
expectedErrStr: "failed to execute helm dependency: some error",
},
}
for i, testCase := range testTable {
t.Run(fmt.Sprint("case ", i), func(t *testing.T) {
helmExecute := &mocks.HelmExecutor{}
helmExecute.On("RunHelmPackage").Return(testCase.methodError)
helmExecute.On("RunHelmDependency").Return(testCase.methodError)
err := runHelmExecute(testCase.config, helmExecute)
if err != nil {
@ -300,7 +300,7 @@ func TestRunHelmDefaultCommand(t *testing.T) {
HelmCommand: "",
},
methodPackageError: errors.New("some error"),
expectedErrStr: "failed to execute helm package: some error",
expectedErrStr: "failed to execute helm dependency: some error",
},
{
config: helmExecuteOptions{
@ -315,7 +315,7 @@ func TestRunHelmDefaultCommand(t *testing.T) {
t.Run(fmt.Sprint("case ", i), func(t *testing.T) {
helmExecute := &mocks.HelmExecutor{}
helmExecute.On("RunHelmLint").Return(testCase.methodLintError)
helmExecute.On("RunHelmPackage").Return(testCase.methodPackageError)
helmExecute.On("RunHelmDependency").Return(testCase.methodPackageError)
helmExecute.On("RunHelmPublish").Return(testCase.methodPublishError)
err := runHelmExecute(testCase.config, helmExecute)

View File

@ -16,9 +16,9 @@ type HelmExecutor interface {
RunHelmLint() error
RunHelmInstall() error
RunHelmUninstall() error
RunHelmPackage() error
RunHelmTest() error
RunHelmPublish() error
RunHelmDependency() error
}
// HelmExecute struct
@ -45,7 +45,8 @@ type HelmExecuteOptions struct {
DockerConfigJSON string `json:"dockerConfigJSON,omitempty"`
PackageVersion string `json:"packageVersion,omitempty"`
AppVersion string `json:"appVersion,omitempty"`
DependencyUpdate bool `json:"dependencyUpdate,omitempty"`
Dependency string `json:"dependency,omitempty" validate:"possible-values=build list update"`
PackageDependencyUpdate bool `json:"packageDependencyUpdate,omitempty"`
DumpLogs bool `json:"dumpLogs,omitempty"`
FilterTest string `json:"filterTest,omitempty"`
TargetRepositoryURL string `json:"targetRepositoryURL,omitempty"`
@ -265,7 +266,7 @@ func (h *HelmExecute) RunHelmUninstall() error {
}
// RunHelmPackage is used to package a chart directory into a chart archive
func (h *HelmExecute) RunHelmPackage() error {
func (h *HelmExecute) runHelmPackage() error {
err := h.runHelmInit()
if err != nil {
return fmt.Errorf("failed to execute deployments: %v", err)
@ -278,7 +279,7 @@ func (h *HelmExecute) RunHelmPackage() error {
if len(h.config.PackageVersion) > 0 {
helmParams = append(helmParams, "--version", h.config.PackageVersion)
}
if h.config.DependencyUpdate {
if h.config.PackageDependencyUpdate {
helmParams = append(helmParams, "--dependency-update")
}
if len(h.config.AppVersion) > 0 {
@ -323,6 +324,31 @@ func (h *HelmExecute) RunHelmTest() error {
return nil
}
// RunHelmDependency is used to manage a chart's dependencies
func (h *HelmExecute) RunHelmDependency() error {
if len(h.config.Dependency) == 0 {
return fmt.Errorf("there is no dependency value. Possible values are build, list, update")
}
helmParams := []string{
"dependency",
}
helmParams = append(helmParams, h.config.Dependency)
helmParams = append(helmParams, h.config.ChartPath)
if len(h.config.AdditionalParameters) > 0 {
helmParams = append(helmParams, h.config.AdditionalParameters...)
}
if err := h.runHelmCommand(helmParams); err != nil {
log.Entry().WithError(err).Fatal("Helm dependency call failed")
}
return nil
}
//RunHelmPublish is used to upload a chart to a registry
func (h *HelmExecute) RunHelmPublish() error {
err := h.runHelmInit()
@ -330,6 +356,11 @@ func (h *HelmExecute) RunHelmPublish() error {
return fmt.Errorf("failed to execute deployments: %v", err)
}
err = h.runHelmPackage()
if err != nil {
return fmt.Errorf("failed to execute deployments: %v", err)
}
if len(h.config.TargetRepositoryURL) == 0 {
return fmt.Errorf("there's no target repository for helm chart publishing configured")
}

View File

@ -241,11 +241,11 @@ func TestRunHelm(t *testing.T) {
},
{
config: HelmExecuteOptions{
ChartPath: ".",
DeploymentName: "testPackage",
PackageVersion: "1.2.3",
DependencyUpdate: true,
AppVersion: "9.8.7",
ChartPath: ".",
DeploymentName: "testPackage",
PackageVersion: "1.2.3",
PackageDependencyUpdate: true,
AppVersion: "9.8.7",
},
expectedConfig: []string{"package", ".", "--version", "1.2.3", "--dependency-update", "--app-version", "9.8.7"},
},
@ -258,7 +258,7 @@ func TestRunHelm(t *testing.T) {
verbose: false,
stdout: log.Writer(),
}
err := helmExecute.RunHelmPackage()
err := helmExecute.runHelmPackage()
assert.NoError(t, err)
assert.Equal(t, mock.ExecCall{Exec: "helm", Params: testCase.expectedConfig}, utils.Calls[i])
}
@ -373,6 +373,50 @@ func TestRunHelm(t *testing.T) {
}
})
t.Run("Helm dependency command", func(t *testing.T) {
utils := newHelmMockUtilsBundle()
testTable := []struct {
config HelmExecuteOptions
expectedError error
expectedResult []string
}{
{
config: HelmExecuteOptions{
ChartPath: ".",
},
expectedError: errors.New("there is no dependency value. Possible values are build, list, update"),
expectedResult: nil,
},
{
config: HelmExecuteOptions{
ChartPath: ".",
Dependency: "update",
},
expectedError: nil,
expectedResult: []string{"dependency", "update", "."},
},
}
for _, testCase := range testTable {
helmExecute := HelmExecute{
utils: utils,
config: testCase.config,
verbose: false,
stdout: log.Writer(),
}
err := helmExecute.RunHelmDependency()
if testCase.expectedError != nil {
assert.Error(t, err)
assert.Equal(t, testCase.expectedError, err)
} else {
assert.NoError(t, err)
assert.Equal(t, mock.ExecCall{Exec: "helm", Params: testCase.expectedResult}, utils.Calls[0])
}
}
})
t.Run("Helm publish command", func(t *testing.T) {
utils := newHelmMockUtilsBundle()

View File

@ -9,8 +9,8 @@ type HelmExecutor struct {
mock.Mock
}
// RunHelmAdd provides a mock function with given fields:
func (_m *HelmExecutor) RunHelmAdd() error {
// RunHelmDependency provides a mock function with given fields:
func (_m *HelmExecutor) RunHelmDependency() error {
ret := _m.Called()
var r0 error
@ -51,20 +51,6 @@ func (_m *HelmExecutor) RunHelmLint() error {
return r0
}
// RunHelmPackage provides a mock function with given fields:
func (_m *HelmExecutor) RunHelmPackage() error {
ret := _m.Called()
var r0 error
if rf, ok := ret.Get(0).(func() error); ok {
r0 = rf()
} else {
r0 = ret.Error(0)
}
return r0
}
// RunHelmPublish provides a mock function with given fields:
func (_m *HelmExecutor) RunHelmPublish() error {
ret := _m.Called()

View File

@ -11,15 +11,15 @@ metadata:
* [Helm Charts] (https://artifacthub.io/)
```
Available Commands:
install install a chart
lint examine a chart for possible issues
package package a chart directory into a chart archive
repo add, list, remove, update, and index chart repositories
test run tests for a release
uninstall uninstall a release
upgrade upgrade a release
verify verify that a chart at the given path has been signed and is valid
push upload a chart to a registry
`upgrade`, `lint`, `install`, `test`, `uninstall`, `dependency`, `publish`
upgrade upgrade a release
lint examine a chart for possible issues
install install a chart
test run tests for a release
uninstall uninstall a release
dependency package a chart directory into a chart archive
publish package and puslish a release
```
@ -189,18 +189,18 @@ spec:
default: docker-config
- name: helmCommand
type: string
description: "Helm: defines the command `install`, `lint`, `package`, `test`, `upgrade` and etc."
description: "Helm: defines the command `upgrade`, `lint`, `install`, `test`, `uninstall`, `dependency`, `publish`."
scope:
- PARAMETERS
- STAGES
- STEPS
possibleValues:
- upgrade
- install
- lint
- install
- test
- uninstall
- package
- dependency
- publish
- name: appVersion
type: string
@ -210,9 +210,20 @@ spec:
- PARAMETERS
- STAGES
- STEPS
- name: dependencyUpdate
- name: dependency
type: string
description: "manage a chart's dependencies"
scope:
- PARAMETERS
- STAGES
- STEPS
possibleValues:
- build
- list
- update
- name: packageDependencyUpdate
type: bool
description: set the appVersion on the chart to this version
description: update dependencies from "Chart.yaml" to dir "charts/" before packaging
default: false
scope:
- GENERAL