Use gopkg.in/yaml.v2 for Helmfile v0.x#609
Conversation
af1880c to
ca9da1d
Compare
Ref #435 Signed-off-by: Yusuke Kuoka <[email protected]>
ca9da1d to
cf0d5b9
Compare
Signed-off-by: Yusuke Kuoka <[email protected]>
Signed-off-by: Yusuke Kuoka <[email protected]>
1a19e6d to
d12c768
Compare
Signed-off-by: Yusuke Kuoka <[email protected]>
…v0.x Signed-off-by: Yusuke Kuoka <[email protected]>
…lmfile v0.x Signed-off-by: Yusuke Kuoka <[email protected]>
… for Helmfile v0.x Signed-off-by: Yusuke Kuoka <[email protected]>
…yaml.v2 for Helmfile v0.x Signed-off-by: Yusuke Kuoka <[email protected]>
…pkg.in/yaml.v2 for Helmfile v0.x Signed-off-by: Yusuke Kuoka <[email protected]>
… Use gopkg.in/yaml.v2 for Helmfile v0.x Signed-off-by: Yusuke Kuoka <[email protected]>
|
@yxxhero FYI, it seems like goccy/go-yaml is more strict when parsing I'm going to update |
|
@yxxhero NVM. Apparently, it is due to that v1 mode requires .gotmpl ext for helmfile.yaml to enable the templating feature. We might need to rename every integration test input.yaml to input.yaml.gotmpl or come up with another way to make the integration test suite runnable for both helmfile v0 and v1 builds... |
|
@mumoshu I agreed with you so much. |
it's more conform to a standard of yaml spec. right? @mumoshu |
… fixup! Use gopkg.in/yaml.v2 for Helmfile v0.x Signed-off-by: Yusuke Kuoka <[email protected]>
|
@yxxhero Right. And it seems like every yaml implementation (yaml.v2, yaml.v3, and goccy/go-yaml) seems to fail if we tried to parse that. The failure was due to that I missed .gotmpl ext for helmfile v1 integration test. |
|
@mumoshu yeah. you are right. we should update the ext of integration test files. |
… fixup! fixup! Use gopkg.in/yaml.v2 for Helmfile v0.x Signed-off-by: Yusuke Kuoka <[email protected]>
… fixup! fixup! fixup! Use gopkg.in/yaml.v2 for Helmfile v0.x Signed-off-by: Yusuke Kuoka <[email protected]>
| # 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" |
There was a problem hiding this comment.
@yxxhero We now run the integration test suite for the v1 mode once per build, with the representative versions of helmfile dependencies, so that we won't break any v1 functionality until we finally stop maintaining v0.
| HELMFILE_HELM3: 1 | ||
| TERM: xterm | ||
| EXTRA_HELMFILE_FLAGS: ${{ matrix.extra-helmfile-flags }} | ||
| HELMFILE_V1MODE: ${{ matrix.v1mode }} |
There was a problem hiding this comment.
FYI, HELMFILE_V1MODE is defined in pkg/runtime/runtime.go
| v := runtime.GoccyGoYaml | ||
| runtime.GoccyGoYaml = tc.goccyGoYaml | ||
| t.Cleanup(func() { | ||
| runtime.GoccyGoYaml = v | ||
| }) |
There was a problem hiding this comment.
This is an idiom I used widely across many test sources to ensure we modify the GoccyGoYaml runtime variable only while running the (sub-)test.
| } | ||
|
|
||
| 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) { |
There was a problem hiding this comment.
You might also see this idiom, the same test is run with goccy/goyaml and with yaml.v2, so that we are sure that we don't break anything while migrating to goccy/goyaml or helmfile v1.
| UpgradeNoticeDisabled = "HELMFILE_UPGRADE_NOTICE_DISABLED" | ||
| V1Mode = "HELMFILE_V1MODE" | ||
| GoccyGoYaml = "HELMFILE_GOCCY_GOYAML" | ||
| CacheHome = "HELMFILE_CACHE_HOME" |
There was a problem hiding this comment.
This isn't strictly necessary to change our yaml library. However I added this because this helped tidy up our e2e/snapshot test to be runnable with/without v1 mode.
The envvar is used in pkg/remote/remote.go and set in snapshot_test.go
| } | ||
|
|
||
| // You can switch the YAML library at runtime via an envvar: | ||
| switch os.Getenv(envvar.GoccyGoYaml) { |
There was a problem hiding this comment.
Although goccy/go-yaml is the default for v1, you can opt in/out in both v0 and v1, by setting this envvar.
| } | ||
|
|
||
| var deserialized map[interface{}]interface{} | ||
| var deserialized map[string]interface{} |
There was a problem hiding this comment.
yaml.v2 deserializes nested yaml dict to map[interface{}]interface{} while yaml.v3 and goccy/go-yaml serializes it to map[string]interface{}.
My original design was to ensure any nested dict is deserialized to the latter, by calling maputil.CastKeysToStrings
| 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{}: |
There was a problem hiding this comment.
| Name: "app", | ||
| Namespace: "dev", | ||
| Values: []interface{}{map[interface{}]interface{}{"key": "app-val0"}}, | ||
| Values: []interface{}{map[string]interface{}{"key": "app-val0"}}, |
There was a problem hiding this comment.
| return nil, fmt.Errorf("%s, offending yaml: %s", err, str) | ||
| } | ||
|
|
||
| m, err := maputil.CastKeysToStrings(m) |
There was a problem hiding this comment.
This is especially important here because this function is supposed to be used like fromYaml | toJson within helmfile templates. Go's json pkg which powers toJson is unable to serialize map[interface{}]interface{} deserialized by yaml.v2. This CastKeysToStrings call normalizes it so that both yaml.v2 and goccy/go-yaml implementation of FromYaml is compatible with ToJson.
| } | ||
|
|
||
| func TestHelmfileTemplateWithBuildCommand(t *testing.T) { | ||
| t.Run("with goccy/go-yaml", func(t *testing.T) { |
There was a problem hiding this comment.
We now run all the snapshot tests for both goccy/go-yaml and yaml.v2
|
|
||
| tmpDir := t.TempDir() | ||
| // HELM_CACHE_HOME contains downloaded chart archives | ||
| helmCacheHome := filepath.Join(tmpDir, "helm_cache") |
There was a problem hiding this comment.
I had to give clean HELM_CACHE_HOME and HELM_CONFIG_HOME to every snapshot test case to make it not affected by the previous tests.
| 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: "" |
There was a problem hiding this comment.
I had to disable debug logging for this test case because running it with yaml.v2 resulted in adding an extra helm> line here due to an unknown reason.
It looked harmless but hard to solve so I just disabled the debug log to make it stable.
| values: | ||
| - template1: template1 | ||
| valuesTemplate: | ||
| - template1Label: "{{` '{{ .Release.Labels.template1 }}' `}}" |
There was a problem hiding this comment.
I'm not completely sure, but goccy/go-yaml seemed to translate single quotes enclosed in double quotes to triple single quotes, which resulted in this test case failing.
You don't need the single quotes anyway to write a valid helmfile yaml for this configuration so I just omitted it.
| inheritedBaseLabel: base | ||
| template2: template2 | ||
| template2Label: template2 | ||
| templates: |
There was a problem hiding this comment.
yaml.v2 encoded this in the flow style but we are not interested in a specific yaml library to encode the same go map to a yaml dict in flow style or non-flow style. I just removed this key out of values to make the output look the same between yaml.v2 and goccy/go-yaml. See input.yaml for the change.
| 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 |
There was a problem hiding this comment.
This is a new idiom I used in all the integration test runner script to rename helmfile.yaml to helmfile.yaml.gotmpl only when it's run with v1 mode.
|
@yxxhero DCO is failing due to perhaps a few commits missed signoffs but I'm too lazy to fix it. It would be great if we could handle it by using the squash-and-merge option and including the signoff line in the squashed commit. |
|
@mumoshu why |
|
@yxxhero That's because it's supposed work only with goccy/go-yamlm and therefore helmfile v1, which requires .gotmpl. Remember that we now run the integration test suite against both helmfile v0 and v1, and that we run the yaml-overwrite test only for v1! |
got. |
|
@yxxhero Thanks for your review! Let's see how this works in the wild. |
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 [email protected]