Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,7 @@ arguments, you can set the following environment variables:
export GOOSE_DRIVER=DRIVER
export GOOSE_DBSTRING=DBSTRING
export GOOSE_MIGRATION_DIR=MIGRATION_DIR
export GOOSE_TABLE=TABLENAME
```

**2. Via `.env` files with corresponding variables. `.env` file example**:
Expand All @@ -255,6 +256,7 @@ export GOOSE_MIGRATION_DIR=MIGRATION_DIR
GOOSE_DRIVER=postgres
GOOSE_DBSTRING=postgres://admin:admin@localhost:5432/admin_db
GOOSE_MIGRATION_DIR=./migrations
GOOSE_TABLE=custom.goose_migrations
```

Loading from `.env` files is enabled by default. To disable this feature, set the `-env=none` flag.
Expand Down
17 changes: 16 additions & 1 deletion cmd/goose/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,9 @@ func main() {
if *sequential {
goose.SetSequential(true)
}
goose.SetTableName(*table)

// Envvars should have lower priority than flags.
goose.SetTableName(firstNonEmpty(*table, envConfig.table))

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this will work, since *table will be set to the default from line 31:

flags.String("table", "goose_db_version", "migrations table name")

I think what might work here is:

- goose.SetTableName(firstNonEmpty(*table, envConfig.table))
+ goose.SetTableName(firstNonEmpty(*table, envConfig.table, "goose_db_version"))

And then remove the flag default:

- table        = flags.String("table", "goose_db_version", "migrations table name")
+ table        = flags.String("table", "", "migrations table name")

I believe that should maintain the order of precedence of flag > env > default.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for looking into this @mfridman! I’ve made a change that should fix it. Please let me know if there are any other changes.


args := flags.Args()

Expand Down Expand Up @@ -421,6 +423,7 @@ type envConfig struct {
driver string
dbstring string
dir string
table string
noColor bool
}

Expand All @@ -429,6 +432,7 @@ func loadEnvConfig() *envConfig {
return &envConfig{
driver: envOr("GOOSE_DRIVER", ""),
dbstring: envOr("GOOSE_DBSTRING", ""),
table: envOr("GOOSE_TABLE", ""),
dir: envOr("GOOSE_MIGRATION_DIR", DefaultMigrationDir),
// https://no-color.org/
noColor: noColorBool,
Expand All @@ -440,6 +444,7 @@ func (c *envConfig) listEnvs() []envVar {
{Name: "GOOSE_DRIVER", Value: c.driver},
{Name: "GOOSE_DBSTRING", Value: c.dbstring},
{Name: "GOOSE_MIGRATION_DIR", Value: c.dir},
{Name: "GOOSE_TABLE", Value: c.table},
{Name: "NO_COLOR", Value: strconv.FormatBool(c.noColor)},
}
}
Expand All @@ -457,3 +462,13 @@ func envOr(key, def string) string {
}
return val
}

// firstNonEmpty returns the first non-empty string from the provided input or an empty string if all are empty.
func firstNonEmpty(values ...string) string {
for _, v := range values {
if v != "" {
return v
}
}
return ""
}
68 changes: 68 additions & 0 deletions cmd/goose/main_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package main

import (
"testing"
)

func TestFirstNonEmpty(t *testing.T) {
tests := []struct {
name string
input []string
expected string
}{
{
name: "no values",
input: []string{},
expected: "",
},
{
name: "all empty values",
input: []string{"", "", ""},
expected: "",
},
{
name: "single non-empty value at start",
input: []string{"value", "", ""},
expected: "value",
},
{
name: "single non-empty value in middle",
input: []string{"", "value", ""},
expected: "value",
},
{
name: "single non-empty value at end",
input: []string{"", "", "value"},
expected: "value",
},
{
name: "multiple non-empty values",
input: []string{"first", "second", "third"},
expected: "first",
},
{
name: "mixed empty and non-empty values",
input: []string{"", "value1", "", "value2"},
expected: "value1",
},
{
name: "only one value, empty",
input: []string{""},
expected: "",
},
{
name: "only one value, non-empty",
input: []string{"value"},
expected: "value",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := firstNonEmpty(tt.input...)
if result != tt.expected {
t.Errorf("expected %q, got %q", tt.expected, result)
}
})
}
}