Skip to content

Commit af41383

Browse files
authored
fix: remote block should override env (#3366)
1 parent c180c3e commit af41383

File tree

1 file changed

+46
-46
lines changed

1 file changed

+46
-46
lines changed

Diff for: pkg/config/config.go

+46-46
Original file line numberDiff line numberDiff line change
@@ -440,35 +440,19 @@ func (c *config) Eject(w io.Writer) error {
440440
// Loads custom config file to struct fields tagged with toml.
441441
func (c *config) loadFromFile(filename string, fsys fs.FS) error {
442442
v := viper.New()
443-
v.SetConfigType("toml")
444-
// Load default values
445-
var buf bytes.Buffer
446-
if err := c.Eject(&buf); err != nil {
443+
if err := c.mergeDefaultValues(v); err != nil {
447444
return err
448-
} else if err := c.loadFromReader(v, &buf); err != nil {
445+
} else if err := mergeFileConfig(v, filename, fsys); err != nil {
449446
return err
450447
}
451-
// Load custom config
452-
if ext := filepath.Ext(filename); len(ext) > 0 {
453-
v.SetConfigType(ext[1:])
454-
}
455-
f, err := fsys.Open(filename)
456-
if errors.Is(err, os.ErrNotExist) {
457-
return nil
458-
} else if err != nil {
459-
return errors.Errorf("failed to read file config: %w", err)
460-
}
461-
defer f.Close()
462-
return c.loadFromReader(v, f)
463-
}
464-
465-
func (c *config) loadFromReader(v *viper.Viper, r io.Reader) error {
466-
if err := v.MergeConfig(r); err != nil {
467-
return errors.Errorf("failed to merge config: %w", err)
448+
// Load base config and mapstructure overrides
449+
if err := c.load(v); err != nil {
450+
return err
451+
} else if err := c.loadFromEnv(); err != nil {
452+
return err
468453
}
469454
// Find [remotes.*] block to override base config
470-
baseId := v.GetString("project_id")
471-
idToName := map[string]string{baseId: "base"}
455+
idToName := map[string]string{}
472456
for name, remote := range v.GetStringMap("remotes") {
473457
projectId := v.GetString(fmt.Sprintf("remotes.%s.project_id", name))
474458
// Track remote project_id to check for duplication
@@ -481,9 +465,43 @@ func (c *config) loadFromReader(v *viper.Viper, r io.Reader) error {
481465
if err := v.MergeConfigMap(remote.(map[string]any)); err != nil {
482466
return err
483467
}
484-
v.Set("project_id", baseId)
485468
}
486469
}
470+
if _, exists := idToName[c.ProjectId]; exists {
471+
return c.load(v)
472+
}
473+
return nil
474+
}
475+
476+
func (c *config) mergeDefaultValues(v *viper.Viper) error {
477+
v.SetConfigType("toml")
478+
var buf bytes.Buffer
479+
if err := c.Eject(&buf); err != nil {
480+
return err
481+
} else if err := v.MergeConfig(&buf); err != nil {
482+
return errors.Errorf("failed to merge default values: %w", err)
483+
}
484+
return nil
485+
}
486+
487+
func mergeFileConfig(v *viper.Viper, filename string, fsys fs.FS) error {
488+
if ext := filepath.Ext(filename); len(ext) > 0 {
489+
v.SetConfigType(ext[1:])
490+
}
491+
f, err := fsys.Open(filename)
492+
if errors.Is(err, os.ErrNotExist) {
493+
return nil
494+
} else if err != nil {
495+
return errors.Errorf("failed to read file config: %w", err)
496+
}
497+
defer f.Close()
498+
if err := v.MergeConfig(f); err != nil {
499+
return errors.Errorf("failed to merge file config: %w", err)
500+
}
501+
return nil
502+
}
503+
504+
func (c *config) load(v *viper.Viper) error {
487505
// Set default values for [functions.*] when config struct is empty
488506
for key, value := range v.GetStringMap("functions") {
489507
if _, ok := value.(map[string]any); !ok {
@@ -520,7 +538,7 @@ func (c *config) loadFromReader(v *viper.Viper, r io.Reader) error {
520538
return nil
521539
}
522540

523-
func (c *config) newDecodeHook(fs ...mapstructure.DecodeHookFunc) mapstructure.DecodeHookFunc {
541+
func (c *baseConfig) newDecodeHook(fs ...mapstructure.DecodeHookFunc) mapstructure.DecodeHookFunc {
524542
fs = append(fs,
525543
mapstructure.StringToTimeDurationHookFunc(),
526544
mapstructure.StringToIPHookFunc(),
@@ -532,26 +550,11 @@ func (c *config) newDecodeHook(fs ...mapstructure.DecodeHookFunc) mapstructure.D
532550
}
533551

534552
// Loads envs prefixed with supabase_ to struct fields tagged with mapstructure.
535-
func (c *config) loadFromEnv() error {
536-
v := viper.New()
553+
func (c *baseConfig) loadFromEnv() error {
554+
v := viper.NewWithOptions(viper.ExperimentalBindStruct())
537555
v.SetEnvPrefix("SUPABASE")
538556
v.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
539557
v.AutomaticEnv()
540-
// Viper does not parse env vars automatically. Instead of calling viper.BindEnv
541-
// per key, we decode all keys from an existing struct, and merge them to viper.
542-
// Ref: https://github.com/spf13/viper/issues/761#issuecomment-859306364
543-
envKeysMap := map[string]interface{}{}
544-
if dec, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
545-
Result: &envKeysMap,
546-
IgnoreUntaggedFields: true,
547-
}); err != nil {
548-
return errors.Errorf("failed to create decoder: %w", err)
549-
} else if err := dec.Decode(c.baseConfig); err != nil {
550-
return errors.Errorf("failed to decode env: %w", err)
551-
} else if err := v.MergeConfigMap(envKeysMap); err != nil {
552-
return errors.Errorf("failed to merge env config: %w", err)
553-
}
554-
// Writes viper state back to config struct, with automatic env substitution
555558
if err := v.UnmarshalExact(c, viper.DecodeHook(c.newDecodeHook())); err != nil {
556559
return errors.Errorf("failed to parse env override: %w", err)
557560
}
@@ -567,9 +570,6 @@ func (c *config) Load(path string, fsys fs.FS) error {
567570
if err := c.loadFromFile(builder.ConfigPath, fsys); err != nil {
568571
return err
569572
}
570-
if err := c.loadFromEnv(); err != nil {
571-
return err
572-
}
573573
// Generate JWT tokens
574574
if len(c.Auth.AnonKey) == 0 {
575575
anonToken := CustomClaims{Role: "anon"}.NewToken()

0 commit comments

Comments
 (0)