Skip to content
This repository was archived by the owner on Jul 28, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions pkg/util/yaml.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,17 @@ func UnmarshalYAMLMerged(bb []byte, vv ...interface{}) error {
} else if err != nil {
return err
}

// It's common for custom yaml.Unmarshaler implementations to use
// UnmarshalYAML to apply default values both before and after calling the
// unmarshal method passed to them.
//
// We *must* do a second non-strict unmarshal *after* the strict unmarshal
// to ensure that every v was able to complete its unmarshal to completion,
// ignoring type errors from unrecognized fields.
if err := yaml.Unmarshal(bb, v); err != nil {
return err
}
}

var (
Expand Down
47 changes: 47 additions & 0 deletions pkg/util/yaml_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package util

import (
"testing"

"github.com/stretchr/testify/require"
)

// TestUnmarshalYAMLMerged_CustomUnmarshal checks to see that
// UnmarshalYAMLMerged works with merging types that have custom unmarshal
// methods which do extra checks after calling unmarshal.
func TestUnmarshalYAMLMerged_CustomUnmarshal(t *testing.T) {
in := `
fieldA: foo
fieldB: bar
`

var (
val1 typeOne
val2 typeTwo
)

err := UnmarshalYAMLMerged([]byte(in), &val1, &val2)
require.NoError(t, err)

require.Equal(t, "foo", val1.FieldA)
require.Equal(t, "bar", val2.FieldB)
require.True(t, val2.Unmarshaled)
}

type typeOne struct {
FieldA string `yaml:"fieldA"`
}

type typeTwo struct {
FieldB string `yaml:"fieldB"`
Unmarshaled bool `yaml:"-"`
}

func (t *typeTwo) UnmarshalYAML(unmarshal func(interface{}) error) error {
type rawType typeTwo
if err := unmarshal((*rawType)(t)); err != nil {
return err
}
t.Unmarshaled = true
return nil
}