1
0
mirror of https://github.com/SAP/jenkins-library.git synced 2025-10-30 23:57:50 +02:00

helmExecute: add remoteHelmChartPath CPE value (#3965)

* Add remoteHelmChartPath CPE value

* Fix tests

* Add empty line at the end of yaml file

* Fix yaml file
This commit is contained in:
Vyacheslav Starostin
2022-08-16 01:41:24 +06:00
committed by GitHub
parent 74cc828221
commit b31549cf7f
7 changed files with 119 additions and 33 deletions

View File

@@ -11,7 +11,7 @@ import (
"github.com/SAP/jenkins-library/pkg/versioning"
)
func helmExecute(config helmExecuteOptions, telemetryData *telemetry.CustomData) {
func helmExecute(config helmExecuteOptions, telemetryData *telemetry.CustomData, commonPipelineEnvironment *helmExecuteCommonPipelineEnvironment) {
helmConfig := kubernetes.HelmExecuteOptions{
AdditionalParameters: config.AdditionalParameters,
ChartPath: config.ChartPath,
@@ -64,12 +64,12 @@ func helmExecute(config helmExecuteOptions, telemetryData *telemetry.CustomData)
helmExecutor := kubernetes.NewHelmExecutor(helmConfig, utils, GeneralConfig.Verbose, log.Writer())
// error situations should stop execution through log.Entry().Fatal() call which leads to an os.Exit(1) in the end
if err := runHelmExecute(config, helmExecutor); err != nil {
if err := runHelmExecute(config, helmExecutor, commonPipelineEnvironment); err != nil {
log.Entry().WithError(err).Fatalf("step execution failed: %v", err)
}
}
func runHelmExecute(config helmExecuteOptions, helmExecutor kubernetes.HelmExecutor) error {
func runHelmExecute(config helmExecuteOptions, helmExecutor kubernetes.HelmExecutor, commonPipelineEnvironment *helmExecuteCommonPipelineEnvironment) error {
switch config.HelmCommand {
case "upgrade":
if err := helmExecutor.RunHelmUpgrade(); err != nil {
@@ -96,11 +96,13 @@ func runHelmExecute(config helmExecuteOptions, helmExecutor kubernetes.HelmExecu
return fmt.Errorf("failed to execute helm dependency: %v", err)
}
case "publish":
if err := helmExecutor.RunHelmPublish(); err != nil {
targetURL, err := helmExecutor.RunHelmPublish()
if err != nil {
return fmt.Errorf("failed to execute helm publish: %v", err)
}
commonPipelineEnvironment.custom.remoteHelmChartPath = targetURL
default:
if err := runHelmExecuteDefault(config, helmExecutor); err != nil {
if err := runHelmExecuteDefault(config, helmExecutor, commonPipelineEnvironment); err != nil {
return err
}
}
@@ -108,7 +110,7 @@ func runHelmExecute(config helmExecuteOptions, helmExecutor kubernetes.HelmExecu
return nil
}
func runHelmExecuteDefault(config helmExecuteOptions, helmExecutor kubernetes.HelmExecutor) error {
func runHelmExecuteDefault(config helmExecuteOptions, helmExecutor kubernetes.HelmExecutor, commonPipelineEnvironment *helmExecuteCommonPipelineEnvironment) error {
if err := helmExecutor.RunHelmLint(); err != nil {
return fmt.Errorf("failed to execute helm lint: %v", err)
}
@@ -120,9 +122,11 @@ func runHelmExecuteDefault(config helmExecuteOptions, helmExecutor kubernetes.He
}
if config.Publish {
if err := helmExecutor.RunHelmPublish(); err != nil {
targetURL, err := helmExecutor.RunHelmPublish()
if err != nil {
return fmt.Errorf("failed to execute helm publish: %v", err)
}
commonPipelineEnvironment.custom.remoteHelmChartPath = targetURL
}
return nil

View File

@@ -5,10 +5,12 @@ package cmd
import (
"fmt"
"os"
"path/filepath"
"time"
"github.com/SAP/jenkins-library/pkg/config"
"github.com/SAP/jenkins-library/pkg/log"
"github.com/SAP/jenkins-library/pkg/piperenv"
"github.com/SAP/jenkins-library/pkg/splunk"
"github.com/SAP/jenkins-library/pkg/telemetry"
"github.com/SAP/jenkins-library/pkg/validation"
@@ -41,6 +43,34 @@ type helmExecuteOptions struct {
Version string `json:"version,omitempty"`
}
type helmExecuteCommonPipelineEnvironment struct {
custom struct {
remoteHelmChartPath string
}
}
func (p *helmExecuteCommonPipelineEnvironment) persist(path, resourceName string) {
content := []struct {
category string
name string
value interface{}
}{
{category: "custom", name: "remoteHelmChartPath", value: p.custom.remoteHelmChartPath},
}
errCount := 0
for _, param := range content {
err := piperenv.SetResourceParameter(path, resourceName, filepath.Join(param.category, param.name), param.value)
if err != nil {
log.Entry().WithError(err).Error("Error persisting piper environment.")
errCount++
}
}
if errCount > 0 {
log.Entry().Error("failed to persist Piper environment")
}
}
// HelmExecuteCommand Executes helm3 functionality as the package manager for Kubernetes.
func HelmExecuteCommand() *cobra.Command {
const STEP_NAME = "helmExecute"
@@ -48,6 +78,7 @@ func HelmExecuteCommand() *cobra.Command {
metadata := helmExecuteMetadata()
var stepConfig helmExecuteOptions
var startTime time.Time
var commonPipelineEnvironment helmExecuteCommonPipelineEnvironment
var logCollector *log.CollectorHook
var splunkClient *splunk.Splunk
telemetryClient := &telemetry.Telemetry{}
@@ -128,6 +159,7 @@ Note: piper supports only helm3 version, since helm2 is deprecated.`,
stepTelemetryData := telemetry.CustomData{}
stepTelemetryData.ErrorCode = "1"
handler := func() {
commonPipelineEnvironment.persist(GeneralConfig.EnvRootPath, "commonPipelineEnvironment")
config.RemoveVaultSecretFiles()
stepTelemetryData.Duration = fmt.Sprintf("%v", time.Since(startTime).Milliseconds())
stepTelemetryData.ErrorCategory = log.GetErrorCategory().String()
@@ -148,7 +180,7 @@ Note: piper supports only helm3 version, since helm2 is deprecated.`,
GeneralConfig.HookConfig.SplunkConfig.Index,
GeneralConfig.HookConfig.SplunkConfig.SendLogs)
}
helmExecute(stepConfig, &stepTelemetryData)
helmExecute(stepConfig, &stepTelemetryData, &commonPipelineEnvironment)
stepTelemetryData.ErrorCode = "0"
log.Entry().Info("SUCCESS")
},
@@ -498,6 +530,17 @@ func helmExecuteMetadata() config.StepData {
Containers: []config.Container{
{Image: "dtzar/helm-kubectl:3.8.0", WorkingDir: "/config", Options: []config.Option{{Name: "-u", Value: "0"}}},
},
Outputs: config.StepOutputs{
Resources: []config.StepResources{
{
Name: "commonPipelineEnvironment",
Type: "piperEnvironment",
Parameters: []map[string]interface{}{
{"name": "custom/remoteHelmChartPath"},
},
},
},
},
},
}
return theMetaData

View File

@@ -34,6 +34,7 @@ func newHelmMockUtilsBundle() helmMockUtilsBundle {
func TestRunHelmUpgrade(t *testing.T) {
t.Parallel()
cpe := helmExecuteCommonPipelineEnvironment{}
testTable := []struct {
config helmExecuteOptions
methodError error
@@ -59,7 +60,7 @@ func TestRunHelmUpgrade(t *testing.T) {
helmExecute := &mocks.HelmExecutor{}
helmExecute.On("RunHelmUpgrade").Return(testCase.methodError)
err := runHelmExecute(testCase.config, helmExecute)
err := runHelmExecute(testCase.config, helmExecute, &cpe)
if err != nil {
assert.Equal(t, testCase.expectedErrStr, err.Error())
}
@@ -71,6 +72,7 @@ func TestRunHelmUpgrade(t *testing.T) {
func TestRunHelmLint(t *testing.T) {
t.Parallel()
cpe := helmExecuteCommonPipelineEnvironment{}
testTable := []struct {
config helmExecuteOptions
expectedConfig []string
@@ -97,7 +99,7 @@ func TestRunHelmLint(t *testing.T) {
helmExecute := &mocks.HelmExecutor{}
helmExecute.On("RunHelmLint").Return(testCase.methodError)
err := runHelmExecute(testCase.config, helmExecute)
err := runHelmExecute(testCase.config, helmExecute, &cpe)
if err != nil {
assert.Equal(t, testCase.expectedErrStr, err.Error())
}
@@ -109,6 +111,7 @@ func TestRunHelmLint(t *testing.T) {
func TestRunHelmInstall(t *testing.T) {
t.Parallel()
cpe := helmExecuteCommonPipelineEnvironment{}
testTable := []struct {
config helmExecuteOptions
expectedConfig []string
@@ -135,7 +138,7 @@ func TestRunHelmInstall(t *testing.T) {
helmExecute := &mocks.HelmExecutor{}
helmExecute.On("RunHelmInstall").Return(testCase.methodError)
err := runHelmExecute(testCase.config, helmExecute)
err := runHelmExecute(testCase.config, helmExecute, &cpe)
if err != nil {
assert.Equal(t, testCase.expectedErrStr, err.Error())
}
@@ -147,6 +150,7 @@ func TestRunHelmInstall(t *testing.T) {
func TestRunHelmTest(t *testing.T) {
t.Parallel()
cpe := helmExecuteCommonPipelineEnvironment{}
testTable := []struct {
config helmExecuteOptions
methodError error
@@ -172,7 +176,7 @@ func TestRunHelmTest(t *testing.T) {
helmExecute := &mocks.HelmExecutor{}
helmExecute.On("RunHelmTest").Return(testCase.methodError)
err := runHelmExecute(testCase.config, helmExecute)
err := runHelmExecute(testCase.config, helmExecute, &cpe)
if err != nil {
assert.Equal(t, testCase.expectedErrStr, err.Error())
}
@@ -184,6 +188,7 @@ func TestRunHelmTest(t *testing.T) {
func TestRunHelmUninstall(t *testing.T) {
t.Parallel()
cpe := helmExecuteCommonPipelineEnvironment{}
testTable := []struct {
config helmExecuteOptions
methodError error
@@ -209,7 +214,7 @@ func TestRunHelmUninstall(t *testing.T) {
helmExecute := &mocks.HelmExecutor{}
helmExecute.On("RunHelmUninstall").Return(testCase.methodError)
err := runHelmExecute(testCase.config, helmExecute)
err := runHelmExecute(testCase.config, helmExecute, &cpe)
if err != nil {
assert.Equal(t, testCase.expectedErrStr, err.Error())
}
@@ -221,6 +226,7 @@ func TestRunHelmUninstall(t *testing.T) {
func TestRunHelmDependency(t *testing.T) {
t.Parallel()
cpe := helmExecuteCommonPipelineEnvironment{}
testTable := []struct {
config helmExecuteOptions
methodError error
@@ -246,7 +252,7 @@ func TestRunHelmDependency(t *testing.T) {
helmExecute := &mocks.HelmExecutor{}
helmExecute.On("RunHelmDependency").Return(testCase.methodError)
err := runHelmExecute(testCase.config, helmExecute)
err := runHelmExecute(testCase.config, helmExecute, &cpe)
if err != nil {
assert.Equal(t, testCase.expectedErrStr, err.Error())
}
@@ -258,8 +264,10 @@ func TestRunHelmDependency(t *testing.T) {
func TestRunHelmPush(t *testing.T) {
t.Parallel()
cpe := helmExecuteCommonPipelineEnvironment{}
testTable := []struct {
config helmExecuteOptions
methodString string
methodError error
expectedErrStr string
}{
@@ -267,7 +275,8 @@ func TestRunHelmPush(t *testing.T) {
config: helmExecuteOptions{
HelmCommand: "publish",
},
methodError: nil,
methodString: "https://my.target.repository",
methodError: nil,
},
{
config: helmExecuteOptions{
@@ -281,9 +290,9 @@ func TestRunHelmPush(t *testing.T) {
for i, testCase := range testTable {
t.Run(fmt.Sprint("case ", i), func(t *testing.T) {
helmExecute := &mocks.HelmExecutor{}
helmExecute.On("RunHelmPublish").Return(testCase.methodError)
helmExecute.On("RunHelmPublish").Return(testCase.methodString, testCase.methodError)
err := runHelmExecute(testCase.config, helmExecute)
err := runHelmExecute(testCase.config, helmExecute, &cpe)
if err != nil {
assert.Equal(t, testCase.expectedErrStr, err.Error())
}
@@ -295,6 +304,7 @@ func TestRunHelmPush(t *testing.T) {
func TestRunHelmDefaultCommand(t *testing.T) {
t.Parallel()
cpe := helmExecuteCommonPipelineEnvironment{}
testTable := []struct {
config helmExecuteOptions
methodLintError error
@@ -340,7 +350,7 @@ func TestRunHelmDefaultCommand(t *testing.T) {
helmExecute.On("RunHelmDependency").Return(testCase.methodPackageError)
helmExecute.On("RunHelmPublish").Return(testCase.methodPublishError)
err := runHelmExecute(testCase.config, helmExecute)
err := runHelmExecute(testCase.config, helmExecute, &cpe)
if err != nil {
assert.Equal(t, testCase.expectedErrStr, err.Error())
}

View File

@@ -17,7 +17,7 @@ type HelmExecutor interface {
RunHelmInstall() error
RunHelmUninstall() error
RunHelmTest() error
RunHelmPublish() error
RunHelmPublish() (string, error)
RunHelmDependency() error
}
@@ -380,19 +380,19 @@ func (h *HelmExecute) RunHelmDependency() error {
}
//RunHelmPublish is used to upload a chart to a registry
func (h *HelmExecute) RunHelmPublish() error {
func (h *HelmExecute) RunHelmPublish() (string, error) {
err := h.runHelmInit()
if err != nil {
return fmt.Errorf("failed to execute deployments: %v", err)
return "", fmt.Errorf("failed to execute deployments: %v", err)
}
err = h.runHelmPackage()
if err != nil {
return fmt.Errorf("failed to execute deployments: %v", err)
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")
return "", fmt.Errorf("there's no target repository for helm chart publishing configured")
}
repoClientOptions := piperhttp.ClientOptions{
@@ -419,14 +419,14 @@ func (h *HelmExecute) RunHelmPublish() error {
response, err := h.utils.UploadRequest(http.MethodPut, targetURL, binary, "", nil, nil, "binary")
if err != nil {
return fmt.Errorf("couldn't upload artifact: %w", err)
return "", fmt.Errorf("couldn't upload artifact: %w", err)
}
if !(response.StatusCode == 200 || response.StatusCode == 201) {
return fmt.Errorf("couldn't upload artifact, received status code %d", response.StatusCode)
return "", fmt.Errorf("couldn't upload artifact, received status code %d", response.StatusCode)
}
return nil
return targetURL, nil
}
func (h *HelmExecute) runHelmCommand(helmParams []string) error {

View File

@@ -506,9 +506,10 @@ func TestRunHelmPublish(t *testing.T) {
stdout: log.Writer(),
}
err := helmExecute.RunHelmPublish()
targetURL, err := helmExecute.RunHelmPublish()
if assert.NoError(t, err) {
assert.Equal(t, 1, len(utils.FileUploads))
assert.Equal(t, "https://my.target.repository.local/test_helm_chart/test_helm_chart-1.2.3.tgz", targetURL)
assert.Equal(t, "https://my.target.repository.local/test_helm_chart/test_helm_chart-1.2.3.tgz", utils.FileUploads["test_helm_chart-1.2.3.tgz"])
}
})

View File

@@ -1,4 +1,4 @@
// Code generated by mockery v2.10.0. DO NOT EDIT.
// Code generated by mockery v2.14.0. DO NOT EDIT.
package mocks
@@ -52,17 +52,24 @@ func (_m *HelmExecutor) RunHelmLint() error {
}
// RunHelmPublish provides a mock function with given fields:
func (_m *HelmExecutor) RunHelmPublish() error {
func (_m *HelmExecutor) RunHelmPublish() (string, error) {
ret := _m.Called()
var r0 error
if rf, ok := ret.Get(0).(func() error); ok {
var r0 string
if rf, ok := ret.Get(0).(func() string); ok {
r0 = rf()
} else {
r0 = ret.Error(0)
r0 = ret.Get(0).(string)
}
return r0
var r1 error
if rf, ok := ret.Get(1).(func() error); ok {
r1 = rf()
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// RunHelmTest provides a mock function with given fields:
@@ -106,3 +113,18 @@ func (_m *HelmExecutor) RunHelmUpgrade() error {
return r0
}
type mockConstructorTestingTNewHelmExecutor interface {
mock.TestingT
Cleanup(func())
}
// NewHelmExecutor creates a new instance of HelmExecutor. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewHelmExecutor(t mockConstructorTestingTNewHelmExecutor) *HelmExecutor {
mock := &HelmExecutor{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}

View File

@@ -297,3 +297,9 @@ spec:
options:
- name: -u
value: "0"
outputs:
resources:
- name: commonPipelineEnvironment
type: piperEnvironment
params:
- name: custom/remoteHelmChartPath