diff --git a/pkg/app/app_test.go b/pkg/app/app_test.go index 4fa19032..db4a5b23 100644 --- a/pkg/app/app_test.go +++ b/pkg/app/app_test.go @@ -1522,6 +1522,8 @@ releases: {stateExternal, `{{ if (keys .Environment.Values | has "foo") }}{{ .Environment.Values.foo }}{{ end }}`, `FOO`}, // See https://github.com/roboll/helmfile/issues/624 {stateExternal, `{{ if (keys .Environment.Values | has "bar") }}{{ if (keys .Environment.Values.bar | has "baz") }}{{ .Environment.Values.bar.baz }}{{ end }}{{ end }}`, `BAZ`}, + // See https://github.com/roboll/helmfile/issues/643 + {stateExternal, `{{ range $service := .Environment.Values.services }}{{ $service.name }}{{ if hasKey $service "something" }}{{ $service.something }}{{ end }}{{ end }}`, `xyfalse`}, } for i := range testcases { tc := testcases[i] @@ -1530,7 +1532,12 @@ releases: testFs := state.NewTestFs(map[string]string{ statePath: stateContent, "/path/to/1.yaml": `foo: FOO`, - "/path/to/2.yaml": `bar: { "baz": "BAZ" }`, + "/path/to/2.yaml": `bar: { "baz": "BAZ" } +services: + - name: "x" + - name: "y" + something: false +`, }) app := &App{ readFile: testFs.ReadFile, diff --git a/pkg/maputil/maputil.go b/pkg/maputil/maputil.go index 66b1cd0e..8a1ef45c 100644 --- a/pkg/maputil/maputil.go +++ b/pkg/maputil/maputil.go @@ -15,32 +15,18 @@ func CastKeysToStrings(s interface{}) (map[string]interface{}, error) { return nil, fmt.Errorf("unexpected type of key in map: expected string, got %T: value=%v, map=%v", typed_k, typed_k, src) } - var casted_v interface{} - switch typed_v := v.(type) { - case map[interface{}]interface{}: - tmp, err := CastKeysToStrings(typed_v) - if err != nil { - return nil, err - } - casted_v = tmp - default: - casted_v = typed_v + casted_v, err := recursivelyStringifyMapKey(v) + if err != nil { + return nil, err } new[str_k] = casted_v } case map[string]interface{}: for k, v := range src { - var casted_v interface{} - switch typed_v := v.(type) { - case map[interface{}]interface{}: - tmp, err := CastKeysToStrings(typed_v) - if err != nil { - return nil, err - } - casted_v = tmp - default: - casted_v = typed_v + casted_v, err := recursivelyStringifyMapKey(v) + if err != nil { + return nil, err } new[k] = casted_v @@ -49,6 +35,31 @@ func CastKeysToStrings(s interface{}) (map[string]interface{}, error) { return new, nil } +func recursivelyStringifyMapKey(v interface{}) (interface{}, error) { + var casted_v interface{} + switch typed_v := v.(type) { + case map[interface{}]interface{}, map[string]interface{}: + tmp, err := CastKeysToStrings(typed_v) + if err != nil { + return nil, err + } + casted_v = tmp + case []interface{}: + a := []interface{}{} + for i := range typed_v { + res, err := recursivelyStringifyMapKey(typed_v[i]) + if err != nil { + return nil, err + } + a = append(a, res) + } + casted_v = a + default: + casted_v = typed_v + } + return casted_v, nil +} + func Set(m map[string]interface{}, key []string, value string) map[string]interface{} { if len(key) == 0 { panic(fmt.Errorf("bug: unexpected length of key: %d", len(key)))