fix!: hide struct binding behind a feature flag

Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
This commit is contained in:
Mark Sagi-Kazar 2023-12-15 13:31:38 +01:00 committed by Márk Sági-Kazár
parent 0b0a1104ba
commit 473a3dfc7f
5 changed files with 42 additions and 14 deletions

View file

@ -26,7 +26,7 @@ jobs:
- name: Set up Go - name: Set up Go
uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0 uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0
with: with:
go-version: '1.21' go-version: "1.21"
- name: Build - name: Build
run: go build . run: go build .
@ -44,8 +44,8 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
os: [ubuntu-latest, macos-latest, windows-latest] os: [ubuntu-latest, macos-latest, windows-latest]
go: ['1.19', '1.20', '1.21'] go: ["1.19", "1.20", "1.21"]
tags: ['', 'finder'] tags: ["", "finder", "viper_bind_struct"]
steps: steps:
- name: Checkout repository - name: Checkout repository
@ -75,7 +75,7 @@ jobs:
- name: Set up Go - name: Set up Go
uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0 uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0
with: with:
go-version: '1.21' go-version: "1.21"
- name: Lint - name: Lint
uses: golangci/golangci-lint-action@3a919529898de77ec3da873e3063ca4b10e7f5cc # v3.7.0 uses: golangci/golangci-lint-action@3a919529898de77ec3da873e3063ca4b10e7f5cc # v3.7.0

View file

@ -0,0 +1,5 @@
//go:build viper_bind_struct
package features
const BindStruct = true

View file

@ -0,0 +1,5 @@
//go:build !viper_bind_struct
package features
const BindStruct = false

View file

@ -48,6 +48,7 @@ import (
"github.com/spf13/viper/internal/encoding/json" "github.com/spf13/viper/internal/encoding/json"
"github.com/spf13/viper/internal/encoding/toml" "github.com/spf13/viper/internal/encoding/toml"
"github.com/spf13/viper/internal/encoding/yaml" "github.com/spf13/viper/internal/encoding/yaml"
"github.com/spf13/viper/internal/features"
) )
// ConfigMarshalError happens when failing to marshal the configuration. // ConfigMarshalError happens when failing to marshal the configuration.
@ -1114,14 +1115,20 @@ func Unmarshal(rawVal any, opts ...DecoderConfigOption) error {
} }
func (v *Viper) Unmarshal(rawVal any, opts ...DecoderConfigOption) error { func (v *Viper) Unmarshal(rawVal any, opts ...DecoderConfigOption) error {
keys := v.AllKeys()
if features.BindStruct {
// TODO: make this optional? // TODO: make this optional?
structKeys, err := v.decodeStructKeys(rawVal, opts...) structKeys, err := v.decodeStructKeys(rawVal, opts...)
if err != nil { if err != nil {
return err return err
} }
keys = append(keys, structKeys...)
}
// TODO: struct keys should be enough? // TODO: struct keys should be enough?
return decode(v.getSettings(append(v.AllKeys(), structKeys...)), defaultDecoderConfig(rawVal, opts...)) return decode(v.getSettings(keys), defaultDecoderConfig(rawVal, opts...))
} }
func (v *Viper) decodeStructKeys(input any, opts ...DecoderConfigOption) ([]string, error) { func (v *Viper) decodeStructKeys(input any, opts ...DecoderConfigOption) ([]string, error) {
@ -1179,14 +1186,20 @@ func (v *Viper) UnmarshalExact(rawVal any, opts ...DecoderConfigOption) error {
config := defaultDecoderConfig(rawVal, opts...) config := defaultDecoderConfig(rawVal, opts...)
config.ErrorUnused = true config.ErrorUnused = true
keys := v.AllKeys()
if features.BindStruct {
// TODO: make this optional? // TODO: make this optional?
structKeys, err := v.decodeStructKeys(rawVal, opts...) structKeys, err := v.decodeStructKeys(rawVal, opts...)
if err != nil { if err != nil {
return err return err
} }
keys = append(keys, structKeys...)
}
// TODO: struct keys should be enough? // TODO: struct keys should be enough?
return decode(v.getSettings(append(v.AllKeys(), structKeys...)), config) return decode(v.getSettings(keys), config)
} }
// BindPFlags binds a full flag set to the configuration, using each flag's long // BindPFlags binds a full flag set to the configuration, using each flag's long

View file

@ -28,6 +28,7 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/spf13/viper/internal/features"
"github.com/spf13/viper/internal/testutil" "github.com/spf13/viper/internal/testutil"
) )
@ -956,6 +957,10 @@ func TestUnmarshalWithDecoderOptions(t *testing.T) {
} }
func TestUnmarshalWithAutomaticEnv(t *testing.T) { func TestUnmarshalWithAutomaticEnv(t *testing.T) {
if !features.BindStruct {
t.Skip("binding struct is not enabled")
}
t.Setenv("PORT", "1313") t.Setenv("PORT", "1313")
t.Setenv("NAME", "Steve") t.Setenv("NAME", "Steve")
t.Setenv("DURATION", "1s1ms") t.Setenv("DURATION", "1s1ms")