Use gopkg.in/yaml.v2 for Helmfile v0.x (#609)
This should fix #435 for Helmfile v0.x releases since the next v0.150.0. We introduce a new envvar to opt-in to the new YAML library, so that you can give it a shot before upgrading your Helmfile to v1. The same envvar can be used to opt-out of the new YAML library after you upgrade to Helmfile v1, giving you a more flexible migration story. Signed-off-by: Yusuke Kuoka <ykuoka@gmail.com>
This commit is contained in:
		
							parent
							
								
									490bb5d147
								
							
						
					
					
						commit
						4688cf0132
					
				|  | @ -61,6 +61,7 @@ jobs: | ||||||
|            plugin-secrets-version: 3.15.0 |            plugin-secrets-version: 3.15.0 | ||||||
|            plugin-diff-version: 3.5.0 |            plugin-diff-version: 3.5.0 | ||||||
|            extra-helmfile-flags: |            extra-helmfile-flags: | ||||||
|  |            v1mode: | ||||||
|          - helm-version: v3.9.4 |          - helm-version: v3.9.4 | ||||||
|            kustomize-version: v4.5.7 |            kustomize-version: v4.5.7 | ||||||
|            # We assume that the helm-secrets plugin is supposed to |            # We assume that the helm-secrets plugin is supposed to | ||||||
|  | @ -71,16 +72,26 @@ jobs: | ||||||
|            plugin-secrets-version: 4.0.0 |            plugin-secrets-version: 4.0.0 | ||||||
|            plugin-diff-version: 3.6.0 |            plugin-diff-version: 3.6.0 | ||||||
|            extra-helmfile-flags: |            extra-helmfile-flags: | ||||||
|  |            v1mode: | ||||||
|          - helm-version: v3.10.3 |          - helm-version: v3.10.3 | ||||||
|            kustomize-version: v4.4.1 |            kustomize-version: v4.4.1 | ||||||
|            plugin-secrets-version: 3.15.0 |            plugin-secrets-version: 3.15.0 | ||||||
|            plugin-diff-version: 3.5.0 |            plugin-diff-version: 3.5.0 | ||||||
|            extra-helmfile-flags: |            extra-helmfile-flags: | ||||||
|  |            v1mode: | ||||||
|          - helm-version: v3.10.3 |          - helm-version: v3.10.3 | ||||||
|            kustomize-version: v4.5.7 |            kustomize-version: v4.5.7 | ||||||
|            plugin-secrets-version: 4.0.0 |            plugin-secrets-version: 4.0.0 | ||||||
|            plugin-diff-version: 3.6.0 |            plugin-diff-version: 3.6.0 | ||||||
|            extra-helmfile-flags: |            extra-helmfile-flags: | ||||||
|  |            v1mode: | ||||||
|  |          # Helmfile v1 | ||||||
|  |          - helm-version: v3.10.3 | ||||||
|  |            kustomize-version: v4.5.7 | ||||||
|  |            plugin-secrets-version: 4.0.0 | ||||||
|  |            plugin-diff-version: 3.6.0 | ||||||
|  |            extra-helmfile-flags: | ||||||
|  |            v1mode: "true" | ||||||
|          # In case you need to test some optional helmfile features, |          # In case you need to test some optional helmfile features, | ||||||
|          # enable it via extra-helmfile-flags below. |          # enable it via extra-helmfile-flags below. | ||||||
|          - helm-version: v3.10.3 |          - helm-version: v3.10.3 | ||||||
|  | @ -88,6 +99,7 @@ jobs: | ||||||
|            plugin-secrets-version: 4.0.0 |            plugin-secrets-version: 4.0.0 | ||||||
|            plugin-diff-version: 3.6.0 |            plugin-diff-version: 3.6.0 | ||||||
|            extra-helmfile-flags: "--enable-live-output" |            extra-helmfile-flags: "--enable-live-output" | ||||||
|  |            v1mode: | ||||||
|     steps: |     steps: | ||||||
|     - uses: actions/checkout@v2 |     - uses: actions/checkout@v2 | ||||||
|     - name: Cache libraries |     - name: Cache libraries | ||||||
|  | @ -131,6 +143,7 @@ jobs: | ||||||
|         HELMFILE_HELM3: 1 |         HELMFILE_HELM3: 1 | ||||||
|         TERM: xterm |         TERM: xterm | ||||||
|         EXTRA_HELMFILE_FLAGS: ${{ matrix.extra-helmfile-flags }} |         EXTRA_HELMFILE_FLAGS: ${{ matrix.extra-helmfile-flags }} | ||||||
|  |         HELMFILE_V1MODE: ${{ matrix.v1mode }} | ||||||
|       run: make integration |       run: make integration | ||||||
|   e2e_tests: |   e2e_tests: | ||||||
|     needs: tests |     needs: tests | ||||||
|  |  | ||||||
|  | @ -15,8 +15,8 @@ import ( | ||||||
| 	"github.com/helmfile/helmfile/pkg/exectest" | 	"github.com/helmfile/helmfile/pkg/exectest" | ||||||
| 	ffs "github.com/helmfile/helmfile/pkg/filesystem" | 	ffs "github.com/helmfile/helmfile/pkg/filesystem" | ||||||
| 	"github.com/helmfile/helmfile/pkg/helmexec" | 	"github.com/helmfile/helmfile/pkg/helmexec" | ||||||
|  | 	"github.com/helmfile/helmfile/pkg/runtime" | ||||||
| 	"github.com/helmfile/helmfile/pkg/testhelper" | 	"github.com/helmfile/helmfile/pkg/testhelper" | ||||||
| 	"github.com/helmfile/helmfile/pkg/yaml" |  | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func TestTemplate(t *testing.T) { | func TestTemplate(t *testing.T) { | ||||||
|  | @ -309,20 +309,21 @@ releases: | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestTemplate_StrictParsing(t *testing.T) { | func TestTemplate_StrictParsing(t *testing.T) { | ||||||
| 	v := yaml.GoccyGoYaml |  | ||||||
| 	yaml.GoccyGoYaml = true |  | ||||||
| 	t.Cleanup(func() { |  | ||||||
| 		yaml.GoccyGoYaml = v |  | ||||||
| 	}) |  | ||||||
| 
 |  | ||||||
| 	type testcase struct { | 	type testcase struct { | ||||||
| 		ns    string | 		goccyGoYaml bool | ||||||
| 		error string | 		ns          string | ||||||
|  | 		error       string | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	check := func(t *testing.T, tc testcase) { | 	check := func(t *testing.T, tc testcase) { | ||||||
| 		t.Helper() | 		t.Helper() | ||||||
| 
 | 
 | ||||||
|  | 		v := runtime.GoccyGoYaml | ||||||
|  | 		runtime.GoccyGoYaml = tc.goccyGoYaml | ||||||
|  | 		t.Cleanup(func() { | ||||||
|  | 			runtime.GoccyGoYaml = v | ||||||
|  | 		}) | ||||||
|  | 
 | ||||||
| 		var helm = &exectest.Helm{ | 		var helm = &exectest.Helm{ | ||||||
| 			FailOnUnexpectedList: true, | 			FailOnUnexpectedList: true, | ||||||
| 			FailOnUnexpectedDiff: true, | 			FailOnUnexpectedDiff: true, | ||||||
|  | @ -381,8 +382,9 @@ releases: | ||||||
| 		}) | 		}) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	t.Run("fail due to known field", func(t *testing.T) { | 	t.Run("fail due to unknown field with goccy/go-yaml", func(t *testing.T) { | ||||||
| 		check(t, testcase{ | 		check(t, testcase{ | ||||||
|  | 			goccyGoYaml: true, | ||||||
| 			error: `in ./helmfile.yaml: failed to read helmfile.yaml: reading document at index 1: [4:3] unknown field "foobar" | 			error: `in ./helmfile.yaml: failed to read helmfile.yaml: reading document at index 1: [4:3] unknown field "foobar" | ||||||
|        2 | releases: |        2 | releases: | ||||||
|        3 | - name: app1 |        3 | - name: app1 | ||||||
|  | @ -391,6 +393,14 @@ releases: | ||||||
|        5 |   chart: incubator/raw`, |        5 |   chart: incubator/raw`, | ||||||
| 		}) | 		}) | ||||||
| 	}) | 	}) | ||||||
|  | 
 | ||||||
|  | 	t.Run("fail due to unknown field with gopkg.in/yaml.v2", func(t *testing.T) { | ||||||
|  | 		check(t, testcase{ | ||||||
|  | 			goccyGoYaml: false, | ||||||
|  | 			error: `in ./helmfile.yaml: failed to read helmfile.yaml: reading document at index 1: yaml: unmarshal errors: | ||||||
|  |   line 4: field foobar not found in type state.ReleaseSpec`, | ||||||
|  | 		}) | ||||||
|  | 	}) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestTemplate_CyclicInheritance(t *testing.T) { | func TestTemplate_CyclicInheritance(t *testing.T) { | ||||||
|  |  | ||||||
|  | @ -9,7 +9,7 @@ import ( | ||||||
| 	"path/filepath" | 	"path/filepath" | ||||||
| 	"reflect" | 	"reflect" | ||||||
| 	"regexp" | 	"regexp" | ||||||
| 	"runtime" | 	goruntime "runtime" | ||||||
| 	"strings" | 	"strings" | ||||||
| 	"sync" | 	"sync" | ||||||
| 	"testing" | 	"testing" | ||||||
|  | @ -25,6 +25,7 @@ import ( | ||||||
| 	ffs "github.com/helmfile/helmfile/pkg/filesystem" | 	ffs "github.com/helmfile/helmfile/pkg/filesystem" | ||||||
| 	"github.com/helmfile/helmfile/pkg/helmexec" | 	"github.com/helmfile/helmfile/pkg/helmexec" | ||||||
| 	"github.com/helmfile/helmfile/pkg/remote" | 	"github.com/helmfile/helmfile/pkg/remote" | ||||||
|  | 	"github.com/helmfile/helmfile/pkg/runtime" | ||||||
| 	"github.com/helmfile/helmfile/pkg/state" | 	"github.com/helmfile/helmfile/pkg/state" | ||||||
| 	"github.com/helmfile/helmfile/pkg/testhelper" | 	"github.com/helmfile/helmfile/pkg/testhelper" | ||||||
| 	"github.com/helmfile/helmfile/pkg/testutil" | 	"github.com/helmfile/helmfile/pkg/testutil" | ||||||
|  | @ -4338,7 +4339,15 @@ myrelease4	testNamespace	true   	true     	id:myrelease1             	mychart1 | ||||||
| 	assert.Equal(t, expected, out) | 	assert.Equal(t, expected, out) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestSetValuesTemplate(t *testing.T) { | func testSetValuesTemplate(t *testing.T, goccyGoYaml bool) { | ||||||
|  | 	t.Helper() | ||||||
|  | 
 | ||||||
|  | 	v := runtime.GoccyGoYaml | ||||||
|  | 	runtime.GoccyGoYaml = goccyGoYaml | ||||||
|  | 	t.Cleanup(func() { | ||||||
|  | 		runtime.GoccyGoYaml = v | ||||||
|  | 	}) | ||||||
|  | 
 | ||||||
| 	files := map[string]string{ | 	files := map[string]string{ | ||||||
| 		"/path/to/helmfile.yaml": ` | 		"/path/to/helmfile.yaml": ` | ||||||
| releases: | releases: | ||||||
|  | @ -4357,7 +4366,7 @@ releases: | ||||||
| `, | `, | ||||||
| 	} | 	} | ||||||
| 	expectedValues := []interface{}{ | 	expectedValues := []interface{}{ | ||||||
| 		map[interface{}]interface{}{"val1": "zipkin"}, | 		map[string]interface{}{"val1": "zipkin"}, | ||||||
| 		map[string]interface{}{"val2": "val2"}} | 		map[string]interface{}{"val2": "val2"}} | ||||||
| 	expectedSetValues := []state.SetValue{ | 	expectedSetValues := []state.SetValue{ | ||||||
| 		{Name: "name-zipkin", Value: "val-zipkin"}, | 		{Name: "name-zipkin", Value: "val-zipkin"}, | ||||||
|  | @ -4402,7 +4411,17 @@ releases: | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func TestSetValuesTemplate(t *testing.T) { | ||||||
|  | 	t.Run("with goccy/go-yaml", func(t *testing.T) { | ||||||
|  | 		testSetValuesTemplate(t, true) | ||||||
|  | 	}) | ||||||
|  | 
 | ||||||
|  | 	t.Run("with gopkg.in/yaml.v2", func(t *testing.T) { | ||||||
|  | 		testSetValuesTemplate(t, false) | ||||||
|  | 	}) | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func location() string { | func location() string { | ||||||
| 	_, fn, line, _ := runtime.Caller(1) | 	_, fn, line, _ := goruntime.Caller(1) | ||||||
| 	return fmt.Sprintf("%s:%d", filepath.Base(fn), line) | 	return fmt.Sprintf("%s:%d", filepath.Base(fn), line) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -10,4 +10,6 @@ const ( | ||||||
| 	Helm3                         = "HELMFILE_HELM3" | 	Helm3                         = "HELMFILE_HELM3" | ||||||
| 	UpgradeNoticeDisabled         = "HELMFILE_UPGRADE_NOTICE_DISABLED" | 	UpgradeNoticeDisabled         = "HELMFILE_UPGRADE_NOTICE_DISABLED" | ||||||
| 	V1Mode                        = "HELMFILE_V1MODE" | 	V1Mode                        = "HELMFILE_V1MODE" | ||||||
|  | 	GoccyGoYaml                   = "HELMFILE_GOCCY_GOYAML" | ||||||
|  | 	CacheHome                     = "HELMFILE_CACHE_HOME" | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  | @ -27,6 +27,10 @@ func init() { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func CacheDir() string { | func CacheDir() string { | ||||||
|  | 	if h := os.Getenv(envvar.CacheHome); h != "" { | ||||||
|  | 		return h | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	dir, err := os.UserCacheDir() | 	dir, err := os.UserCacheDir() | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		// fall back to relative path with hidden directory
 | 		// fall back to relative path with hidden directory
 | ||||||
|  |  | ||||||
|  | @ -13,13 +13,23 @@ import ( | ||||||
| var ( | var ( | ||||||
| 	V1Mode bool | 	V1Mode bool | ||||||
| 
 | 
 | ||||||
|  | 	// GoccyGoYaml is set to true in order to let Helmfile use
 | ||||||
|  | 	// goccy/go-yaml instead of gopkg.in/yaml.v2.
 | ||||||
|  | 	// It's false by default in Helmfile v0.x and true by default for Helmfile v1.x.
 | ||||||
|  | 	GoccyGoYaml bool | ||||||
|  | 
 | ||||||
| 	// We set this via ldflags at build-time so that we can use the
 | 	// We set this via ldflags at build-time so that we can use the
 | ||||||
| 	// value specified at the build time as the runtime default.
 | 	// value specified at the build time as the runtime default.
 | ||||||
| 	v1Mode string | 	v1Mode string | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func Info() string { | func Info() string { | ||||||
| 	return fmt.Sprintf("V1 mode = %v", V1Mode) | 	yamlLib := "gopkg.in/yaml.v2" | ||||||
|  | 	if GoccyGoYaml { | ||||||
|  | 		yamlLib = "goccy/go-yaml" | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return fmt.Sprintf("V1 mode = %v\nYAML library = %v", V1Mode, yamlLib) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func init() { | func init() { | ||||||
|  | @ -34,4 +44,14 @@ func init() { | ||||||
| 	default: | 	default: | ||||||
| 		V1Mode, _ = strconv.ParseBool(v1Mode) | 		V1Mode, _ = strconv.ParseBool(v1Mode) | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
|  | 	// You can switch the YAML library at runtime via an envvar:
 | ||||||
|  | 	switch os.Getenv(envvar.GoccyGoYaml) { | ||||||
|  | 	case "true": | ||||||
|  | 		GoccyGoYaml = true | ||||||
|  | 	case "false": | ||||||
|  | 		GoccyGoYaml = false | ||||||
|  | 	default: | ||||||
|  | 		GoccyGoYaml = V1Mode | ||||||
|  | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -3,6 +3,7 @@ package state | ||||||
| import ( | import ( | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 
 | 
 | ||||||
|  | 	"github.com/helmfile/helmfile/pkg/maputil" | ||||||
| 	"github.com/helmfile/helmfile/pkg/tmpl" | 	"github.com/helmfile/helmfile/pkg/tmpl" | ||||||
| 	"github.com/helmfile/helmfile/pkg/yaml" | 	"github.com/helmfile/helmfile/pkg/yaml" | ||||||
| ) | ) | ||||||
|  | @ -107,13 +108,18 @@ func (r ReleaseSpec) ExecuteTemplateExpressions(renderer *tmpl.FileRenderer) (*R | ||||||
| 					return nil, fmt.Errorf("failed executing template expressions in release \"%s\".values[%d] = \"%v\": %v", r.Name, i, string(serialized), err) | 					return nil, fmt.Errorf("failed executing template expressions in release \"%s\".values[%d] = \"%v\": %v", r.Name, i, string(serialized), err) | ||||||
| 				} | 				} | ||||||
| 
 | 
 | ||||||
| 				var deserialized map[interface{}]interface{} | 				var deserialized map[string]interface{} | ||||||
| 
 | 
 | ||||||
| 				if err := yaml.Unmarshal(s.Bytes(), &deserialized); err != nil { | 				if err := yaml.Unmarshal(s.Bytes(), &deserialized); err != nil { | ||||||
| 					return nil, fmt.Errorf("failed executing template expressions in release \"%s\".values[%d] = \"%v\": %v", r.Name, i, ts, err) | 					return nil, fmt.Errorf("failed executing template expressions in release \"%s\".values[%d] = \"%v\": %v", r.Name, i, ts, err) | ||||||
| 				} | 				} | ||||||
| 
 | 
 | ||||||
| 				result.ValuesTemplate[i] = deserialized | 				m, err := maputil.CastKeysToStrings(deserialized) | ||||||
|  | 				if err != nil { | ||||||
|  | 					return nil, fmt.Errorf("failed executing template expressions in release \"%s\".values[%d] = \"%v\": %v", r.Name, i, ts, err) | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				result.ValuesTemplate[i] = m | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | @ -130,6 +136,12 @@ func (r ReleaseSpec) ExecuteTemplateExpressions(renderer *tmpl.FileRenderer) (*R | ||||||
| 				return nil, fmt.Errorf("failed executing template expressions in release \"%s\".values[%d] = \"%s\": %v", r.Name, i, ts, err) | 				return nil, fmt.Errorf("failed executing template expressions in release \"%s\".values[%d] = \"%s\": %v", r.Name, i, ts, err) | ||||||
| 			} | 			} | ||||||
| 			result.Values[i] = s.String() | 			result.Values[i] = s.String() | ||||||
|  | 		case map[interface{}]interface{}: | ||||||
|  | 			m, err := maputil.CastKeysToStrings(ts) | ||||||
|  | 			if err != nil { | ||||||
|  | 				return nil, fmt.Errorf("failed executing template expressions in release \"%s\".values[%d] = \"%s\": %v", r.Name, i, ts, err) | ||||||
|  | 			} | ||||||
|  | 			result.Values[i] = m | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -121,7 +121,7 @@ func TestHelmState_executeTemplates(t *testing.T) { | ||||||
| 				Verify:    nil, | 				Verify:    nil, | ||||||
| 				Name:      "app", | 				Name:      "app", | ||||||
| 				Namespace: "dev", | 				Namespace: "dev", | ||||||
| 				Values:    []interface{}{map[interface{}]interface{}{"key": "app-val0"}}, | 				Values:    []interface{}{map[string]interface{}{"key": "app-val0"}}, | ||||||
| 			}, | 			}, | ||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -17,6 +17,7 @@ import ( | ||||||
| 
 | 
 | ||||||
| 	"github.com/helmfile/helmfile/pkg/envvar" | 	"github.com/helmfile/helmfile/pkg/envvar" | ||||||
| 	"github.com/helmfile/helmfile/pkg/helmexec" | 	"github.com/helmfile/helmfile/pkg/helmexec" | ||||||
|  | 	"github.com/helmfile/helmfile/pkg/maputil" | ||||||
| 	"github.com/helmfile/helmfile/pkg/yaml" | 	"github.com/helmfile/helmfile/pkg/yaml" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
|  | @ -286,11 +287,17 @@ func ToYaml(v interface{}) (string, error) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func FromYaml(str string) (Values, error) { | func FromYaml(str string) (Values, error) { | ||||||
| 	m := Values{} | 	m := map[string]interface{}{} | ||||||
| 
 | 
 | ||||||
| 	if err := yaml.Unmarshal([]byte(str), &m); err != nil { | 	if err := yaml.Unmarshal([]byte(str), &m); err != nil { | ||||||
| 		return nil, fmt.Errorf("%s, offending yaml: %s", err, str) | 		return nil, fmt.Errorf("%s, offending yaml: %s", err, str) | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
|  | 	m, err := maputil.CastKeysToStrings(m) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, fmt.Errorf("%s, offending yaml: %s", err, str) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	return m, nil | 	return m, nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -5,12 +5,13 @@ import ( | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"io/fs" | 	"io/fs" | ||||||
| 	"path/filepath" | 	"path/filepath" | ||||||
| 	"runtime" | 	goruntime "runtime" | ||||||
| 	"testing" | 	"testing" | ||||||
| 
 | 
 | ||||||
| 	"github.com/stretchr/testify/require" | 	"github.com/stretchr/testify/require" | ||||||
| 
 | 
 | ||||||
| 	"github.com/helmfile/helmfile/pkg/filesystem" | 	"github.com/helmfile/helmfile/pkg/filesystem" | ||||||
|  | 	"github.com/helmfile/helmfile/pkg/runtime" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func TestCreateFuncMap(t *testing.T) { | func TestCreateFuncMap(t *testing.T) { | ||||||
|  | @ -126,7 +127,7 @@ func TestReadDir(t *testing.T) { | ||||||
| 		"sampleDirectory/file3.yaml", | 		"sampleDirectory/file3.yaml", | ||||||
| 	} | 	} | ||||||
| 	var expectedArray []string | 	var expectedArray []string | ||||||
| 	if runtime.GOOS == "windows" { | 	if goruntime.GOOS == "windows" { | ||||||
| 		expectedArray = expectedArrayWindows | 		expectedArray = expectedArrayWindows | ||||||
| 	} else { | 	} else { | ||||||
| 		expectedArray = expectedArrayUnix | 		expectedArray = expectedArrayUnix | ||||||
|  | @ -177,16 +178,29 @@ func TestReadFile_PassAbsPath(t *testing.T) { | ||||||
| 	require.Equal(t, actual, expected) | 	require.Equal(t, actual, expected) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestToYaml_UnsupportedNestedMapKey(t *testing.T) { | func TestToYaml_NestedMapInterfaceKey(t *testing.T) { | ||||||
| 	expected := "foo:\n  bar: BAR\n" | 	v := runtime.GoccyGoYaml | ||||||
|  | 	t.Cleanup(func() { | ||||||
|  | 		runtime.GoccyGoYaml = v | ||||||
|  | 	}) | ||||||
|  | 
 | ||||||
| 	// nolint: unconvert
 | 	// nolint: unconvert
 | ||||||
| 	vals := Values(map[string]interface{}{ | 	vals := Values(map[string]interface{}{ | ||||||
| 		"foo": map[interface{}]interface{}{ | 		"foo": map[interface{}]interface{}{ | ||||||
| 			"bar": "BAR", | 			"bar": "BAR", | ||||||
| 		}, | 		}, | ||||||
| 	}) | 	}) | ||||||
|  | 
 | ||||||
|  | 	runtime.GoccyGoYaml = true | ||||||
|  | 
 | ||||||
| 	actual, err := ToYaml(vals) | 	actual, err := ToYaml(vals) | ||||||
| 	require.Equal(t, expected, actual) | 	require.Equal(t, "foo:\n  bar: BAR\n", actual) | ||||||
|  | 	require.NoError(t, err, "expected nil, but got: %v, when type: map[interface {}]interface {}", err) | ||||||
|  | 
 | ||||||
|  | 	runtime.GoccyGoYaml = false | ||||||
|  | 
 | ||||||
|  | 	actual, err = ToYaml(vals) | ||||||
|  | 	require.Equal(t, "foo:\n  bar: BAR\n", actual) | ||||||
| 	require.NoError(t, err, "expected nil, but got: %v, when type: map[interface {}]interface {}", err) | 	require.NoError(t, err, "expected nil, but got: %v, when type: map[interface {}]interface {}", err) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -205,21 +219,51 @@ func TestToYaml(t *testing.T) { | ||||||
| 	require.Equal(t, expected, actual) | 	require.Equal(t, expected, actual) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestFromYaml(t *testing.T) { | func testFromYaml(t *testing.T, goccyGoYaml bool, expected Values) { | ||||||
|  | 	t.Helper() | ||||||
|  | 
 | ||||||
|  | 	v := runtime.GoccyGoYaml | ||||||
|  | 	runtime.GoccyGoYaml = goccyGoYaml | ||||||
|  | 	t.Cleanup(func() { | ||||||
|  | 		runtime.GoccyGoYaml = v | ||||||
|  | 	}) | ||||||
|  | 
 | ||||||
| 	raw := `foo: | 	raw := `foo: | ||||||
|   bar: BAR |   bar: BAR | ||||||
| ` | ` | ||||||
| 	// nolint: unconvert
 |  | ||||||
| 	expected := Values(map[string]interface{}{ |  | ||||||
| 		"foo": map[string]interface{}{ |  | ||||||
| 			"bar": "BAR", |  | ||||||
| 		}, |  | ||||||
| 	}) |  | ||||||
| 	actual, err := FromYaml(raw) | 	actual, err := FromYaml(raw) | ||||||
| 	require.NoError(t, err) | 	require.NoError(t, err) | ||||||
| 	require.Equal(t, expected, actual) | 	require.Equal(t, expected, actual) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func TestFromYaml(t *testing.T) { | ||||||
|  | 	t.Run("with goccy/go-yaml", func(t *testing.T) { | ||||||
|  | 		testFromYaml( | ||||||
|  | 			t, | ||||||
|  | 			true, | ||||||
|  | 			// nolint: unconvert
 | ||||||
|  | 			Values(map[string]interface{}{ | ||||||
|  | 				"foo": map[string]interface{}{ | ||||||
|  | 					"bar": "BAR", | ||||||
|  | 				}, | ||||||
|  | 			}), | ||||||
|  | 		) | ||||||
|  | 	}) | ||||||
|  | 
 | ||||||
|  | 	t.Run("with gopkg.in/yaml.v2", func(t *testing.T) { | ||||||
|  | 		testFromYaml( | ||||||
|  | 			t, | ||||||
|  | 			false, | ||||||
|  | 			// nolint: unconvert
 | ||||||
|  | 			Values(map[string]interface{}{ | ||||||
|  | 				"foo": map[string]interface{}{ | ||||||
|  | 					"bar": "BAR", | ||||||
|  | 				}, | ||||||
|  | 			}), | ||||||
|  | 		) | ||||||
|  | 	}) | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func TestFromYamlToJson(t *testing.T) { | func TestFromYamlToJson(t *testing.T) { | ||||||
| 	input := `foo: | 	input := `foo: | ||||||
|   bar: BAR |   bar: BAR | ||||||
|  |  | ||||||
|  | @ -6,12 +6,8 @@ import ( | ||||||
| 
 | 
 | ||||||
| 	"github.com/goccy/go-yaml" | 	"github.com/goccy/go-yaml" | ||||||
| 	v2 "gopkg.in/yaml.v2" | 	v2 "gopkg.in/yaml.v2" | ||||||
| ) |  | ||||||
| 
 | 
 | ||||||
| var ( | 	"github.com/helmfile/helmfile/pkg/runtime" | ||||||
| 	// We'll derive the default from the build once
 |  | ||||||
| 	// is merged
 |  | ||||||
| 	GoccyGoYaml bool = true |  | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| type Encoder interface { | type Encoder interface { | ||||||
|  | @ -21,7 +17,7 @@ type Encoder interface { | ||||||
| 
 | 
 | ||||||
| // NewEncoder creates and returns a function that is used to encode a Go object to a YAML document
 | // NewEncoder creates and returns a function that is used to encode a Go object to a YAML document
 | ||||||
| func NewEncoder(w io.Writer) Encoder { | func NewEncoder(w io.Writer) Encoder { | ||||||
| 	if GoccyGoYaml { | 	if runtime.GoccyGoYaml { | ||||||
| 		return yaml.NewEncoder(w) | 		return yaml.NewEncoder(w) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -29,7 +25,7 @@ func NewEncoder(w io.Writer) Encoder { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func Unmarshal(data []byte, v interface{}) error { | func Unmarshal(data []byte, v interface{}) error { | ||||||
| 	if GoccyGoYaml { | 	if runtime.GoccyGoYaml { | ||||||
| 		return yaml.Unmarshal(data, v) | 		return yaml.Unmarshal(data, v) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -41,7 +37,7 @@ func Unmarshal(data []byte, v interface{}) error { | ||||||
| // When strict is true, this function ensures that every field found in the YAML document
 | // When strict is true, this function ensures that every field found in the YAML document
 | ||||||
| // to have the corresponding field in the decoded Go struct.
 | // to have the corresponding field in the decoded Go struct.
 | ||||||
| func NewDecoder(data []byte, strict bool) func(interface{}) error { | func NewDecoder(data []byte, strict bool) func(interface{}) error { | ||||||
| 	if GoccyGoYaml { | 	if runtime.GoccyGoYaml { | ||||||
| 		var opts []yaml.DecodeOption | 		var opts []yaml.DecodeOption | ||||||
| 		if strict { | 		if strict { | ||||||
| 			opts = append(opts, yaml.DisallowUnknownField()) | 			opts = append(opts, yaml.DisallowUnknownField()) | ||||||
|  | @ -66,11 +62,10 @@ func NewDecoder(data []byte, strict bool) func(interface{}) error { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func Marshal(v interface{}) ([]byte, error) { | func Marshal(v interface{}) ([]byte, error) { | ||||||
| 	if GoccyGoYaml { | 	if runtime.GoccyGoYaml { | ||||||
| 		var b bytes.Buffer | 		var b bytes.Buffer | ||||||
| 		yamlEncoder := yaml.NewEncoder( | 		yamlEncoder := yaml.NewEncoder( | ||||||
| 			&b, | 			&b, | ||||||
| 			yaml.IndentSequence(true), |  | ||||||
| 			yaml.Indent(2), | 			yaml.Indent(2), | ||||||
| 		) | 		) | ||||||
| 		err := yamlEncoder.Encode(v) | 		err := yamlEncoder.Encode(v) | ||||||
|  |  | ||||||
|  | @ -4,9 +4,19 @@ import ( | ||||||
| 	"testing" | 	"testing" | ||||||
| 
 | 
 | ||||||
| 	"github.com/stretchr/testify/require" | 	"github.com/stretchr/testify/require" | ||||||
|  | 
 | ||||||
|  | 	"github.com/helmfile/helmfile/pkg/runtime" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func TestYamlMarshal(t *testing.T) { | func testYamlMarshal(t *testing.T, goccyGoYaml bool) { | ||||||
|  | 	t.Helper() | ||||||
|  | 
 | ||||||
|  | 	v := runtime.GoccyGoYaml | ||||||
|  | 	runtime.GoccyGoYaml = goccyGoYaml | ||||||
|  | 	t.Cleanup(func() { | ||||||
|  | 		runtime.GoccyGoYaml = v | ||||||
|  | 	}) | ||||||
|  | 
 | ||||||
| 	tests := []struct { | 	tests := []struct { | ||||||
| 		Name string `yaml:"name"` | 		Name string `yaml:"name"` | ||||||
| 		Info []struct { | 		Info []struct { | ||||||
|  | @ -22,7 +32,7 @@ func TestYamlMarshal(t *testing.T) { | ||||||
| 				Age     int    `yaml:"age"` | 				Age     int    `yaml:"age"` | ||||||
| 				Address string `yaml:"address"` | 				Address string `yaml:"address"` | ||||||
| 			}{{Age: 20, Address: "New York"}}, | 			}{{Age: 20, Address: "New York"}}, | ||||||
| 			expected: "name: John\ninfo:\n  - age: 20\n    address: New York\n", | 			expected: "name: John\ninfo:\n- age: 20\n  address: New York\n", | ||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -32,3 +42,13 @@ func TestYamlMarshal(t *testing.T) { | ||||||
| 		require.Equal(t, tt.expected, string(actual)) | 		require.Equal(t, tt.expected, string(actual)) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | func TestYamlMarshal(t *testing.T) { | ||||||
|  | 	t.Run("with goccy/go-yaml", func(t *testing.T) { | ||||||
|  | 		testYamlMarshal(t, true) | ||||||
|  | 	}) | ||||||
|  | 
 | ||||||
|  | 	t.Run("with gopkg.in/yaml.v2", func(t *testing.T) { | ||||||
|  | 		testYamlMarshal(t, false) | ||||||
|  | 	}) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -8,7 +8,8 @@ import ( | ||||||
| 	"os/exec" | 	"os/exec" | ||||||
| 	"path/filepath" | 	"path/filepath" | ||||||
| 	"regexp" | 	"regexp" | ||||||
| 	"runtime" | 	goruntime "runtime" | ||||||
|  | 	"strconv" | ||||||
| 	"strings" | 	"strings" | ||||||
| 	"testing" | 	"testing" | ||||||
| 	"time" | 	"time" | ||||||
|  | @ -57,6 +58,18 @@ func (f fakeInit) Force() bool { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestHelmfileTemplateWithBuildCommand(t *testing.T) { | func TestHelmfileTemplateWithBuildCommand(t *testing.T) { | ||||||
|  | 	t.Run("with goccy/go-yaml", func(t *testing.T) { | ||||||
|  | 		testHelmfileTemplateWithBuildCommand(t, true) | ||||||
|  | 	}) | ||||||
|  | 
 | ||||||
|  | 	t.Run("with gopkg.in/yaml.v2", func(t *testing.T) { | ||||||
|  | 		testHelmfileTemplateWithBuildCommand(t, false) | ||||||
|  | 	}) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func testHelmfileTemplateWithBuildCommand(t *testing.T, goccyGoYaml bool) { | ||||||
|  | 	t.Setenv(envvar.GoccyGoYaml, strconv.FormatBool(goccyGoYaml)) | ||||||
|  | 
 | ||||||
| 	localChartPortSets := make(map[int]struct{}) | 	localChartPortSets := make(map[int]struct{}) | ||||||
| 
 | 
 | ||||||
| 	logger := helmexec.NewLogger(os.Stderr, "info") | 	logger := helmexec.NewLogger(os.Stderr, "info") | ||||||
|  | @ -69,10 +82,10 @@ func TestHelmfileTemplateWithBuildCommand(t *testing.T) { | ||||||
| 	err := helmfileInit.CheckHelmPlugins() | 	err := helmfileInit.CheckHelmPlugins() | ||||||
| 	require.NoError(t, err) | 	require.NoError(t, err) | ||||||
| 
 | 
 | ||||||
| 	_, filename, _, _ := runtime.Caller(0) | 	_, filename, _, _ := goruntime.Caller(0) | ||||||
| 	projectRoot := filepath.Join(filepath.Dir(filename), "..", "..", "..", "..") | 	projectRoot := filepath.Join(filepath.Dir(filename), "..", "..", "..", "..") | ||||||
| 	helmfileBin := filepath.Join(projectRoot, "helmfile") | 	helmfileBin := filepath.Join(projectRoot, "helmfile") | ||||||
| 	if runtime.GOOS == "windows" { | 	if goruntime.GOOS == "windows" { | ||||||
| 		helmfileBin = helmfileBin + ".exe" | 		helmfileBin = helmfileBin + ".exe" | ||||||
| 	} | 	} | ||||||
| 	testdataDir := "testdata/snapshot" | 	testdataDir := "testdata/snapshot" | ||||||
|  | @ -200,6 +213,15 @@ func TestHelmfileTemplateWithBuildCommand(t *testing.T) { | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
|  | 			tmpDir := t.TempDir() | ||||||
|  | 			// HELM_CACHE_HOME contains downloaded chart archives
 | ||||||
|  | 			helmCacheHome := filepath.Join(tmpDir, "helm_cache") | ||||||
|  | 			// HELMFILE_CACHE_HOME contains remote charts and manifests downloaded by Helmfile using the go-getter integration
 | ||||||
|  | 			helmfileCacheHome := filepath.Join(tmpDir, "helmfile_cache") | ||||||
|  | 			// HELM_CONFIG_HOME contains the registry auth file (registry.json) and the index of all the repos added via helm-repo-add (repositories.yaml).
 | ||||||
|  | 			helmConfigHome := filepath.Join(tmpDir, "helm_config") | ||||||
|  | 			t.Logf("Using HELM_CACHE_HOME=%s, HELMFILE_CACHE_HOME=%s, HELM_CONFIG_HOME=%s", helmCacheHome, helmfileCacheHome, helmConfigHome) | ||||||
|  | 
 | ||||||
| 			inputFile := filepath.Join(testdataDir, name, "input.yaml") | 			inputFile := filepath.Join(testdataDir, name, "input.yaml") | ||||||
| 			outputFile := filepath.Join(testdataDir, name, "output.yaml") | 			outputFile := filepath.Join(testdataDir, name, "output.yaml") | ||||||
| 
 | 
 | ||||||
|  | @ -214,6 +236,9 @@ func TestHelmfileTemplateWithBuildCommand(t *testing.T) { | ||||||
| 				cmd.Env, | 				cmd.Env, | ||||||
| 				envvar.TempDir+"=/tmp/helmfile", | 				envvar.TempDir+"=/tmp/helmfile", | ||||||
| 				envvar.DisableRunnerUniqueID+"=1", | 				envvar.DisableRunnerUniqueID+"=1", | ||||||
|  | 				"HELM_CACHE_HOME="+helmCacheHome, | ||||||
|  | 				"HELM_CONFIG_HOME="+helmConfigHome, | ||||||
|  | 				"HELMFILE_CACHE_HOME="+helmfileCacheHome, | ||||||
| 			) | 			) | ||||||
| 			got, err := cmd.CombinedOutput() | 			got, err := cmd.CombinedOutput() | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
|  | @ -231,6 +256,9 @@ func TestHelmfileTemplateWithBuildCommand(t *testing.T) { | ||||||
| 			gotStr = chartGitFullPathRegex.ReplaceAllString(gotStr, `chart=$$GoGetterPath`) | 			gotStr = chartGitFullPathRegex.ReplaceAllString(gotStr, `chart=$$GoGetterPath`) | ||||||
| 			// Replace helm version with $HelmVersion
 | 			// Replace helm version with $HelmVersion
 | ||||||
| 			gotStr = helmShortVersionRegex.ReplaceAllString(gotStr, `$$HelmVersion`) | 			gotStr = helmShortVersionRegex.ReplaceAllString(gotStr, `$$HelmVersion`) | ||||||
|  | 			// Replace all occurrences of HELMFILE_CACHE_HOME with /home/runner/.cache/helmfile
 | ||||||
|  | 			// for stable test result
 | ||||||
|  | 			gotStr = strings.ReplaceAll(gotStr, helmfileCacheHome, "/home/runner/.cache/helmfile") | ||||||
| 
 | 
 | ||||||
| 			// OCI based helm charts are pulled and exported under temporary directory.
 | 			// OCI based helm charts are pulled and exported under temporary directory.
 | ||||||
| 			// We are not sure the exact name of the temporary directory generated by helmfile,
 | 			// We are not sure the exact name of the temporary directory generated by helmfile,
 | ||||||
|  |  | ||||||
|  | @ -6,23 +6,23 @@ helmBinary: helm | ||||||
| environments: | environments: | ||||||
|   default: {} |   default: {} | ||||||
| repositories: | repositories: | ||||||
|   - name: aservo | - name: aservo | ||||||
|     url: https://aservo.github.io/charts |   url: https://aservo.github.io/charts | ||||||
| releases: | releases: | ||||||
|   - chart: aservo/util | - chart: aservo/util | ||||||
|     version: 0.0.1 |   version: 0.0.1 | ||||||
|     name: default-shared-resources |   name: default-shared-resources | ||||||
|     namespace: default |   namespace: default | ||||||
|     labels: |   labels: | ||||||
|       service: shared-resources |     service: shared-resources | ||||||
|   - chart: aservo/util | - chart: aservo/util | ||||||
|     version: 0.0.1 |   version: 0.0.1 | ||||||
|     needs: |   needs: | ||||||
|       - default/default-shared-resources |   - default/default-shared-resources | ||||||
|     name: default-release-resources |   name: default-release-resources | ||||||
|     namespace: default |   namespace: default | ||||||
|     labels: |   labels: | ||||||
|       service: release-resources |     service: release-resources | ||||||
| templates: | templates: | ||||||
|   defaults: |   defaults: | ||||||
|     name: default-{{ .Release.Labels.service }} |     name: default-{{ .Release.Labels.service }} | ||||||
|  |  | ||||||
|  | @ -1,8 +1,4 @@ | ||||||
| Building dependency release=foo, chart=$WD/temp1/foo | Building dependency release=foo, chart=$WD/temp1/foo | ||||||
| Hang tight while we grab the latest from your chart repositories... |  | ||||||
| ...Successfully got an update from the "myrepo" chart repository |  | ||||||
| ...Successfully got an update from the "istio" chart repository |  | ||||||
| Update Complete. ⎈Happy Helming!⎈ |  | ||||||
| Saving 1 charts | Saving 1 charts | ||||||
| Downloading raw from repo oci://localhost:5000/myrepo | Downloading raw from repo oci://localhost:5000/myrepo | ||||||
| Deleting outdated charts | Deleting outdated charts | ||||||
|  |  | ||||||
|  | @ -1,9 +1,5 @@ | ||||||
| Building dependency release=foo, chart=../../charts/raw-0.1.0 | Building dependency release=foo, chart=../../charts/raw-0.1.0 | ||||||
| Building dependency release=baz, chart=$WD/temp1/baz | Building dependency release=baz, chart=$WD/temp1/baz | ||||||
| Hang tight while we grab the latest from your chart repositories... |  | ||||||
| ...Successfully got an update from the "myrepo" chart repository |  | ||||||
| ...Successfully got an update from the "istio" chart repository |  | ||||||
| Update Complete. ⎈Happy Helming!⎈ |  | ||||||
| Saving 1 charts | Saving 1 charts | ||||||
| Downloading raw from repo oci://localhost:5001/myrepo | Downloading raw from repo oci://localhost:5001/myrepo | ||||||
| Deleting outdated charts | Deleting outdated charts | ||||||
|  |  | ||||||
|  | @ -1,4 +1,3 @@ | ||||||
| helmfileArgs: | helmfileArgs: | ||||||
| - template | - template | ||||||
| - --debug |  | ||||||
| - --concurrency=1 | - --concurrency=1 | ||||||
|  |  | ||||||
|  | @ -1,103 +1,5 @@ | ||||||
| processing file "input.yaml" in directory "testdata/snapshot/pr_560" |  | ||||||
| changing working directory to "/home/runner/work/helmfile/helmfile/test/e2e/template/helmfile/testdata/snapshot/pr_560" |  | ||||||
| first-pass rendering starting for "input.yaml.part.0": inherited=&{default map[] map[]}, overrode=<nil> |  | ||||||
| first-pass uses: &{default map[] map[]} |  | ||||||
| first-pass rendering output of "input.yaml.part.0": |  | ||||||
|  0: releases: |  | ||||||
|  1: - name: foo |  | ||||||
|  2:   chart: ../../charts/raw-0.1.0 |  | ||||||
|  3:   values: |  | ||||||
|  4:   - templates: |  | ||||||
|  5:       - | |  | ||||||
|  6:         apiVersion: v1 |  | ||||||
|  7:         kind: ConfigMap |  | ||||||
|  8:         metadata: |  | ||||||
|  9:           name: {{ .Release.Name }}-1 |  | ||||||
| 10:           namespace: {{ .Release.Namespace }} |  | ||||||
| 11:         data: |  | ||||||
| 12:           foo: FOO |  | ||||||
| 13:   - git::https://github.com/helmfile/helmfile.git@test/e2e/template/helmfile/testdata/snapshot/pr_560/values.yaml?ref=main |  | ||||||
| 14:   secrets: |  | ||||||
| 15:   - git::https://github.com/helmfile/helmfile.git@test/e2e/template/helmfile/testdata/snapshot/pr_560/secrets.yaml?ref=main |  | ||||||
| 16:   missingFileHandler: Debug |  | ||||||
| 17:  |  | ||||||
| 
 |  | ||||||
| first-pass produced: &{default map[] map[]} |  | ||||||
| first-pass rendering result of "input.yaml.part.0": {default map[] map[]} |  | ||||||
| vals: |  | ||||||
| map[] |  | ||||||
| defaultVals:[] |  | ||||||
| second-pass rendering result of "input.yaml.part.0": |  | ||||||
|  0: releases: |  | ||||||
|  1: - name: foo |  | ||||||
|  2:   chart: ../../charts/raw-0.1.0 |  | ||||||
|  3:   values: |  | ||||||
|  4:   - templates: |  | ||||||
|  5:       - | |  | ||||||
|  6:         apiVersion: v1 |  | ||||||
|  7:         kind: ConfigMap |  | ||||||
|  8:         metadata: |  | ||||||
|  9:           name: {{ .Release.Name }}-1 |  | ||||||
| 10:           namespace: {{ .Release.Namespace }} |  | ||||||
| 11:         data: |  | ||||||
| 12:           foo: FOO |  | ||||||
| 13:   - git::https://github.com/helmfile/helmfile.git@test/e2e/template/helmfile/testdata/snapshot/pr_560/values.yaml?ref=main |  | ||||||
| 14:   secrets: |  | ||||||
| 15:   - git::https://github.com/helmfile/helmfile.git@test/e2e/template/helmfile/testdata/snapshot/pr_560/secrets.yaml?ref=main |  | ||||||
| 16:   missingFileHandler: Debug |  | ||||||
| 17:  |  | ||||||
| 
 |  | ||||||
| merged environment: &{default map[] map[]} |  | ||||||
| helm> $HelmVersion |  | ||||||
| helm>  |  | ||||||
| Building dependency release=foo, chart=../../charts/raw-0.1.0 | Building dependency release=foo, chart=../../charts/raw-0.1.0 | ||||||
| exec: helm dependency build ../../charts/raw-0.1.0 |  | ||||||
| 1 release(s) found in input.yaml |  | ||||||
| 
 |  | ||||||
| processing 1 groups of releases in this order: |  | ||||||
| GROUP RELEASES |  | ||||||
| 1     foo |  | ||||||
| 
 |  | ||||||
| processing releases in group 1/1: foo |  | ||||||
| remote> getter: git |  | ||||||
| remote> scheme: https |  | ||||||
| remote> user:  |  | ||||||
| remote> host: github.com |  | ||||||
| remote> dir: /helmfile/helmfile.git |  | ||||||
| remote> file: test/e2e/template/helmfile/testdata/snapshot/pr_560/values.yaml |  | ||||||
| remote> home: /home/runner/.cache/helmfile |  | ||||||
| remote> getter dest: values/https_github_com_helmfile_helmfile_git.ref=main |  | ||||||
| remote> cached dir: /home/runner/.cache/helmfile/values/https_github_com_helmfile_helmfile_git.ref=main |  | ||||||
| remote> downloading git::https://github.com/helmfile/helmfile.git?ref=main to values/https_github_com_helmfile_helmfile_git.ref=main |  | ||||||
| client: {Ctx:context.Background Src:git::https://github.com/helmfile/helmfile.git?ref=main Dst:/home/runner/.cache/helmfile/values/https_github_com_helmfile_helmfile_git.ref=main Pwd:/home/runner/.cache/helmfile Mode:3 Umask:---------- Detectors:[] Decompressors:map[] Getters:map[] Dir:false ProgressListener:<nil> Insecure:false DisableSymlinks:false Options:[]} |  | ||||||
| skipping missing values file matching "git::https://github.com/helmfile/helmfile.git@test/e2e/template/helmfile/testdata/snapshot/pr_560/values.yaml?ref=main" |  | ||||||
| remote> getter: git |  | ||||||
| remote> scheme: https |  | ||||||
| remote> user:  |  | ||||||
| remote> host: github.com |  | ||||||
| remote> dir: /helmfile/helmfile.git |  | ||||||
| remote> file: test/e2e/template/helmfile/testdata/snapshot/pr_560/secrets.yaml |  | ||||||
| remote> home: /home/runner/.cache/helmfile |  | ||||||
| remote> getter dest: values/https_github_com_helmfile_helmfile_git.ref=main |  | ||||||
| remote> cached dir: /home/runner/.cache/helmfile/values/https_github_com_helmfile_helmfile_git.ref=main |  | ||||||
| skipping missing secrets file matching "git::https://github.com/helmfile/helmfile.git@test/e2e/template/helmfile/testdata/snapshot/pr_560/secrets.yaml?ref=main" |  | ||||||
| Templating release=foo, chart=../../charts/raw-0.1.0 | Templating release=foo, chart=../../charts/raw-0.1.0 | ||||||
| exec: helm template foo ../../charts/raw-0.1.0 --values /tmp/helmfile/foo-values-d459bc67c --debug |  | ||||||
| helm> install.go:192: [debug] Original chart version: "" |  | ||||||
| helm>  |  | ||||||
| helm> install.go:209: [debug] CHART PATH: /home/runner/work/helmfile/helmfile/test/e2e/template/helmfile/testdata/charts/raw-0.1.0 |  | ||||||
| helm>  |  | ||||||
| helm>  |  | ||||||
| helm> --- |  | ||||||
| helm> # Source: raw/templates/resources.yaml |  | ||||||
| helm> apiVersion: v1 |  | ||||||
| helm> kind: ConfigMap |  | ||||||
| helm> metadata: |  | ||||||
| helm> name: foo-1 |  | ||||||
| helm> namespace: default |  | ||||||
| helm> data: |  | ||||||
| helm> foo: FOO |  | ||||||
| helm>  |  | ||||||
| --- | --- | ||||||
| # Source: raw/templates/resources.yaml | # Source: raw/templates/resources.yaml | ||||||
| apiVersion: v1 | apiVersion: v1 | ||||||
|  | @ -108,6 +10,3 @@ metadata: | ||||||
| data: | data: | ||||||
|   foo: FOO |   foo: FOO | ||||||
| 
 | 
 | ||||||
| Removed /tmp/helmfile/foo-values-d459bc67c |  | ||||||
| Removed /tmp/helmfile |  | ||||||
| changing working directory back to "/home/runner/work/helmfile/helmfile/test/e2e/template/helmfile" |  | ||||||
|  |  | ||||||
|  | @ -3,3 +3,5 @@ localChartRepoServer: | ||||||
|   port: 18084 |   port: 18084 | ||||||
| helmfileArgs: | helmfileArgs: | ||||||
| - template | - template | ||||||
|  | # Prevent two releases foo and bar from racing and randomizing the log | ||||||
|  | - --concurrency=1 | ||||||
|  |  | ||||||
|  | @ -12,7 +12,7 @@ templates: | ||||||
|     values: |     values: | ||||||
|     - template1: template1 |     - template1: template1 | ||||||
|     valuesTemplate: |     valuesTemplate: | ||||||
|     - template1Label: "{{` '{{ .Release.Labels.template1 }}' `}}" |     - template1Label: "{{`{{ .Release.Labels.template1 }}`}}" | ||||||
|     labels: |     labels: | ||||||
|       template1: template1 |       template1: template1 | ||||||
|     inherit: |     inherit: | ||||||
|  | @ -23,8 +23,8 @@ templates: | ||||||
|     values: |     values: | ||||||
|     - template2: template2 |     - template2: template2 | ||||||
|     valuesTemplate: |     valuesTemplate: | ||||||
|     - inheritedBaseLabel: "{{` '{{ .Release.Labels.base }}' `}}" |     - inheritedBaseLabel: "{{`{{ .Release.Labels.base }}`}}" | ||||||
|       template2Label: "{{` '{{ .Release.Labels.template2 }}' `}}" |       template2Label: "{{`{{ .Release.Labels.template2 }}`}}" | ||||||
|     labels: |     labels: | ||||||
|       template2: template2 |       template2: template2 | ||||||
|     inherit: |     inherit: | ||||||
|  | @ -46,7 +46,7 @@ releases: | ||||||
|         name: {{`{{ .Release.Name }}`}}-1 |         name: {{`{{ .Release.Name }}`}}-1 | ||||||
|         namespace: {{`{{ .Release.Namespace }}`}} |         namespace: {{`{{ .Release.Namespace }}`}} | ||||||
|       data: |       data: | ||||||
|         {{` {{ .Values | toYaml | nindent 2 }} `}} |         {{` {{ (unset .Values "templates") | toYaml | nindent 2 }} `}} | ||||||
| - name: foo2 | - name: foo2 | ||||||
|   chart: ../../charts/raw-0.1.0 |   chart: ../../charts/raw-0.1.0 | ||||||
|   inherit: |   inherit: | ||||||
|  | @ -60,4 +60,4 @@ releases: | ||||||
|         name: {{`{{ .Release.Name }}`}}-1 |         name: {{`{{ .Release.Name }}`}}-1 | ||||||
|         namespace: {{`{{ .Release.Namespace }}`}} |         namespace: {{`{{ .Release.Namespace }}`}} | ||||||
|       data: |       data: | ||||||
|         {{` {{ .Values | toYaml | nindent 2 }} `}} |         {{` {{ (unset .Values "templates") | toYaml | nindent 2 }} `}} | ||||||
|  | @ -16,9 +16,6 @@ data: | ||||||
|   base: base |   base: base | ||||||
|   template1: template1 |   template1: template1 | ||||||
|   template1Label: template1 |   template1Label: template1 | ||||||
|   templates: |  | ||||||
|   - "apiVersion: v1\nkind: ConfigMap\nmetadata:\n  name: {{ .Release.Name }}-1\n  namespace: |  | ||||||
|     {{ .Release.Namespace }}\ndata:\n   {{ .Values | toYaml | nindent 2 }} \n" |  | ||||||
| 
 | 
 | ||||||
| Templating release=foo2, chart=../../charts/raw-0.1.0 | Templating release=foo2, chart=../../charts/raw-0.1.0 | ||||||
| --- | --- | ||||||
|  | @ -33,13 +30,4 @@ data: | ||||||
|   inheritedBaseLabel: base |   inheritedBaseLabel: base | ||||||
|   template2: template2 |   template2: template2 | ||||||
|   template2Label: template2 |   template2Label: template2 | ||||||
|   templates: |  | ||||||
|   - |- |  | ||||||
|     apiVersion: v1 |  | ||||||
|     kind: ConfigMap |  | ||||||
|     metadata: |  | ||||||
|       name: {{ .Release.Name }}-1 |  | ||||||
|       namespace: {{ .Release.Namespace }} |  | ||||||
|     data: |  | ||||||
|        {{ .Values | toYaml | nindent 2 }} |  | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -2,6 +2,14 @@ if [[ helm_major_version -eq 3 ]]; then | ||||||
|   chart_need_case_input_dir="${cases_dir}/chart-needs/input" |   chart_need_case_input_dir="${cases_dir}/chart-needs/input" | ||||||
|   chart_need_case_output_dir="${cases_dir}/chart-needs/output" |   chart_need_case_output_dir="${cases_dir}/chart-needs/output" | ||||||
| 
 | 
 | ||||||
|  |   config_file="helmfile.yaml" | ||||||
|  |   if [[ ${HELMFILE_V1MODE} = true ]]; then | ||||||
|  |     pushd "${chart_need_case_input_dir}" | ||||||
|  |     mv "${config_file}" "${config_file}.gotmpl" | ||||||
|  |     config_file="${config_file}.gotmpl" | ||||||
|  |     popd | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|   chart_needs_tmp=$(mktemp -d) |   chart_needs_tmp=$(mktemp -d) | ||||||
|   chart_needs_template_reverse=${chart_needs_tmp}/chart.needs.template.log |   chart_needs_template_reverse=${chart_needs_tmp}/chart.needs.template.log | ||||||
|   chart_needs_lint_reverse=${chart_needs_tmp}/chart.needs.lint.log |   chart_needs_lint_reverse=${chart_needs_tmp}/chart.needs.lint.log | ||||||
|  | @ -20,46 +28,46 @@ if [[ helm_major_version -eq 3 ]]; then | ||||||
| 
 | 
 | ||||||
|   for i in $(seq 10); do |   for i in $(seq 10); do | ||||||
|       info "Comparing template/chart-needs #$i" |       info "Comparing template/chart-needs #$i" | ||||||
|       ${helmfile} -f ${chart_need_case_input_dir}/helmfile.yaml template --include-needs > ${chart_needs_template_reverse} || fail "\"helmfile template\" shouldn't fail" |       ${helmfile} -f ${chart_need_case_input_dir}/${config_file} template --include-needs > ${chart_needs_template_reverse} || fail "\"helmfile template\" shouldn't fail" | ||||||
|       ./dyff between -bs ${chart_need_case_output_dir}/template ${chart_needs_template_reverse} || fail "\"helmfile template\" should be consistent" |       ./dyff between -bs ${chart_need_case_output_dir}/template ${chart_needs_template_reverse} || fail "\"helmfile template\" should be consistent" | ||||||
|       echo code=$? |       echo code=$? | ||||||
|   done |   done | ||||||
| 
 | 
 | ||||||
|   for i in $(seq 10); do |   for i in $(seq 10); do | ||||||
|       info "Comparing lint/chart-needs #$i" |       info "Comparing lint/chart-needs #$i" | ||||||
|       ${helmfile} -f ${chart_need_case_input_dir}/helmfile.yaml lint --include-needs | grep -v Linting > ${chart_needs_lint_reverse} || fail "\"helmfile lint\" shouldn't fail" |       ${helmfile} -f ${chart_need_case_input_dir}/${config_file} lint --include-needs | grep -v Linting > ${chart_needs_lint_reverse} || fail "\"helmfile lint\" shouldn't fail" | ||||||
|       diff -u ${lint_out_file} ${chart_needs_lint_reverse} || fail "\"helmfile lint\" should be consistent" |       diff -u ${lint_out_file} ${chart_needs_lint_reverse} || fail "\"helmfile lint\" should be consistent" | ||||||
|       echo code=$? |       echo code=$? | ||||||
|   done |   done | ||||||
| 
 | 
 | ||||||
|   for i in $(seq 10); do |   for i in $(seq 10); do | ||||||
|       info "Comparing diff/chart-needs #$i" |       info "Comparing diff/chart-needs #$i" | ||||||
|       ${helmfile} -f ${chart_need_case_input_dir}/helmfile.yaml diff --include-needs | grep -Ev "Comparing release=azuredisk-csi-storageclass, chart=/tmp/.*/azuredisk-csi-storageclass" > ${chart_needs_diff_reverse} || fail "\"helmfile diff\" shouldn't fail" |       ${helmfile} -f ${chart_need_case_input_dir}/${config_file} diff --include-needs | grep -Ev "Comparing release=azuredisk-csi-storageclass, chart=/tmp/.*/azuredisk-csi-storageclass" > ${chart_needs_diff_reverse} || fail "\"helmfile diff\" shouldn't fail" | ||||||
|       diff -u ${diff_out_file} ${chart_needs_diff_reverse} || fail "\"helmfile diff\" should be consistent" |       diff -u ${diff_out_file} ${chart_needs_diff_reverse} || fail "\"helmfile diff\" should be consistent" | ||||||
|       echo code=$? |       echo code=$? | ||||||
|   done |   done | ||||||
| 
 | 
 | ||||||
|   info "Applying ${chart_need_case_input_dir}/helmfile.yaml" |   info "Applying ${chart_need_case_input_dir}/${config_file}" | ||||||
|   ${helmfile} -f ${chart_need_case_input_dir}/helmfile.yaml  apply --include-needs |   ${helmfile} -f ${chart_need_case_input_dir}/${config_file}  apply --include-needs | ||||||
|   code=$? |   code=$? | ||||||
|   [ ${code} -eq 0 ] || fail "unexpected exit code returned by helmfile apply: want 0, got ${code}" |   [ ${code} -eq 0 ] || fail "unexpected exit code returned by helmfile apply: want 0, got ${code}" | ||||||
| 
 | 
 | ||||||
|   ${kubectl} get storageclass managed-csi -o yaml | grep -q "provisioner: disk.csi.azure.com" || fail "storageclass managed-csi should be created when applying helmfile.yaml" |   ${kubectl} get storageclass managed-csi -o yaml | grep -q "provisioner: disk.csi.azure.com" || fail "storageclass managed-csi should be created when applying helmfile.yaml" | ||||||
| 
 | 
 | ||||||
|   info "Destroying ${chart_need_case_input_dir}/helmfile.yaml" |   info "Destroying ${chart_need_case_input_dir}/${config_file}" | ||||||
|   ${helmfile} -f ${chart_need_case_input_dir}/helmfile.yaml destroy |   ${helmfile} -f ${chart_need_case_input_dir}/${config_file} destroy | ||||||
|   code=$? |   code=$? | ||||||
|   [ ${code} -eq 0 ] || fail "unexpected exit code returned by helmfile destroy: want 0, got ${code}" |   [ ${code} -eq 0 ] || fail "unexpected exit code returned by helmfile destroy: want 0, got ${code}" | ||||||
| 
 | 
 | ||||||
|   info "Syncing ${chart_need_case_input_dir}/helmfile.yaml" |   info "Syncing ${chart_need_case_input_dir}/${config_file}" | ||||||
|   ${helmfile} -f ${chart_need_case_input_dir}/helmfile.yaml  sync --include-needs |   ${helmfile} -f ${chart_need_case_input_dir}/${config_file}  sync --include-needs | ||||||
|   code=$? |   code=$? | ||||||
|   [ ${code} -eq 0 ] || fail "unexpected exit code returned by helmfile apply: want 0, got ${code}" |   [ ${code} -eq 0 ] || fail "unexpected exit code returned by helmfile apply: want 0, got ${code}" | ||||||
| 
 | 
 | ||||||
|   ${kubectl} get storageclass managed-csi -o yaml | grep -q "provisioner: disk.csi.azure.com" || fail "storageclass managed-csi should be created when syncing helmfile.yaml" |   ${kubectl} get storageclass managed-csi -o yaml | grep -q "provisioner: disk.csi.azure.com" || fail "storageclass managed-csi should be created when syncing helmfile.yaml" | ||||||
| 
 | 
 | ||||||
|   info "Destroying ${chart_need_case_input_dir}/helmfile.yaml" |   info "Destroying ${chart_need_case_input_dir}/${config_file}" | ||||||
|   ${helmfile} -f ${chart_need_case_input_dir}/helmfile.yaml destroy |   ${helmfile} -f ${chart_need_case_input_dir}/${config_file} destroy | ||||||
|   code=$? |   code=$? | ||||||
|   [ ${code} -eq 0 ] || fail "unexpected exit code returned by helmfile destroy: want 0, got ${code}" |   [ ${code} -eq 0 ] || fail "unexpected exit code returned by helmfile destroy: want 0, got ${code}" | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -2,22 +2,30 @@ test_start "happypath - simple rollout of httpbin chart" | ||||||
| 
 | 
 | ||||||
| happypath_case_input_dir="${cases_dir}/happypath/input" | happypath_case_input_dir="${cases_dir}/happypath/input" | ||||||
| happypath_case_output_dir="${cases_dir}/happypath/output" | happypath_case_output_dir="${cases_dir}/happypath/output" | ||||||
|  | config_file="happypath.yaml" | ||||||
| 
 | 
 | ||||||
| info "Diffing ${happypath_case_input_dir}/happypath.yaml" | if [[ ${HELMFILE_V1MODE} = true ]]; then | ||||||
| bash -c "${helmfile} -f ${happypath_case_input_dir}/happypath.yaml diff --detailed-exitcode; code="'$?'"; [ "'${code}'" -eq 2 ]" || fail "unexpected exit code returned by helmfile diff" |   pushd "${happypath_case_input_dir}" | ||||||
|  |   mv "${config_file}" "${config_file}.gotmpl" | ||||||
|  |   config_file="${config_file}.gotmpl" | ||||||
|  |   popd | ||||||
|  | fi | ||||||
| 
 | 
 | ||||||
| info "Diffing ${happypath_case_input_dir}/happypath.yaml without color" | info "Diffing ${happypath_case_input_dir}/${config_file}" | ||||||
| bash -c "${helmfile} -f ${happypath_case_input_dir}/happypath.yaml --no-color diff --detailed-exitcode; code="'$?'"; [ "'${code}'" -eq 2 ]" || fail "unexpected exit code returned by helmfile diff" | bash -c "${helmfile} -f ${happypath_case_input_dir}/${config_file} diff --detailed-exitcode; code="'$?'"; [ "'${code}'" -eq 2 ]" || fail "unexpected exit code returned by helmfile diff" | ||||||
| 
 | 
 | ||||||
| info "Diffing ${happypath_case_input_dir}/happypath.yaml with limited context" | info "Diffing ${happypath_case_input_dir}/${config_file} without color" | ||||||
| bash -c "${helmfile} -f ${happypath_case_input_dir}/happypath.yaml diff --context 3 --detailed-exitcode; code="'$?'"; [ "'${code}'" -eq 2 ]" || fail "unexpected exit code returned by helmfile diff" | bash -c "${helmfile} -f ${happypath_case_input_dir}/${config_file} --no-color diff --detailed-exitcode; code="'$?'"; [ "'${code}'" -eq 2 ]" || fail "unexpected exit code returned by helmfile diff" | ||||||
| 
 | 
 | ||||||
| info "Diffing ${happypath_case_input_dir}/happypath.yaml with altered output" | info "Diffing ${happypath_case_input_dir}/${config_file} with limited context" | ||||||
| bash -c "${helmfile} -f ${happypath_case_input_dir}/happypath.yaml diff --output simple --detailed-exitcode; code="'$?'"; [ "'${code}'" -eq 2 ]" || fail "unexpected exit code returned by helmfile diff" | bash -c "${helmfile} -f ${happypath_case_input_dir}/${config_file} diff --context 3 --detailed-exitcode; code="'$?'"; [ "'${code}'" -eq 2 ]" || fail "unexpected exit code returned by helmfile diff" | ||||||
| 
 | 
 | ||||||
| info "Templating ${happypath_case_input_dir}/happypath.yaml" | info "Diffing ${happypath_case_input_dir}/${config_file} with altered output" | ||||||
|  | bash -c "${helmfile} -f ${happypath_case_input_dir}/${config_file} diff --output simple --detailed-exitcode; code="'$?'"; [ "'${code}'" -eq 2 ]" || fail "unexpected exit code returned by helmfile diff" | ||||||
|  | 
 | ||||||
|  | info "Templating ${happypath_case_input_dir}/${config_file}" | ||||||
| rm -rf ${dir}/tmp | rm -rf ${dir}/tmp | ||||||
| ${helmfile} -f ${happypath_case_input_dir}/happypath.yaml --debug template --output-dir tmp | ${helmfile} -f ${happypath_case_input_dir}/${config_file} --debug template --output-dir tmp | ||||||
| code=$? | code=$? | ||||||
| [ ${code} -eq 0 ] || fail "unexpected exit code returned by helmfile template: ${code}" | [ ${code} -eq 0 ] || fail "unexpected exit code returned by helmfile template: ${code}" | ||||||
| for output in $(ls -d ${dir}/tmp/*); do | for output in $(ls -d ${dir}/tmp/*); do | ||||||
|  | @ -30,39 +38,39 @@ for output in $(ls -d ${dir}/tmp/*); do | ||||||
|     done |     done | ||||||
| done | done | ||||||
| 
 | 
 | ||||||
| info "Applying ${happypath_case_input_dir}/happypath.yaml" | info "Applying ${happypath_case_input_dir}/${config_file}" | ||||||
| bash -c "${helmfile} -f ${happypath_case_input_dir}/happypath.yaml apply --detailed-exitcode; code="'$?'"; echo Code: "'$code'"; [ "'${code}'" -eq 2 ]" || fail "unexpected exit code returned by helmfile apply" | bash -c "${helmfile} -f ${happypath_case_input_dir}/${config_file} apply --detailed-exitcode; code="'$?'"; echo Code: "'$code'"; [ "'${code}'" -eq 2 ]" || fail "unexpected exit code returned by helmfile apply" | ||||||
| 
 | 
 | ||||||
| info "Syncing ${happypath_case_input_dir}/happypath.yaml" | info "Syncing ${happypath_case_input_dir}/${config_file}" | ||||||
| ${helmfile} -f ${happypath_case_input_dir}/happypath.yaml sync | ${helmfile} -f ${happypath_case_input_dir}/${config_file} sync | ||||||
| wait_deploy_ready httpbin-httpbin | wait_deploy_ready httpbin-httpbin | ||||||
| retry 5 "curl --fail $(minikube service --url --namespace=${test_ns} httpbin-httpbin)/status/200" | retry 5 "curl --fail $(minikube service --url --namespace=${test_ns} httpbin-httpbin)/status/200" | ||||||
| [ ${retry_result} -eq 0 ] || fail "httpbin failed to return 200 OK" | [ ${retry_result} -eq 0 ] || fail "httpbin failed to return 200 OK" | ||||||
| 
 | 
 | ||||||
| info "Applying ${happypath_case_input_dir}/happypath.yaml" | info "Applying ${happypath_case_input_dir}/${config_file}" | ||||||
| ${helmfile} -f ${happypath_case_input_dir}/happypath.yaml apply --detailed-exitcode | ${helmfile} -f ${happypath_case_input_dir}/${config_file} apply --detailed-exitcode | ||||||
| code=$? | code=$? | ||||||
| [ ${code} -eq 0 ] || fail "unexpected exit code returned by helmfile apply: want 0, got ${code}" | [ ${code} -eq 0 ] || fail "unexpected exit code returned by helmfile apply: want 0, got ${code}" | ||||||
| 
 | 
 | ||||||
| info "Locking dependencies" | info "Locking dependencies" | ||||||
| ${helmfile} -f ${happypath_case_input_dir}/happypath.yaml deps | ${helmfile} -f ${happypath_case_input_dir}/${config_file} deps | ||||||
| code=$? | code=$? | ||||||
| [ ${code} -eq 0 ] || fail "unexpected exit code returned by helmfile deps: ${code}" | [ ${code} -eq 0 ] || fail "unexpected exit code returned by helmfile deps: ${code}" | ||||||
| 
 | 
 | ||||||
| info "Applying ${happypath_case_input_dir}/happypath.yaml with locked dependencies" | info "Applying ${happypath_case_input_dir}/${config_file} with locked dependencies" | ||||||
| ${helmfile} -f ${happypath_case_input_dir}/happypath.yaml apply | ${helmfile} -f ${happypath_case_input_dir}/${config_file} apply | ||||||
| code=$? | code=$? | ||||||
| [ ${code} -eq 0 ] || fail "unexpected exit code returned by helmfile apply: ${code}" | [ ${code} -eq 0 ] || fail "unexpected exit code returned by helmfile apply: ${code}" | ||||||
| ${helm} list --namespace=${test_ns} || fail "unable to list releases" | ${helm} list --namespace=${test_ns} || fail "unable to list releases" | ||||||
| 
 | 
 | ||||||
| info "Deleting release" | info "Deleting release" | ||||||
| ${helmfile} -f ${happypath_case_input_dir}/happypath.yaml delete | ${helmfile} -f ${happypath_case_input_dir}/${config_file} destroy | ||||||
| ${helm} status --namespace=${test_ns} httpbin &> /dev/null && fail "release should not exist anymore after a delete" | ${helm} status --namespace=${test_ns} httpbin &> /dev/null && fail "release should not exist anymore after a delete" | ||||||
| 
 | 
 | ||||||
| info "Ensuring \"helmfile delete\" doesn't fail when no releases installed" | info "Ensuring \"helmfile destroy\" doesn't fail when no releases installed" | ||||||
| ${helmfile} -f ${happypath_case_input_dir}/happypath.yaml delete || fail "\"helmfile delete\" shouldn't fail when there are no installed releases" | ${helmfile} -f ${happypath_case_input_dir}/${config_file} destroy || fail "\"helmfile delete\" shouldn't fail when there are no installed releases" | ||||||
| 
 | 
 | ||||||
| info "Ensuring \"helmfile template\" output does contain only YAML docs" | info "Ensuring \"helmfile template\" output does contain only YAML docs" | ||||||
| (${helmfile} -f ${happypath_case_input_dir}/happypath.yaml template | kubectl apply -f -) || fail "\"helmfile template | kubectl apply -f -\" shouldn't fail" | (${helmfile} -f ${happypath_case_input_dir}/${config_file} template | kubectl apply -f -) || fail "\"helmfile template | kubectl apply -f -\" shouldn't fail" | ||||||
| 
 | 
 | ||||||
| test_pass "happypath" | test_pass "happypath" | ||||||
|  | @ -2,6 +2,14 @@ if [[ helm_major_version -eq 3 ]]; then | ||||||
|   postrender_diff_case_input_dir="${cases_dir}/postrender-diff/input" |   postrender_diff_case_input_dir="${cases_dir}/postrender-diff/input" | ||||||
|   postrender_diff_case_output_dir="${cases_dir}/postrender-diff/output" |   postrender_diff_case_output_dir="${cases_dir}/postrender-diff/output" | ||||||
| 
 | 
 | ||||||
|  |   config_file="helmfile.yaml" | ||||||
|  |   if [[ ${HELMFILE_V1MODE} = true ]]; then | ||||||
|  |     pushd "${postrender_diff_case_input_dir}" | ||||||
|  |     mv "${config_file}" "${config_file}.gotmpl" | ||||||
|  |     config_file="${config_file}.gotmpl" | ||||||
|  |     popd | ||||||
|  |   fi | ||||||
|  | 
 | ||||||
|   postrender_diff_out_file=${postrender_diff_case_output_dir}/result |   postrender_diff_out_file=${postrender_diff_case_output_dir}/result | ||||||
|   if [[ $EXTRA_HELMFILE_FLAGS == *--enable-live-output* ]]; then |   if [[ $EXTRA_HELMFILE_FLAGS == *--enable-live-output* ]]; then | ||||||
|       postrender_diff_out_file=${postrender_diff_case_output_dir}/result-live |       postrender_diff_out_file=${postrender_diff_case_output_dir}/result-live | ||||||
|  | @ -14,7 +22,7 @@ if [[ helm_major_version -eq 3 ]]; then | ||||||
|   info "Comparing postrender diff output ${postrender_diff_reverse} with ${postrender_diff_case_output_dir}/result.yaml" |   info "Comparing postrender diff output ${postrender_diff_reverse} with ${postrender_diff_case_output_dir}/result.yaml" | ||||||
|   for i in $(seq 10); do |   for i in $(seq 10); do | ||||||
|       info "Comparing build/postrender-diff #$i" |       info "Comparing build/postrender-diff #$i" | ||||||
|       ${helmfile} -f ${postrender_diff_case_input_dir}/helmfile.yaml diff --concurrency 1 &> ${postrender_diff_reverse} || fail "\"helmfile diff\" shouldn't fail" |       ${helmfile} -f ${postrender_diff_case_input_dir}/${config_file} diff --concurrency 1 &> ${postrender_diff_reverse} || fail "\"helmfile diff\" shouldn't fail" | ||||||
|       diff -u  ${postrender_diff_out_file} ${postrender_diff_reverse} || fail "\"helmfile diff\" should be consistent" |       diff -u  ${postrender_diff_out_file} ${postrender_diff_reverse} || fail "\"helmfile diff\" should be consistent" | ||||||
|       echo code=$? |       echo code=$? | ||||||
|   done |   done | ||||||
|  |  | ||||||
|  | @ -3,15 +3,37 @@ test_start "regression tests" | ||||||
| 
 | 
 | ||||||
| if [[ helm_major_version -eq 3 ]]; then | if [[ helm_major_version -eq 3 ]]; then | ||||||
|   regression_case_input_dir="${cases_dir}/regression/input" |   regression_case_input_dir="${cases_dir}/regression/input" | ||||||
|  | 
 | ||||||
|   info "https://github.com/roboll/helmfile/issues/1857" |   info "https://github.com/roboll/helmfile/issues/1857" | ||||||
|   (${helmfile} -f ${regression_case_input_dir}/issue.1857.yaml --state-values-set grafanaEnabled=true template | grep grafana 1>/dev/null) || fail "\"helmfile template\" shouldn't include grafana" |   config_file="issue.1857.yaml" | ||||||
|   ! (${helmfile} -f ${regression_case_input_dir}/issue.1857.yaml --state-values-set grafanaEnabled=false template | grep grafana) || fail "\"helmfile template\" shouldn't include grafana" |   if [[ ${HELMFILE_V1MODE} = true ]]; then | ||||||
|  |     pushd "${regression_case_input_dir}" | ||||||
|  |     mv "${config_file}" "${config_file}.gotmpl" | ||||||
|  |     config_file="${config_file}.gotmpl" | ||||||
|  |     popd | ||||||
|  |   fi | ||||||
|  |   (${helmfile} -f ${regression_case_input_dir}/${config_file} --state-values-set grafanaEnabled=true template | grep grafana 1>/dev/null) || fail "\"helmfile template\" shouldn't include grafana" | ||||||
|  |   ! (${helmfile} -f ${regression_case_input_dir}/${config_file} --state-values-set grafanaEnabled=false template | grep grafana) || fail "\"helmfile template\" shouldn't include grafana" | ||||||
| 
 | 
 | ||||||
|   info "https://github.com/roboll/helmfile/issues/1867" |   info "https://github.com/roboll/helmfile/issues/1867" | ||||||
|   (${helmfile} -f ${regression_case_input_dir}/issue.1867.yaml template 1>/dev/null) || fail "\"helmfile template\" shouldn't fail" |   config_file="issue.1867.yaml" | ||||||
|  |   if [[ ${HELMFILE_V1MODE} = true ]]; then | ||||||
|  |     pushd "${regression_case_input_dir}" | ||||||
|  |     mv "${config_file}" "${config_file}.gotmpl" | ||||||
|  |     config_file="${config_file}.gotmpl" | ||||||
|  |     popd | ||||||
|  |   fi | ||||||
|  |   (${helmfile} -f ${regression_case_input_dir}/${config_file} template 1>/dev/null) || fail "\"helmfile template\" shouldn't fail" | ||||||
| 
 | 
 | ||||||
|   info "https://github.com/roboll/helmfile/issues/2118" |   info "https://github.com/roboll/helmfile/issues/2118" | ||||||
|   (${helmfile} -f ${regression_case_input_dir}/issue.2118.yaml template 1>/dev/null) || fail "\"helmfile template\" shouldn't fail" |   config_file="issue.2118.yaml" | ||||||
|  |   if [[ ${HELMFILE_V1MODE} = true ]]; then | ||||||
|  |     pushd "${regression_case_input_dir}" | ||||||
|  |     mv "${config_file}" "${config_file}.gotmpl" | ||||||
|  |     config_file="${config_file}.gotmpl" | ||||||
|  |     popd | ||||||
|  |   fi | ||||||
|  |   (${helmfile} -f ${regression_case_input_dir}/${config_file} template 1>/dev/null) || fail "\"helmfile template\" shouldn't fail" | ||||||
| else | else | ||||||
|   info "There are no regression tests for helm 2 because all the target charts have dropped helm 2 support." |   info "There are no regression tests for helm 2 because all the target charts have dropped helm 2 support." | ||||||
| fi | fi | ||||||
|  |  | ||||||
|  | @ -5,6 +5,13 @@ if [[ helm_major_version -eq 3 ]]; then | ||||||
| 
 | 
 | ||||||
|   secretssops_case_input_dir="${cases_dir}/secretssops/input" |   secretssops_case_input_dir="${cases_dir}/secretssops/input" | ||||||
|   secretssops_case_output_dir="${cases_dir}/secretssops/output" |   secretssops_case_output_dir="${cases_dir}/secretssops/output" | ||||||
|  |   config_file="secretssops.yaml" | ||||||
|  |   if [[ ${HELMFILE_V1MODE} = true ]]; then | ||||||
|  |     pushd "${secretssops_case_input_dir}" | ||||||
|  |     mv "${config_file}" "${config_file}.gotmpl" | ||||||
|  |     config_file="${config_file}.gotmpl" | ||||||
|  |     popd | ||||||
|  |   fi | ||||||
| 
 | 
 | ||||||
|   mkdir -p ${secretssops_case_input_dir}/tmp |   mkdir -p ${secretssops_case_input_dir}/tmp | ||||||
| 
 | 
 | ||||||
|  | @ -19,7 +26,7 @@ if [[ helm_major_version -eq 3 ]]; then | ||||||
| 
 | 
 | ||||||
|   info "Ensure helmfile fails when no helm-secrets is installed" |   info "Ensure helmfile fails when no helm-secrets is installed" | ||||||
|   unset code |   unset code | ||||||
|   ${helmfile} -f ${secretssops_case_input_dir}/secretssops.yaml -e direct build || code="$?"; code="${code:-0}" |   ${helmfile} -f ${secretssops_case_input_dir}/${config_file} -e direct build || code="$?"; code="${code:-0}" | ||||||
|   echo Code: "${code}" |   echo Code: "${code}" | ||||||
|   [ "${code}" -ne 0 ] || fail "\"helmfile build\" should fail without secrets plugin" |   [ "${code}" -ne 0 ] || fail "\"helmfile build\" should fail without secrets plugin" | ||||||
| 
 | 
 | ||||||
|  | @ -31,7 +38,7 @@ if [[ helm_major_version -eq 3 ]]; then | ||||||
|   ${helm} plugin install https://github.com/jkroepke/helm-secrets --version v${HELM_SECRETS_VERSION} |   ${helm} plugin install https://github.com/jkroepke/helm-secrets --version v${HELM_SECRETS_VERSION} | ||||||
| 
 | 
 | ||||||
|   info "Ensure helmfile succeed when helm-secrets is installed" |   info "Ensure helmfile succeed when helm-secrets is installed" | ||||||
|   ${helmfile} -f ${secretssops_case_input_dir}/secretssops.yaml -e direct build || fail "\"helmfile build\" shouldn't fail" |   ${helmfile} -f ${secretssops_case_input_dir}/${config_file} -e direct build || fail "\"helmfile build\" shouldn't fail" | ||||||
| 
 | 
 | ||||||
|   test_pass "secretssops.2" |   test_pass "secretssops.2" | ||||||
| 
 | 
 | ||||||
|  | @ -46,7 +53,7 @@ if [[ helm_major_version -eq 3 ]]; then | ||||||
|   info "Comparing build/direct output ${direct} with ${secretssops_case_output_dir}" |   info "Comparing build/direct output ${direct} with ${secretssops_case_output_dir}" | ||||||
|   for i in $(seq 10); do |   for i in $(seq 10); do | ||||||
|       info "Comparing build/direct #$i" |       info "Comparing build/direct #$i" | ||||||
|       ${helmfile} -f ${secretssops_case_input_dir}/secretssops.yaml -e direct template --skip-deps > ${direct} || fail "\"helmfile template\" shouldn't fail" |       ${helmfile} -f ${secretssops_case_input_dir}/${config_file} -e direct template --skip-deps > ${direct} || fail "\"helmfile template\" shouldn't fail" | ||||||
|       ./dyff between -bs ${secretssops_case_output_dir}/direct.build.yaml ${direct} || fail "\"helmfile template\" should be consistent" |       ./dyff between -bs ${secretssops_case_output_dir}/direct.build.yaml ${direct} || fail "\"helmfile template\" should be consistent" | ||||||
|       echo code=$? |       echo code=$? | ||||||
|   done |   done | ||||||
|  | @ -54,7 +61,7 @@ if [[ helm_major_version -eq 3 ]]; then | ||||||
|   info "Comparing build/reverse output ${direct} with ${secretssops_case_output_dir}" |   info "Comparing build/reverse output ${direct} with ${secretssops_case_output_dir}" | ||||||
|   for i in $(seq 10); do |   for i in $(seq 10); do | ||||||
|       info "Comparing build/reverse #$i" |       info "Comparing build/reverse #$i" | ||||||
|       ${helmfile} -f ${secretssops_case_input_dir}/secretssops.yaml -e reverse template --skip-deps > ${reverse} || fail "\"helmfile template\" shouldn't fail" |       ${helmfile} -f ${secretssops_case_input_dir}/${config_file} -e reverse template --skip-deps > ${reverse} || fail "\"helmfile template\" shouldn't fail" | ||||||
|       ./dyff between -bs ${secretssops_case_output_dir}/reverse.build.yaml ${reverse} || fail "\"helmfile template\" should be consistent" |       ./dyff between -bs ${secretssops_case_output_dir}/reverse.build.yaml ${reverse} || fail "\"helmfile template\" should be consistent" | ||||||
|       echo code=$? |       echo code=$? | ||||||
|   done |   done | ||||||
|  |  | ||||||
|  | @ -1,17 +1,21 @@ | ||||||
| if [[ helm_major_version -eq 3 ]]; then | if [[ helm_major_version -eq 3 ]]; then | ||||||
|   yaml_overwrite_case_input_dir="${cases_dir}/yaml-overwrite/input" |   if [[ ${HELMFILE_V1MODE} = true ]]; then | ||||||
|   yaml_overwrite_case_output_dir="${cases_dir}/yaml-overwrite/output" |     yaml_overwrite_case_input_dir="${cases_dir}/yaml-overwrite/input" | ||||||
|  |     yaml_overwrite_case_output_dir="${cases_dir}/yaml-overwrite/output" | ||||||
| 
 | 
 | ||||||
|   yaml_overwrite_tmp=$(mktemp -d) |     yaml_overwrite_tmp=$(mktemp -d) | ||||||
|   yaml_overwrite_reverse=${yaml_overwrite_tmp}/yaml.override.build.yaml |     yaml_overwrite_reverse=${yaml_overwrite_tmp}/yaml.override.build.yaml | ||||||
| 
 | 
 | ||||||
|   test_start "yaml overwrite feature" |     test_start "yaml overwrite feature" | ||||||
|   info "Comparing yaml overwrite feature output ${yaml_overwrite_reverse} with ${yaml_overwrite_case_output_dir}/overwritten.yaml" |     info "Comparing yaml overwrite feature output ${yaml_overwrite_reverse} with ${yaml_overwrite_case_output_dir}/overwritten.yaml" | ||||||
|   for i in $(seq 10); do |     for i in $(seq 10); do | ||||||
|       info "Comparing build/yaml-overwrite #$i" |         info "Comparing build/yaml-overwrite #$i" | ||||||
|       ${helmfile} -f ${yaml_overwrite_case_input_dir}/issue.657.yaml template --skip-deps > ${yaml_overwrite_reverse} || fail "\"helmfile template\" shouldn't fail" |         ${helmfile} -f ${yaml_overwrite_case_input_dir}/issue.657.yaml.gotmpl template --skip-deps > ${yaml_overwrite_reverse} || fail "\"helmfile template\" shouldn't fail" | ||||||
|       ./dyff between -bs ${yaml_overwrite_case_output_dir}/overwritten.yaml ${yaml_overwrite_reverse} || fail "\"helmfile template\" should be consistent" |         ./dyff between -bs ${yaml_overwrite_case_output_dir}/overwritten.yaml ${yaml_overwrite_reverse} || fail "\"helmfile template\" should be consistent" | ||||||
|       echo code=$? |         echo code=$? | ||||||
|   done |     done | ||||||
|   test_pass "yaml overwrite feature" |     test_pass "yaml overwrite feature" | ||||||
|  |   else | ||||||
|  |     test_pass "[skipped] yaml overwrite feature" | ||||||
|  |   fi | ||||||
| fi | fi | ||||||
		Loading…
	
		Reference in New Issue