Skip to content
Open
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
10 changes: 10 additions & 0 deletions internal/cli/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,16 @@ var (
errInvalidTimeFormat = errors.New("time format may not be empty")
)

// databaseFromEnv reads the database connection string from the specified environment variable.
// Returns the value if set, or an error if the environment variable is not set or empty.
func databaseFromEnv(envName string) (string, error) {
val := os.Getenv(envName)
if val == "" {
return "", fmt.Errorf("environment variable %s is not set or empty", envName)
}
return val, nil
}

func nextSeqVersion(matches []string, seqDigits int) (string, error) {
if seqDigits <= 0 {
return "", errInvalidSequenceWidth
Expand Down
41 changes: 41 additions & 0 deletions internal/cli/commands_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,47 @@
}
}

func TestDatabaseFromEnv(t *testing.T) {
cases := []struct {
name string
envName string
envValue string
setEnv bool
expectedResult string
expectedErrStr string
}{
{"valid env var", "TEST_DB_URL", "postgres://localhost:5432/test", true, "postgres://localhost:5432/test", ""},
{"empty env var", "TEST_DB_URL_EMPTY", "", true, "", "environment variable TEST_DB_URL_EMPTY is not set or empty"},
{"unset env var", "TEST_DB_URL_UNSET", "", false, "", "environment variable TEST_DB_URL_UNSET is not set or empty"},
}

for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
if c.setEnv {
os.Setenv(c.envName, c.envValue)

Check failure on line 273 in internal/cli/commands_test.go

View workflow job for this annotation

GitHub Actions / lint

Error return value of `os.Setenv` is not checked (errcheck)
defer os.Unsetenv(c.envName)

Check failure on line 274 in internal/cli/commands_test.go

View workflow job for this annotation

GitHub Actions / lint

Error return value of `os.Unsetenv` is not checked (errcheck)
}

result, err := databaseFromEnv(c.envName)

if c.expectedErrStr != "" {
if err == nil {
t.Errorf("Expected error: %s but got nil", c.expectedErrStr)
} else if err.Error() != c.expectedErrStr {
t.Errorf("Expected error: %s but got: %s", c.expectedErrStr, err.Error())
}
} else {
if err != nil {
t.Errorf("Unexpected error: %s", err.Error())
}
if result != c.expectedResult {
t.Errorf("Expected result: %s but got: %s", c.expectedResult, result)
}
}
})
}
}

func TestNumDownFromArgs(t *testing.T) {
cases := []struct {
name string
Expand Down
11 changes: 11 additions & 0 deletions internal/cli/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ func Main(version string) {
pathPtr := flag.String("path", "", "")
databasePtr := flag.String("database", "", "")
sourcePtr := flag.String("source", "", "")
envPtr := flag.String("env", "", "")

flag.Usage = func() {
fmt.Fprintf(os.Stderr,
Expand All @@ -78,6 +79,7 @@ Options:
-source Location of the migrations (driver://url)
-path Shorthand for -source=file://path
-database Run migrations against this database (driver://url)
-env Read database connection string from environment variable
-prefetch N Number of migrations to load in advance before executing (default 10)
-lock-timeout N Allow N seconds to acquire database lock (default 15)
-verbose Print verbose logging
Expand Down Expand Up @@ -119,6 +121,15 @@ Database drivers: `+strings.Join(database.List(), ", ")+"\n", createUsage, gotoU
*sourcePtr = fmt.Sprintf("file://%v", *pathPtr)
}

// read database connection string from environment variable if -env is given
if *envPtr != "" {
dbFromEnv, err := databaseFromEnv(*envPtr)
if err != nil {
log.fatalErr(err)
}
*databasePtr = dbFromEnv
}

// initialize migrate
// don't catch migraterErr here and let each command decide
// how it wants to handle the error
Expand Down
Loading