refactor(yaml): upgrade from gopkg.in/yaml.v2 to v3 (#2039)

* refactor(yaml): upgrade from gopkg.in/yaml.v2 to v3

Signed-off-by: yxxhero <aiopsclub@163.com>

* refactor(yaml): enhance yaml encoding with consistent formatting and quotes

Signed-off-by: yxxhero <aiopsclub@163.com>

* optimize code

Signed-off-by: yxxhero <aiopsclub@163.com>

* fix tests

Signed-off-by: yxxhero <aiopsclub@163.com>

* fix more issues

Signed-off-by: yxxhero <aiopsclub@163.com>

* fix tests

Signed-off-by: yxxhero <aiopsclub@163.com>

---------

Signed-off-by: yxxhero <aiopsclub@163.com>
This commit is contained in:
yxxhero 2025-05-15 22:21:37 +08:00 committed by GitHub
parent 867bef0f03
commit b52ca9ae04
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 140 additions and 147 deletions

View File

@ -570,18 +570,17 @@ Helmfile uses some OS environment variables to override default behaviour:
* `HELMFILE_ENVIRONMENT` - specify [Helmfile environment](https://helmfile.readthedocs.io/en/latest/#environment), it has lower priority than CLI argument `--environment` * `HELMFILE_ENVIRONMENT` - specify [Helmfile environment](https://helmfile.readthedocs.io/en/latest/#environment), it has lower priority than CLI argument `--environment`
* `HELMFILE_TEMPDIR` - specify directory to store temporary files * `HELMFILE_TEMPDIR` - specify directory to store temporary files
* `HELMFILE_UPGRADE_NOTICE_DISABLED` - expecting any non-empty value to skip the check for the latest version of Helmfile in [helmfile version](https://helmfile.readthedocs.io/en/latest/#version) * `HELMFILE_UPGRADE_NOTICE_DISABLED` - expecting any non-empty value to skip the check for the latest version of Helmfile in [helmfile version](https://helmfile.readthedocs.io/en/latest/#version)
* `HELMFILE_GOCCY_GOYAML` - 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. * `HELMFILE_GO_YAML_V3` - use *gopkg.in/yaml.v3* instead of *gopkg.in/yaml.v2*. It's `false` by default in Helmfile v0.x, and `true` in Helmfile v1.x.
* `HELMFILE_CACHE_HOME` - specify directory to store cached files for remote operations * `HELMFILE_CACHE_HOME` - specify directory to store cached files for remote operations
* `HELMFILE_FILE_PATH` - specify the path to the helmfile.yaml file * `HELMFILE_FILE_PATH` - specify the path to the helmfile.yaml file
* `HELMFILE_INTERACTIVE` - enable interactive mode, expecting `true` lower case. The same as `--interactive` CLI flag * `HELMFILE_INTERACTIVE` - enable interactive mode, expecting `true` lower case. The same as `--interactive` CLI flag
* `HELMFILE_ENABLE_GOCCY_GOYAML_JSON_STYLE`: - enable JSON style for *goccy/go-yaml* instead of *gopkg.in/yaml.v2*. It's `false` by default in Helmfile. it will add quotes to string values.
## CLI Reference ## CLI Reference
``` ```
Declaratively deploy your Kubernetes manifests, Kustomize configs, and Charts as Helm releases in one shot Declaratively deploy your Kubernetes manifests, Kustomize configs, and Charts as Helm releases in one shot
V1 mode = false V1 mode = false
YAML library = gopkg.in/yaml.v2 YAML library = gopkg.in/yaml.v3
Usage: Usage:
helmfile [command] helmfile [command]

4
go.mod
View File

@ -8,7 +8,6 @@ require (
github.com/Masterminds/sprig/v3 v3.3.0 github.com/Masterminds/sprig/v3 v3.3.0
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc
github.com/go-test/deep v1.1.1 github.com/go-test/deep v1.1.1
github.com/goccy/go-yaml v1.17.1
github.com/golang/mock v1.6.0 github.com/golang/mock v1.6.0
github.com/google/go-cmp v0.7.0 github.com/google/go-cmp v0.7.0
github.com/gosuri/uitable v0.0.4 github.com/gosuri/uitable v0.0.4
@ -29,6 +28,7 @@ require (
golang.org/x/sync v0.14.0 golang.org/x/sync v0.14.0
golang.org/x/term v0.32.0 golang.org/x/term v0.32.0
gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v2 v2.4.0
gopkg.in/yaml.v3 v3.0.1
helm.sh/helm/v3 v3.17.3 helm.sh/helm/v3 v3.17.3
k8s.io/apimachinery v0.33.0 k8s.io/apimachinery v0.33.0
) )
@ -217,6 +217,7 @@ require (
github.com/go-openapi/swag v0.23.1 // indirect github.com/go-openapi/swag v0.23.1 // indirect
github.com/go-openapi/validate v0.24.0 // indirect github.com/go-openapi/validate v0.24.0 // indirect
github.com/gobwas/glob v0.2.3 // indirect github.com/gobwas/glob v0.2.3 // indirect
github.com/goccy/go-yaml v1.17.1 // indirect
github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang-jwt/jwt/v5 v5.2.2 // indirect github.com/golang-jwt/jwt/v5 v5.2.2 // indirect
@ -307,7 +308,6 @@ require (
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
gopkg.in/gookit/color.v1 v1.1.6 // indirect gopkg.in/gookit/color.v1 v1.1.6 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/api v0.33.0 // indirect k8s.io/api v0.33.0 // indirect
k8s.io/apiextensions-apiserver v0.32.2 // indirect k8s.io/apiextensions-apiserver v0.32.2 // indirect
k8s.io/cli-runtime v0.32.2 // indirect k8s.io/cli-runtime v0.32.2 // indirect

View File

@ -338,18 +338,18 @@ releases:
func TestTemplate_StrictParsing(t *testing.T) { func TestTemplate_StrictParsing(t *testing.T) {
type testcase struct { type testcase struct {
goccyGoYaml bool GoYamlV3 bool
ns string ns string
error string error string
} }
check := func(t *testing.T, tc testcase) { check := func(t *testing.T, tc testcase) {
t.Helper() t.Helper()
v := runtime.GoccyGoYaml v := runtime.GoYamlV3
runtime.GoccyGoYaml = tc.goccyGoYaml runtime.GoYamlV3 = tc.GoYamlV3
t.Cleanup(func() { t.Cleanup(func() {
runtime.GoccyGoYaml = v runtime.GoYamlV3 = v
}) })
var helm = &exectest.Helm{ var helm = &exectest.Helm{
@ -411,21 +411,17 @@ releases:
}) })
} }
t.Run("fail due to unknown field with goccy/go-yaml", func(t *testing.T) { t.Run("fail due to unknown field with gopkg.in/yaml.v3", func(t *testing.T) {
check(t, testcase{ check(t, testcase{
goccyGoYaml: true, GoYamlV3: true,
error: `in ./helmfile.yaml: failed to read helmfile.yaml: reading document at index 1. Started seeing this since Helmfile v1? Add the .gotmpl file extension: [4:3] unknown field "foobar" error: `in ./helmfile.yaml: failed to read helmfile.yaml: reading document at index 1. Started seeing this since Helmfile v1? Add the .gotmpl file extension: yaml: unmarshal errors:
2 | releases: line 4: field foobar not found in type state.ReleaseSpec`,
3 | - name: app1
> 4 | foobar: FOOBAR
^
5 | chart: incubator/raw`,
}) })
}) })
t.Run("fail due to unknown field with gopkg.in/yaml.v2", func(t *testing.T) { t.Run("fail due to unknown field with gopkg.in/yaml.v2", func(t *testing.T) {
check(t, testcase{ check(t, testcase{
goccyGoYaml: false, GoYamlV3: false,
error: `in ./helmfile.yaml: failed to read helmfile.yaml: reading document at index 1. Started seeing this since Helmfile v1? Add the .gotmpl file extension: yaml: unmarshal errors: error: `in ./helmfile.yaml: failed to read helmfile.yaml: reading document at index 1. Started seeing this since Helmfile v1? Add the .gotmpl file extension: yaml: unmarshal errors:
line 4: field foobar not found in type state.ReleaseSpec`, line 4: field foobar not found in type state.ReleaseSpec`,
}) })

View File

@ -4020,13 +4020,13 @@ myrelease4 testNamespace true true chart:mychart1,id:myrelease1,name:myr
assert.Equal(t, expected, out) assert.Equal(t, expected, out)
} }
func testSetStringValuesTemplate(t *testing.T, goccyGoYaml bool) { func testSetStringValuesTemplate(t *testing.T, GoYamlV3 bool) {
t.Helper() t.Helper()
v := runtime.GoccyGoYaml v := runtime.GoYamlV3
runtime.GoccyGoYaml = goccyGoYaml runtime.GoYamlV3 = GoYamlV3
t.Cleanup(func() { t.Cleanup(func() {
runtime.GoccyGoYaml = v runtime.GoYamlV3 = v
}) })
files := map[string]string{ files := map[string]string{
@ -4088,13 +4088,13 @@ releases:
} }
} }
func testSetValuesTemplate(t *testing.T, goccyGoYaml bool) { func testSetValuesTemplate(t *testing.T, GoYamlV3 bool) {
t.Helper() t.Helper()
v := runtime.GoccyGoYaml v := runtime.GoYamlV3
runtime.GoccyGoYaml = goccyGoYaml runtime.GoYamlV3 = GoYamlV3
t.Cleanup(func() { t.Cleanup(func() {
runtime.GoccyGoYaml = v runtime.GoYamlV3 = v
}) })
files := map[string]string{ files := map[string]string{
@ -4161,7 +4161,7 @@ releases:
} }
func TestSetValuesTemplate(t *testing.T) { func TestSetValuesTemplate(t *testing.T) {
t.Run("with goccy/go-yaml", func(t *testing.T) { t.Run("with gopkg.in/yaml.v3", func(t *testing.T) {
testSetValuesTemplate(t, true) testSetValuesTemplate(t, true)
}) })
@ -4171,7 +4171,7 @@ func TestSetValuesTemplate(t *testing.T) {
} }
func TestSetStringValuesTemplate(t *testing.T) { func TestSetStringValuesTemplate(t *testing.T) {
t.Run("with goccy/go-yaml", func(t *testing.T) { t.Run("with gopkg.in/yaml.v3", func(t *testing.T) {
testSetStringValuesTemplate(t, true) testSetStringValuesTemplate(t, true)
}) })

View File

@ -6,14 +6,13 @@ const (
// use helm status to check if a release exists before installing it // use helm status to check if a release exists before installing it
UseHelmStatusToCheckReleaseExistence = "HELMFILE_USE_HELM_STATUS_TO_CHECK_RELEASE_EXISTENCE" UseHelmStatusToCheckReleaseExistence = "HELMFILE_USE_HELM_STATUS_TO_CHECK_RELEASE_EXISTENCE"
DisableRunnerUniqueID = "HELMFILE_DISABLE_RUNNER_UNIQUE_ID" DisableRunnerUniqueID = "HELMFILE_DISABLE_RUNNER_UNIQUE_ID"
Experimental = "HELMFILE_EXPERIMENTAL" // environment variable for experimental features, expecting "true" lower case Experimental = "HELMFILE_EXPERIMENTAL" // environment variable for experimental features, expecting "true" lower case
Environment = "HELMFILE_ENVIRONMENT" Environment = "HELMFILE_ENVIRONMENT"
FilePath = "HELMFILE_FILE_PATH" FilePath = "HELMFILE_FILE_PATH"
TempDir = "HELMFILE_TEMPDIR" TempDir = "HELMFILE_TEMPDIR"
UpgradeNoticeDisabled = "HELMFILE_UPGRADE_NOTICE_DISABLED" UpgradeNoticeDisabled = "HELMFILE_UPGRADE_NOTICE_DISABLED"
GoccyGoYaml = "HELMFILE_GOCCY_GOYAML" GoYamlV3 = "HELMFILE_GO_YAML_V3"
CacheHome = "HELMFILE_CACHE_HOME" CacheHome = "HELMFILE_CACHE_HOME"
Interactive = "HELMFILE_INTERACTIVE" Interactive = "HELMFILE_INTERACTIVE"
EnableGoccyGoYamlJSONStyle = "HELMFILE_ENABLE_GOCCY_GOYAML_JSON_STYLE"
) )

View File

@ -8,16 +8,16 @@ import (
) )
var ( var (
// GoccyGoYaml is set to true in order to let Helmfile use // GoYamlV3 is set to true in order to let Helmfile use
// goccy/go-yaml instead of gopkg.in/yaml.v2. // gopkg.in/yaml.v3 instead of gopkg.in/yaml.v2.
// It's false by default in Helmfile v0.x and true by default for Helmfile v1.x. // It's false by default in Helmfile v0.x and true in Helmfile v1.x.
GoccyGoYaml bool GoYamlV3 bool
) )
func Info() string { func Info() string {
yamlLib := "gopkg.in/yaml.v2" yamlLib := "gopkg.in/yaml.v2"
if GoccyGoYaml { if GoYamlV3 {
yamlLib = "goccy/go-yaml" yamlLib = "gopkg.in/yaml.v3"
} }
return fmt.Sprintf("YAML library = %v", yamlLib) return fmt.Sprintf("YAML library = %v", yamlLib)
@ -25,12 +25,12 @@ func Info() string {
func init() { func init() {
// You can switch the YAML library at runtime via an envvar: // You can switch the YAML library at runtime via an envvar:
switch os.Getenv(envvar.GoccyGoYaml) { switch os.Getenv(envvar.GoYamlV3) {
case "true": case "true":
GoccyGoYaml = true GoYamlV3 = true
case "false": case "false":
GoccyGoYaml = false GoYamlV3 = false
default: default:
GoccyGoYaml = true GoYamlV3 = true
} }
} }

View File

@ -22,10 +22,10 @@ func TestExecuteTemplateExpressions(t *testing.T) {
}, },
}) })
v := runtime.GoccyGoYaml v := runtime.GoYamlV3
runtime.GoccyGoYaml = true runtime.GoYamlV3 = true
t.Cleanup(func() { t.Cleanup(func() {
runtime.GoccyGoYaml = v runtime.GoYamlV3 = v
}) })
rs := ReleaseSpec{ rs := ReleaseSpec{

View File

@ -4,14 +4,12 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io/fs" "io/fs"
"os"
"path/filepath" "path/filepath"
goruntime "runtime" goruntime "runtime"
"testing" "testing"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/helmfile/helmfile/pkg/envvar"
"github.com/helmfile/helmfile/pkg/filesystem" "github.com/helmfile/helmfile/pkg/filesystem"
"github.com/helmfile/helmfile/pkg/runtime" "github.com/helmfile/helmfile/pkg/runtime"
) )
@ -162,9 +160,9 @@ func TestReadFile_PassAbsPath(t *testing.T) {
} }
func TestToYaml_NestedMapInterfaceKey(t *testing.T) { func TestToYaml_NestedMapInterfaceKey(t *testing.T) {
v := runtime.GoccyGoYaml v := runtime.GoYamlV3
t.Cleanup(func() { t.Cleanup(func() {
runtime.GoccyGoYaml = v runtime.GoYamlV3 = v
}) })
// nolint: unconvert // nolint: unconvert
@ -174,13 +172,13 @@ func TestToYaml_NestedMapInterfaceKey(t *testing.T) {
}, },
}) })
runtime.GoccyGoYaml = true runtime.GoYamlV3 = true
actual, err := ToYaml(vals) actual, err := ToYaml(vals)
require.Equal(t, "foo:\n bar: BAR\n", 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) require.NoError(t, err, "expected nil, but got: %v, when type: map[interface {}]interface {}", err)
runtime.GoccyGoYaml = false runtime.GoYamlV3 = false
actual, err = ToYaml(vals) actual, err = ToYaml(vals)
require.Equal(t, "foo:\n bar: BAR\n", actual) require.Equal(t, "foo:\n bar: BAR\n", actual)
@ -189,18 +187,16 @@ func TestToYaml_NestedMapInterfaceKey(t *testing.T) {
func TestToYaml(t *testing.T) { func TestToYaml(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
input any input any
expected string expected string
wantErr bool wantErr bool
enableJsonStyle bool
}{ }{
{ {
// https://github.com/helmfile/helmfile/issues/2024 // https://github.com/helmfile/helmfile/issues/2024
name: "test unmarshalling issue 2024", name: "test unmarshalling issue 2024",
enableJsonStyle: true, input: map[string]any{"thisShouldBeString": "01234567890123456789"},
input: map[string]any{"thisShouldBeString": "01234567890123456789"}, expected: `thisShouldBeString: "01234567890123456789"
expected: `'thisShouldBeString': '01234567890123456789'
`, `,
}, },
{ {
@ -247,12 +243,6 @@ func TestToYaml(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
if tt.enableJsonStyle {
_ = os.Setenv(envvar.EnableGoccyGoYamlJSONStyle, "true")
}
defer func() {
_ = os.Unsetenv(envvar.EnableGoccyGoYamlJSONStyle)
}()
actual, err := ToYaml(tt.input) actual, err := ToYaml(tt.input)
if tt.wantErr { if tt.wantErr {
require.Error(t, err) require.Error(t, err)
@ -345,13 +335,13 @@ func testFromYamlNull(t *testing.T) {
require.Equal(t, nil, actual) require.Equal(t, nil, actual)
} }
func testFromYaml(t *testing.T, goccyGoYaml bool) { func testFromYaml(t *testing.T, GoYamlV3 bool) {
t.Helper() t.Helper()
v := runtime.GoccyGoYaml v := runtime.GoYamlV3
runtime.GoccyGoYaml = goccyGoYaml runtime.GoYamlV3 = GoYamlV3
t.Cleanup(func() { t.Cleanup(func() {
runtime.GoccyGoYaml = v runtime.GoYamlV3 = v
}) })
t.Run("test unmarshalling object", testFromYamlObject) t.Run("test unmarshalling object", testFromYamlObject)
@ -368,11 +358,11 @@ func testFromYaml(t *testing.T, goccyGoYaml bool) {
} }
func TestFromYaml(t *testing.T) { func TestFromYaml(t *testing.T) {
t.Run("with goccy/go-yaml", func(t *testing.T) { t.Run("with gopkg.in/yaml.v2", func(t *testing.T) {
testFromYaml(t, true) testFromYaml(t, true)
}) })
t.Run("with gopkg.in/yaml.v2", func(t *testing.T) { t.Run("with gopkg.in/yaml.v3", func(t *testing.T) {
testFromYaml(t, false) testFromYaml(t, false)
}) })
} }

View File

@ -3,12 +3,10 @@ package yaml
import ( import (
"bytes" "bytes"
"io" "io"
"os"
"github.com/goccy/go-yaml"
v2 "gopkg.in/yaml.v2" v2 "gopkg.in/yaml.v2"
v3 "gopkg.in/yaml.v3"
"github.com/helmfile/helmfile/pkg/envvar"
"github.com/helmfile/helmfile/pkg/runtime" "github.com/helmfile/helmfile/pkg/runtime"
) )
@ -19,24 +17,22 @@ 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 runtime.GoccyGoYaml { if runtime.GoYamlV3 {
yamlEncoderOpts := []yaml.EncodeOption{} v3Encoder := v3.NewEncoder(w)
// enable JSON style if the envvar is set v3Encoder.SetIndent(2)
if os.Getenv(envvar.EnableGoccyGoYamlJSONStyle) == "true" { return v3Encoder
yamlEncoderOpts = append(yamlEncoderOpts, yaml.JSON(), yaml.Flow(false))
}
return yaml.NewEncoder(w, yamlEncoderOpts...)
} }
return v2.NewEncoder(w) return v2.NewEncoder(w)
} }
func Unmarshal(data []byte, v any) error { func Marshal(v any) ([]byte, error) {
if runtime.GoccyGoYaml { var b bytes.Buffer
return yaml.Unmarshal(data, v) yamlEncoder := NewEncoder(&b)
} err := yamlEncoder.Encode(v)
defer func() {
return v2.Unmarshal(data, v) _ = yamlEncoder.Close()
}()
return b.Bytes(), err
} }
// NewDecoder creates and returns a function that is used to decode a YAML document // NewDecoder creates and returns a function that is used to decode a YAML document
@ -44,19 +40,9 @@ func Unmarshal(data []byte, v any) 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(any) error { func NewDecoder(data []byte, strict bool) func(any) error {
if runtime.GoccyGoYaml { if runtime.GoYamlV3 {
var opts []yaml.DecodeOption decoder := v3.NewDecoder(bytes.NewReader(data))
if strict { decoder.KnownFields(strict)
opts = append(opts, yaml.DisallowUnknownField())
}
// allow duplicate keys
opts = append(opts, yaml.AllowDuplicateMapKey())
decoder := yaml.NewDecoder(
bytes.NewReader(data),
opts...,
)
return func(v any) error { return func(v any) error {
return decoder.Decode(v) return decoder.Decode(v)
} }
@ -70,29 +56,10 @@ func NewDecoder(data []byte, strict bool) func(any) error {
} }
} }
func Marshal(v any) ([]byte, error) { func Unmarshal(data []byte, v any) error {
if runtime.GoccyGoYaml { if runtime.GoYamlV3 {
var b bytes.Buffer return v3.Unmarshal(data, v)
yamlEncoderOpts := []yaml.EncodeOption{
yaml.Indent(2),
yaml.UseSingleQuote(true),
yaml.UseLiteralStyleIfMultiline(true),
}
// enable JSON style if the envvar is set
if os.Getenv(envvar.EnableGoccyGoYamlJSONStyle) == "true" {
yamlEncoderOpts = append(yamlEncoderOpts, yaml.JSON(), yaml.Flow(false))
}
yamlEncoder := yaml.NewEncoder(
&b,
yamlEncoderOpts...,
)
err := yamlEncoder.Encode(v)
defer func() {
_ = yamlEncoder.Close()
}()
return b.Bytes(), err
} }
return v2.Marshal(v) return v2.Unmarshal(data, v)
} }

View File

@ -8,20 +8,20 @@ import (
"github.com/helmfile/helmfile/pkg/runtime" "github.com/helmfile/helmfile/pkg/runtime"
) )
func testYamlMarshal(t *testing.T, goccyGoYaml bool) { func testYamlMarshal(t *testing.T, GoYamlV3 bool) {
t.Helper() t.Helper()
var yamlLibraryName string var yamlLibraryName string
if goccyGoYaml { if GoYamlV3 {
yamlLibraryName = "goccy/go-yaml" yamlLibraryName = "gopkg.in/yaml.v3"
} else { } else {
yamlLibraryName = "gopkg.in/yaml.v2" yamlLibraryName = "gopkg.in/yaml.v2"
} }
v := runtime.GoccyGoYaml v := runtime.GoYamlV3
runtime.GoccyGoYaml = goccyGoYaml runtime.GoYamlV3 = GoYamlV3
t.Cleanup(func() { t.Cleanup(func() {
runtime.GoccyGoYaml = v runtime.GoYamlV3 = v
}) })
tests := []struct { tests := []struct {
@ -49,8 +49,8 @@ func testYamlMarshal(t *testing.T, goccyGoYaml bool) {
Annotation: "on", Annotation: "on",
}}, }},
expected: map[string]string{ expected: map[string]string{
"goccy/go-yaml": "name: John\ninfo:\n- age: 20\n address: New York\n annotation: 'on'\n",
"gopkg.in/yaml.v2": "name: John\ninfo:\n- age: 20\n address: New York\n annotation: \"on\"\n", "gopkg.in/yaml.v2": "name: John\ninfo:\n- age: 20\n address: New York\n annotation: \"on\"\n",
"gopkg.in/yaml.v3": "name: John\ninfo:\n - age: 20\n address: New York\n annotation: \"on\"\n",
}, },
}, },
} }
@ -63,11 +63,11 @@ func testYamlMarshal(t *testing.T, goccyGoYaml bool) {
} }
func TestYamlMarshal(t *testing.T) { func TestYamlMarshal(t *testing.T) {
t.Run("with goccy/go-yaml", func(t *testing.T) { t.Run("with gopkg.in/yaml.v2", func(t *testing.T) {
testYamlMarshal(t, true) testYamlMarshal(t, true)
}) })
t.Run("with gopkg.in/yaml.v2", func(t *testing.T) { t.Run("with gopkg.in/yaml.v3", func(t *testing.T) {
testYamlMarshal(t, false) testYamlMarshal(t, false)
}) })
} }

View File

@ -58,17 +58,17 @@ 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) { t.Run("with gopkg.in/yaml.v2", func(t *testing.T) {
testHelmfileTemplateWithBuildCommand(t, true) testHelmfileTemplateWithBuildCommand(t, true)
}) })
t.Run("with gopkg.in/yaml.v2", func(t *testing.T) { t.Run("with gopkg.in/yaml.v3", func(t *testing.T) {
testHelmfileTemplateWithBuildCommand(t, false) testHelmfileTemplateWithBuildCommand(t, false)
}) })
} }
func testHelmfileTemplateWithBuildCommand(t *testing.T, goccyGoYaml bool) { func testHelmfileTemplateWithBuildCommand(t *testing.T, GoYamlV3 bool) {
t.Setenv(envvar.GoccyGoYaml, strconv.FormatBool(goccyGoYaml)) t.Setenv(envvar.GoYamlV3, strconv.FormatBool(GoYamlV3))
localChartPortSets := make(map[int]struct{}) localChartPortSets := make(map[int]struct{})
@ -224,7 +224,12 @@ func testHelmfileTemplateWithBuildCommand(t *testing.T, goccyGoYaml bool) {
t.Logf("Using HELM_CACHE_HOME=%s, HELMFILE_CACHE_HOME=%s, HELM_CONFIG_HOME=%s", helmCacheHome, helmfileCacheHome, helmConfigHome) 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.gotmpl") inputFile := filepath.Join(testdataDir, name, "input.yaml.gotmpl")
outputFile := filepath.Join(testdataDir, name, "output.yaml") outputFile := ""
if GoYamlV3 {
outputFile = filepath.Join(testdataDir, name, "gopkg.in-yaml.v3-output.yaml")
} else {
outputFile = filepath.Join(testdataDir, name, "gopkg.in-yaml.v2-output.yaml")
}
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel() defer cancel()

View File

@ -0,0 +1,37 @@
---
# Source: __workingdir__/testdata/snapshot/issue_2098_release_template_needs/input.yaml.gotmpl
filepath: input.yaml.gotmpl
helmBinary: helm
kustomizeBinary: kustomize
environments:
default: {}
repositories:
- name: aservo
url: https://aservo.github.io/charts
releases:
- chart: aservo/util
version: 0.0.1
name: default-shared-resources
namespace: default
labels:
chart: util
name: default-shared-resources
namespace: default
service: shared-resources
- chart: aservo/util
version: 0.0.1
needs:
- default/default-shared-resources
name: default-release-resources
namespace: default
labels:
chart: util
name: default-release-resources
namespace: default
service: release-resources
templates:
defaults:
name: default-{{ .Release.Labels.service }}
namespace: default
renderedvalues: {}