Skip to content
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
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
19 changes: 17 additions & 2 deletions cmd/goose/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ var (

flags = flag.NewFlagSet("goose", flag.ExitOnError)
dir = flags.String("dir", DefaultMigrationDir, "directory with migration files, (GOOSE_MIGRATION_DIR env variable supported)")
table = flags.String("table", "goose_db_version", "migrations table name")
table = flags.String("table", "", "migrations table name")
verbose = flags.Bool("v", false, "enable verbose mode")
help = flags.Bool("h", false, "print help")
versionFlag = flags.Bool("version", false, "print version")
Expand Down Expand Up @@ -83,7 +83,9 @@ func main() {
if *sequential {
goose.SetSequential(true)
}
goose.SetTableName(*table)

// The order of precedence should be: flag > env variable > default value.
goose.SetTableName(firstNonEmpty(*table, envConfig.table, goose.DefaultTablename))

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)
}
})
}
}