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-diff-version: 3.5.0
|
||||
extra-helmfile-flags:
|
||||
v1mode:
|
||||
- helm-version: v3.9.4
|
||||
kustomize-version: v4.5.7
|
||||
# We assume that the helm-secrets plugin is supposed to
|
||||
|
|
@ -71,16 +72,26 @@ jobs:
|
|||
plugin-secrets-version: 4.0.0
|
||||
plugin-diff-version: 3.6.0
|
||||
extra-helmfile-flags:
|
||||
v1mode:
|
||||
- helm-version: v3.10.3
|
||||
kustomize-version: v4.4.1
|
||||
plugin-secrets-version: 3.15.0
|
||||
plugin-diff-version: 3.5.0
|
||||
extra-helmfile-flags:
|
||||
v1mode:
|
||||
- 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:
|
||||
# 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,
|
||||
# enable it via extra-helmfile-flags below.
|
||||
- helm-version: v3.10.3
|
||||
|
|
@ -88,6 +99,7 @@ jobs:
|
|||
plugin-secrets-version: 4.0.0
|
||||
plugin-diff-version: 3.6.0
|
||||
extra-helmfile-flags: "--enable-live-output"
|
||||
v1mode:
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Cache libraries
|
||||
|
|
@ -131,6 +143,7 @@ jobs:
|
|||
HELMFILE_HELM3: 1
|
||||
TERM: xterm
|
||||
EXTRA_HELMFILE_FLAGS: ${{ matrix.extra-helmfile-flags }}
|
||||
HELMFILE_V1MODE: ${{ matrix.v1mode }}
|
||||
run: make integration
|
||||
e2e_tests:
|
||||
needs: tests
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ import (
|
|||
"github.com/helmfile/helmfile/pkg/exectest"
|
||||
ffs "github.com/helmfile/helmfile/pkg/filesystem"
|
||||
"github.com/helmfile/helmfile/pkg/helmexec"
|
||||
"github.com/helmfile/helmfile/pkg/runtime"
|
||||
"github.com/helmfile/helmfile/pkg/testhelper"
|
||||
"github.com/helmfile/helmfile/pkg/yaml"
|
||||
)
|
||||
|
||||
func TestTemplate(t *testing.T) {
|
||||
|
|
@ -309,20 +309,21 @@ releases:
|
|||
}
|
||||
|
||||
func TestTemplate_StrictParsing(t *testing.T) {
|
||||
v := yaml.GoccyGoYaml
|
||||
yaml.GoccyGoYaml = true
|
||||
t.Cleanup(func() {
|
||||
yaml.GoccyGoYaml = v
|
||||
})
|
||||
|
||||
type testcase struct {
|
||||
ns string
|
||||
error string
|
||||
goccyGoYaml bool
|
||||
ns string
|
||||
error string
|
||||
}
|
||||
|
||||
check := func(t *testing.T, tc testcase) {
|
||||
t.Helper()
|
||||
|
||||
v := runtime.GoccyGoYaml
|
||||
runtime.GoccyGoYaml = tc.goccyGoYaml
|
||||
t.Cleanup(func() {
|
||||
runtime.GoccyGoYaml = v
|
||||
})
|
||||
|
||||
var helm = &exectest.Helm{
|
||||
FailOnUnexpectedList: 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{
|
||||
goccyGoYaml: true,
|
||||
error: `in ./helmfile.yaml: failed to read helmfile.yaml: reading document at index 1: [4:3] unknown field "foobar"
|
||||
2 | releases:
|
||||
3 | - name: app1
|
||||
|
|
@ -391,6 +393,14 @@ releases:
|
|||
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) {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import (
|
|||
"path/filepath"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"runtime"
|
||||
goruntime "runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
|
|
@ -25,6 +25,7 @@ import (
|
|||
ffs "github.com/helmfile/helmfile/pkg/filesystem"
|
||||
"github.com/helmfile/helmfile/pkg/helmexec"
|
||||
"github.com/helmfile/helmfile/pkg/remote"
|
||||
"github.com/helmfile/helmfile/pkg/runtime"
|
||||
"github.com/helmfile/helmfile/pkg/state"
|
||||
"github.com/helmfile/helmfile/pkg/testhelper"
|
||||
"github.com/helmfile/helmfile/pkg/testutil"
|
||||
|
|
@ -4338,7 +4339,15 @@ myrelease4 testNamespace true true id:myrelease1 mychart1
|
|||
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{
|
||||
"/path/to/helmfile.yaml": `
|
||||
releases:
|
||||
|
|
@ -4357,7 +4366,7 @@ releases:
|
|||
`,
|
||||
}
|
||||
expectedValues := []interface{}{
|
||||
map[interface{}]interface{}{"val1": "zipkin"},
|
||||
map[string]interface{}{"val1": "zipkin"},
|
||||
map[string]interface{}{"val2": "val2"}}
|
||||
expectedSetValues := []state.SetValue{
|
||||
{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 {
|
||||
_, fn, line, _ := runtime.Caller(1)
|
||||
_, fn, line, _ := goruntime.Caller(1)
|
||||
return fmt.Sprintf("%s:%d", filepath.Base(fn), line)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,4 +10,6 @@ const (
|
|||
Helm3 = "HELMFILE_HELM3"
|
||||
UpgradeNoticeDisabled = "HELMFILE_UPGRADE_NOTICE_DISABLED"
|
||||
V1Mode = "HELMFILE_V1MODE"
|
||||
GoccyGoYaml = "HELMFILE_GOCCY_GOYAML"
|
||||
CacheHome = "HELMFILE_CACHE_HOME"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -27,6 +27,10 @@ func init() {
|
|||
}
|
||||
|
||||
func CacheDir() string {
|
||||
if h := os.Getenv(envvar.CacheHome); h != "" {
|
||||
return h
|
||||
}
|
||||
|
||||
dir, err := os.UserCacheDir()
|
||||
if err != nil {
|
||||
// fall back to relative path with hidden directory
|
||||
|
|
|
|||
|
|
@ -13,13 +13,23 @@ import (
|
|||
var (
|
||||
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
|
||||
// value specified at the build time as the runtime default.
|
||||
v1Mode 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() {
|
||||
|
|
@ -34,4 +44,14 @@ func init() {
|
|||
default:
|
||||
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 (
|
||||
"fmt"
|
||||
|
||||
"github.com/helmfile/helmfile/pkg/maputil"
|
||||
"github.com/helmfile/helmfile/pkg/tmpl"
|
||||
"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)
|
||||
}
|
||||
|
||||
var deserialized map[interface{}]interface{}
|
||||
var deserialized map[string]interface{}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
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,
|
||||
Name: "app",
|
||||
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/helmexec"
|
||||
"github.com/helmfile/helmfile/pkg/maputil"
|
||||
"github.com/helmfile/helmfile/pkg/yaml"
|
||||
)
|
||||
|
||||
|
|
@ -286,11 +287,17 @@ func ToYaml(v interface{}) (string, error) {
|
|||
}
|
||||
|
||||
func FromYaml(str string) (Values, error) {
|
||||
m := Values{}
|
||||
m := map[string]interface{}{}
|
||||
|
||||
if err := yaml.Unmarshal([]byte(str), &m); err != nil {
|
||||
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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,12 +5,13 @@ import (
|
|||
"fmt"
|
||||
"io/fs"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
goruntime "runtime"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/helmfile/helmfile/pkg/filesystem"
|
||||
"github.com/helmfile/helmfile/pkg/runtime"
|
||||
)
|
||||
|
||||
func TestCreateFuncMap(t *testing.T) {
|
||||
|
|
@ -126,7 +127,7 @@ func TestReadDir(t *testing.T) {
|
|||
"sampleDirectory/file3.yaml",
|
||||
}
|
||||
var expectedArray []string
|
||||
if runtime.GOOS == "windows" {
|
||||
if goruntime.GOOS == "windows" {
|
||||
expectedArray = expectedArrayWindows
|
||||
} else {
|
||||
expectedArray = expectedArrayUnix
|
||||
|
|
@ -177,16 +178,29 @@ func TestReadFile_PassAbsPath(t *testing.T) {
|
|||
require.Equal(t, actual, expected)
|
||||
}
|
||||
|
||||
func TestToYaml_UnsupportedNestedMapKey(t *testing.T) {
|
||||
expected := "foo:\n bar: BAR\n"
|
||||
func TestToYaml_NestedMapInterfaceKey(t *testing.T) {
|
||||
v := runtime.GoccyGoYaml
|
||||
t.Cleanup(func() {
|
||||
runtime.GoccyGoYaml = v
|
||||
})
|
||||
|
||||
// nolint: unconvert
|
||||
vals := Values(map[string]interface{}{
|
||||
"foo": map[interface{}]interface{}{
|
||||
"bar": "BAR",
|
||||
},
|
||||
})
|
||||
|
||||
runtime.GoccyGoYaml = true
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
|
|
@ -205,21 +219,51 @@ func TestToYaml(t *testing.T) {
|
|||
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:
|
||||
bar: BAR
|
||||
`
|
||||
// nolint: unconvert
|
||||
expected := Values(map[string]interface{}{
|
||||
"foo": map[string]interface{}{
|
||||
"bar": "BAR",
|
||||
},
|
||||
})
|
||||
actual, err := FromYaml(raw)
|
||||
require.NoError(t, err)
|
||||
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) {
|
||||
input := `foo:
|
||||
bar: BAR
|
||||
|
|
|
|||
|
|
@ -6,12 +6,8 @@ import (
|
|||
|
||||
"github.com/goccy/go-yaml"
|
||||
v2 "gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
var (
|
||||
// We'll derive the default from the build once
|
||||
// is merged
|
||||
GoccyGoYaml bool = true
|
||||
"github.com/helmfile/helmfile/pkg/runtime"
|
||||
)
|
||||
|
||||
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
|
||||
func NewEncoder(w io.Writer) Encoder {
|
||||
if GoccyGoYaml {
|
||||
if runtime.GoccyGoYaml {
|
||||
return yaml.NewEncoder(w)
|
||||
}
|
||||
|
||||
|
|
@ -29,7 +25,7 @@ func NewEncoder(w io.Writer) Encoder {
|
|||
}
|
||||
|
||||
func Unmarshal(data []byte, v interface{}) error {
|
||||
if GoccyGoYaml {
|
||||
if runtime.GoccyGoYaml {
|
||||
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
|
||||
// to have the corresponding field in the decoded Go struct.
|
||||
func NewDecoder(data []byte, strict bool) func(interface{}) error {
|
||||
if GoccyGoYaml {
|
||||
if runtime.GoccyGoYaml {
|
||||
var opts []yaml.DecodeOption
|
||||
if strict {
|
||||
opts = append(opts, yaml.DisallowUnknownField())
|
||||
|
|
@ -66,11 +62,10 @@ func NewDecoder(data []byte, strict bool) func(interface{}) error {
|
|||
}
|
||||
|
||||
func Marshal(v interface{}) ([]byte, error) {
|
||||
if GoccyGoYaml {
|
||||
if runtime.GoccyGoYaml {
|
||||
var b bytes.Buffer
|
||||
yamlEncoder := yaml.NewEncoder(
|
||||
&b,
|
||||
yaml.IndentSequence(true),
|
||||
yaml.Indent(2),
|
||||
)
|
||||
err := yamlEncoder.Encode(v)
|
||||
|
|
|
|||
|
|
@ -4,9 +4,19 @@ import (
|
|||
"testing"
|
||||
|
||||
"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 {
|
||||
Name string `yaml:"name"`
|
||||
Info []struct {
|
||||
|
|
@ -22,7 +32,7 @@ func TestYamlMarshal(t *testing.T) {
|
|||
Age int `yaml:"age"`
|
||||
Address string `yaml:"address"`
|
||||
}{{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))
|
||||
}
|
||||
}
|
||||
|
||||
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"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime"
|
||||
goruntime "runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
|
@ -57,6 +58,18 @@ func (f fakeInit) Force() bool {
|
|||
}
|
||||
|
||||
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{})
|
||||
|
||||
logger := helmexec.NewLogger(os.Stderr, "info")
|
||||
|
|
@ -69,10 +82,10 @@ func TestHelmfileTemplateWithBuildCommand(t *testing.T) {
|
|||
err := helmfileInit.CheckHelmPlugins()
|
||||
require.NoError(t, err)
|
||||
|
||||
_, filename, _, _ := runtime.Caller(0)
|
||||
_, filename, _, _ := goruntime.Caller(0)
|
||||
projectRoot := filepath.Join(filepath.Dir(filename), "..", "..", "..", "..")
|
||||
helmfileBin := filepath.Join(projectRoot, "helmfile")
|
||||
if runtime.GOOS == "windows" {
|
||||
if goruntime.GOOS == "windows" {
|
||||
helmfileBin = helmfileBin + ".exe"
|
||||
}
|
||||
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")
|
||||
outputFile := filepath.Join(testdataDir, name, "output.yaml")
|
||||
|
||||
|
|
@ -214,6 +236,9 @@ func TestHelmfileTemplateWithBuildCommand(t *testing.T) {
|
|||
cmd.Env,
|
||||
envvar.TempDir+"=/tmp/helmfile",
|
||||
envvar.DisableRunnerUniqueID+"=1",
|
||||
"HELM_CACHE_HOME="+helmCacheHome,
|
||||
"HELM_CONFIG_HOME="+helmConfigHome,
|
||||
"HELMFILE_CACHE_HOME="+helmfileCacheHome,
|
||||
)
|
||||
got, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
|
|
@ -231,6 +256,9 @@ func TestHelmfileTemplateWithBuildCommand(t *testing.T) {
|
|||
gotStr = chartGitFullPathRegex.ReplaceAllString(gotStr, `chart=$$GoGetterPath`)
|
||||
// Replace helm version with $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.
|
||||
// We are not sure the exact name of the temporary directory generated by helmfile,
|
||||
|
|
|
|||
|
|
@ -6,23 +6,23 @@ helmBinary: helm
|
|||
environments:
|
||||
default: {}
|
||||
repositories:
|
||||
- name: aservo
|
||||
url: https://aservo.github.io/charts
|
||||
- name: aservo
|
||||
url: https://aservo.github.io/charts
|
||||
releases:
|
||||
- chart: aservo/util
|
||||
version: 0.0.1
|
||||
name: default-shared-resources
|
||||
namespace: default
|
||||
labels:
|
||||
service: shared-resources
|
||||
- chart: aservo/util
|
||||
version: 0.0.1
|
||||
needs:
|
||||
- default/default-shared-resources
|
||||
name: default-release-resources
|
||||
namespace: default
|
||||
labels:
|
||||
service: release-resources
|
||||
- chart: aservo/util
|
||||
version: 0.0.1
|
||||
name: default-shared-resources
|
||||
namespace: default
|
||||
labels:
|
||||
service: shared-resources
|
||||
- chart: aservo/util
|
||||
version: 0.0.1
|
||||
needs:
|
||||
- default/default-shared-resources
|
||||
name: default-release-resources
|
||||
namespace: default
|
||||
labels:
|
||||
service: release-resources
|
||||
templates:
|
||||
defaults:
|
||||
name: default-{{ .Release.Labels.service }}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,4 @@
|
|||
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
|
||||
Downloading raw from repo oci://localhost:5000/myrepo
|
||||
Deleting outdated charts
|
||||
|
|
|
|||
|
|
@ -1,9 +1,5 @@
|
|||
Building dependency release=foo, chart=../../charts/raw-0.1.0
|
||||
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
|
||||
Downloading raw from repo oci://localhost:5001/myrepo
|
||||
Deleting outdated charts
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
helmfileArgs:
|
||||
- template
|
||||
- --debug
|
||||
- --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
|
||||
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
|
||||
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
|
||||
apiVersion: v1
|
||||
|
|
@ -108,6 +10,3 @@ metadata:
|
|||
data:
|
||||
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
|
||||
helmfileArgs:
|
||||
- template
|
||||
# Prevent two releases foo and bar from racing and randomizing the log
|
||||
- --concurrency=1
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ templates:
|
|||
values:
|
||||
- template1: template1
|
||||
valuesTemplate:
|
||||
- template1Label: "{{` '{{ .Release.Labels.template1 }}' `}}"
|
||||
- template1Label: "{{`{{ .Release.Labels.template1 }}`}}"
|
||||
labels:
|
||||
template1: template1
|
||||
inherit:
|
||||
|
|
@ -23,8 +23,8 @@ templates:
|
|||
values:
|
||||
- template2: template2
|
||||
valuesTemplate:
|
||||
- inheritedBaseLabel: "{{` '{{ .Release.Labels.base }}' `}}"
|
||||
template2Label: "{{` '{{ .Release.Labels.template2 }}' `}}"
|
||||
- inheritedBaseLabel: "{{`{{ .Release.Labels.base }}`}}"
|
||||
template2Label: "{{`{{ .Release.Labels.template2 }}`}}"
|
||||
labels:
|
||||
template2: template2
|
||||
inherit:
|
||||
|
|
@ -46,7 +46,7 @@ releases:
|
|||
name: {{`{{ .Release.Name }}`}}-1
|
||||
namespace: {{`{{ .Release.Namespace }}`}}
|
||||
data:
|
||||
{{` {{ .Values | toYaml | nindent 2 }} `}}
|
||||
{{` {{ (unset .Values "templates") | toYaml | nindent 2 }} `}}
|
||||
- name: foo2
|
||||
chart: ../../charts/raw-0.1.0
|
||||
inherit:
|
||||
|
|
@ -60,4 +60,4 @@ releases:
|
|||
name: {{`{{ .Release.Name }}`}}-1
|
||||
namespace: {{`{{ .Release.Namespace }}`}}
|
||||
data:
|
||||
{{` {{ .Values | toYaml | nindent 2 }} `}}
|
||||
{{` {{ (unset .Values "templates") | toYaml | nindent 2 }} `}}
|
||||
|
|
@ -16,9 +16,6 @@ data:
|
|||
base: base
|
||||
template1: 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
|
||||
---
|
||||
|
|
@ -33,13 +30,4 @@ data:
|
|||
inheritedBaseLabel: base
|
||||
template2: 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_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_template_reverse=${chart_needs_tmp}/chart.needs.template.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
|
||||
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"
|
||||
echo code=$?
|
||||
done
|
||||
|
||||
for i in $(seq 10); do
|
||||
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"
|
||||
echo code=$?
|
||||
done
|
||||
|
||||
for i in $(seq 10); do
|
||||
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"
|
||||
echo code=$?
|
||||
done
|
||||
|
||||
info "Applying ${chart_need_case_input_dir}/helmfile.yaml"
|
||||
${helmfile} -f ${chart_need_case_input_dir}/helmfile.yaml apply --include-needs
|
||||
info "Applying ${chart_need_case_input_dir}/${config_file}"
|
||||
${helmfile} -f ${chart_need_case_input_dir}/${config_file} apply --include-needs
|
||||
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"
|
||||
|
||||
info "Destroying ${chart_need_case_input_dir}/helmfile.yaml"
|
||||
${helmfile} -f ${chart_need_case_input_dir}/helmfile.yaml destroy
|
||||
info "Destroying ${chart_need_case_input_dir}/${config_file}"
|
||||
${helmfile} -f ${chart_need_case_input_dir}/${config_file} destroy
|
||||
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"
|
||||
${helmfile} -f ${chart_need_case_input_dir}/helmfile.yaml sync --include-needs
|
||||
info "Syncing ${chart_need_case_input_dir}/${config_file}"
|
||||
${helmfile} -f ${chart_need_case_input_dir}/${config_file} sync --include-needs
|
||||
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"
|
||||
|
||||
info "Destroying ${chart_need_case_input_dir}/helmfile.yaml"
|
||||
${helmfile} -f ${chart_need_case_input_dir}/helmfile.yaml destroy
|
||||
info "Destroying ${chart_need_case_input_dir}/${config_file}"
|
||||
${helmfile} -f ${chart_need_case_input_dir}/${config_file} destroy
|
||||
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_output_dir="${cases_dir}/happypath/output"
|
||||
config_file="happypath.yaml"
|
||||
|
||||
info "Diffing ${happypath_case_input_dir}/happypath.yaml"
|
||||
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"
|
||||
if [[ ${HELMFILE_V1MODE} = true ]]; then
|
||||
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"
|
||||
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"
|
||||
info "Diffing ${happypath_case_input_dir}/${config_file}"
|
||||
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"
|
||||
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"
|
||||
info "Diffing ${happypath_case_input_dir}/${config_file} without color"
|
||||
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"
|
||||
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"
|
||||
info "Diffing ${happypath_case_input_dir}/${config_file} with limited context"
|
||||
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
|
||||
${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} -eq 0 ] || fail "unexpected exit code returned by helmfile template: ${code}"
|
||||
for output in $(ls -d ${dir}/tmp/*); do
|
||||
|
|
@ -30,39 +38,39 @@ for output in $(ls -d ${dir}/tmp/*); do
|
|||
done
|
||||
done
|
||||
|
||||
info "Applying ${happypath_case_input_dir}/happypath.yaml"
|
||||
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"
|
||||
info "Applying ${happypath_case_input_dir}/${config_file}"
|
||||
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"
|
||||
${helmfile} -f ${happypath_case_input_dir}/happypath.yaml sync
|
||||
info "Syncing ${happypath_case_input_dir}/${config_file}"
|
||||
${helmfile} -f ${happypath_case_input_dir}/${config_file} sync
|
||||
wait_deploy_ready httpbin-httpbin
|
||||
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"
|
||||
|
||||
info "Applying ${happypath_case_input_dir}/happypath.yaml"
|
||||
${helmfile} -f ${happypath_case_input_dir}/happypath.yaml apply --detailed-exitcode
|
||||
info "Applying ${happypath_case_input_dir}/${config_file}"
|
||||
${helmfile} -f ${happypath_case_input_dir}/${config_file} apply --detailed-exitcode
|
||||
code=$?
|
||||
[ ${code} -eq 0 ] || fail "unexpected exit code returned by helmfile apply: want 0, got ${code}"
|
||||
|
||||
info "Locking dependencies"
|
||||
${helmfile} -f ${happypath_case_input_dir}/happypath.yaml deps
|
||||
${helmfile} -f ${happypath_case_input_dir}/${config_file} 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"
|
||||
${helmfile} -f ${happypath_case_input_dir}/happypath.yaml apply
|
||||
info "Applying ${happypath_case_input_dir}/${config_file} with locked dependencies"
|
||||
${helmfile} -f ${happypath_case_input_dir}/${config_file} apply
|
||||
code=$?
|
||||
[ ${code} -eq 0 ] || fail "unexpected exit code returned by helmfile apply: ${code}"
|
||||
${helm} list --namespace=${test_ns} || fail "unable to list releases"
|
||||
|
||||
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"
|
||||
|
||||
info "Ensuring \"helmfile delete\" 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"
|
||||
info "Ensuring \"helmfile destroy\" doesn't fail when no releases installed"
|
||||
${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"
|
||||
(${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"
|
||||
|
|
@ -2,6 +2,14 @@ if [[ helm_major_version -eq 3 ]]; then
|
|||
postrender_diff_case_input_dir="${cases_dir}/postrender-diff/input"
|
||||
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
|
||||
if [[ $EXTRA_HELMFILE_FLAGS == *--enable-live-output* ]]; then
|
||||
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"
|
||||
for i in $(seq 10); do
|
||||
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"
|
||||
echo code=$?
|
||||
done
|
||||
|
|
|
|||
|
|
@ -3,15 +3,37 @@ test_start "regression tests"
|
|||
|
||||
if [[ helm_major_version -eq 3 ]]; then
|
||||
regression_case_input_dir="${cases_dir}/regression/input"
|
||||
|
||||
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"
|
||||
! (${helmfile} -f ${regression_case_input_dir}/issue.1857.yaml --state-values-set grafanaEnabled=false template | grep grafana) || fail "\"helmfile template\" shouldn't include grafana"
|
||||
config_file="issue.1857.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} --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"
|
||||
(${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"
|
||||
(${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
|
||||
info "There are no regression tests for helm 2 because all the target charts have dropped helm 2 support."
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -5,6 +5,13 @@ if [[ helm_major_version -eq 3 ]]; then
|
|||
|
||||
secretssops_case_input_dir="${cases_dir}/secretssops/input"
|
||||
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
|
||||
|
||||
|
|
@ -19,7 +26,7 @@ if [[ helm_major_version -eq 3 ]]; then
|
|||
|
||||
info "Ensure helmfile fails when no helm-secrets is installed"
|
||||
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}"
|
||||
[ "${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}
|
||||
|
||||
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"
|
||||
|
||||
|
|
@ -46,7 +53,7 @@ if [[ helm_major_version -eq 3 ]]; then
|
|||
info "Comparing build/direct output ${direct} with ${secretssops_case_output_dir}"
|
||||
for i in $(seq 10); do
|
||||
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"
|
||||
echo code=$?
|
||||
done
|
||||
|
|
@ -54,7 +61,7 @@ if [[ helm_major_version -eq 3 ]]; then
|
|||
info "Comparing build/reverse output ${direct} with ${secretssops_case_output_dir}"
|
||||
for i in $(seq 10); do
|
||||
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"
|
||||
echo code=$?
|
||||
done
|
||||
|
|
|
|||
|
|
@ -1,17 +1,21 @@
|
|||
if [[ helm_major_version -eq 3 ]]; then
|
||||
yaml_overwrite_case_input_dir="${cases_dir}/yaml-overwrite/input"
|
||||
yaml_overwrite_case_output_dir="${cases_dir}/yaml-overwrite/output"
|
||||
if [[ ${HELMFILE_V1MODE} = true ]]; then
|
||||
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_reverse=${yaml_overwrite_tmp}/yaml.override.build.yaml
|
||||
yaml_overwrite_tmp=$(mktemp -d)
|
||||
yaml_overwrite_reverse=${yaml_overwrite_tmp}/yaml.override.build.yaml
|
||||
|
||||
test_start "yaml overwrite feature"
|
||||
info "Comparing yaml overwrite feature output ${yaml_overwrite_reverse} with ${yaml_overwrite_case_output_dir}/overwritten.yaml"
|
||||
for i in $(seq 10); do
|
||||
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"
|
||||
./dyff between -bs ${yaml_overwrite_case_output_dir}/overwritten.yaml ${yaml_overwrite_reverse} || fail "\"helmfile template\" should be consistent"
|
||||
echo code=$?
|
||||
done
|
||||
test_pass "yaml overwrite feature"
|
||||
fi
|
||||
test_start "yaml overwrite feature"
|
||||
info "Comparing yaml overwrite feature output ${yaml_overwrite_reverse} with ${yaml_overwrite_case_output_dir}/overwritten.yaml"
|
||||
for i in $(seq 10); do
|
||||
info "Comparing build/yaml-overwrite #$i"
|
||||
${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"
|
||||
echo code=$?
|
||||
done
|
||||
test_pass "yaml overwrite feature"
|
||||
else
|
||||
test_pass "[skipped] yaml overwrite feature"
|
||||
fi
|
||||
fi
|
||||
|
|
|
|||
Loading…
Reference in New Issue