Skip to content

Commit 6b06c6b

Browse files
committed
SDP-1934 Add configurable environment file loading to support multiple deployment contexts
1 parent 35d5f2f commit 6b06c6b

File tree

8 files changed

+527
-11
lines changed

8 files changed

+527
-11
lines changed

cmd/root.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,14 @@ func rootCmd() *cobra.Command {
6666
FlagDefault: "http://localhost:3000",
6767
Required: true,
6868
},
69+
// env-file flag is already handled in main.go, but it needs to be also defined here because Cobra doesn't allow unknown flags.
70+
{
71+
Name: "env-file",
72+
Usage: "Path to environment file to load (e.g., \"dev/.env.https-testnet\"). Supports absolute and relative paths. Defaults to \".env\" if not specified.",
73+
OptType: types.String,
74+
ConfigKey: &globalOptions.EnvFile,
75+
Required: false,
76+
},
6977
cmdUtils.NetworkPassphrase(&globalOptions.NetworkPassphrase),
7078
}
7179

cmd/utils/env_loader.go

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
package utils
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
"os"
7+
"path/filepath"
8+
"strings"
9+
10+
"github.com/joho/godotenv"
11+
)
12+
13+
const (
14+
envFileFlag = "--env-file"
15+
envFileEnvVar = "ENV_FILE"
16+
)
17+
18+
// LoadEnvFile loads environment variables from a file.
19+
// Priority: --env-file flag > ENV_FILE environment variable > .env in working directory
20+
func LoadEnvFile() error {
21+
envFilePath := determineEnvFilePath()
22+
23+
if envFilePath != "" {
24+
return loadExplicitEnvFile(envFilePath)
25+
}
26+
27+
return loadDefaultEnvFile()
28+
}
29+
30+
// determineEnvFilePath determines the path to the env file based on priority.
31+
func determineEnvFilePath() string {
32+
if path := parseEnvFileFlag(); path != "" {
33+
return toAbsolutePath(path)
34+
}
35+
36+
if path := os.Getenv(envFileEnvVar); path != "" {
37+
return toAbsolutePath(path)
38+
}
39+
40+
return ""
41+
}
42+
43+
// parseEnvFileFlag checks command-line arguments for the --env-file flag.
44+
func parseEnvFileFlag() string {
45+
for i, arg := range os.Args {
46+
if arg == envFileFlag && i+1 < len(os.Args) {
47+
return os.Args[i+1]
48+
}
49+
if strings.HasPrefix(arg, envFileFlag+"=") {
50+
return strings.TrimPrefix(arg, envFileFlag+"=")
51+
}
52+
}
53+
return ""
54+
}
55+
56+
// toAbsolutePath converts a relative path to an absolute path.
57+
func toAbsolutePath(path string) string {
58+
if path == "" || filepath.IsAbs(path) {
59+
return path
60+
}
61+
62+
absPath, err := filepath.Abs(path)
63+
if err != nil {
64+
return path
65+
}
66+
return absPath
67+
}
68+
69+
// loadExplicitEnvFile loads environment variables from the specified file.
70+
func loadExplicitEnvFile(path string) error {
71+
if err := godotenv.Load(path); err != nil {
72+
return fmt.Errorf("loading env file %s: %w", path, err)
73+
}
74+
return nil
75+
}
76+
77+
// loadDefaultEnvFile loads environment variables from the default .env file.
78+
func loadDefaultEnvFile() error {
79+
err := godotenv.Load()
80+
if err == nil {
81+
return nil
82+
}
83+
84+
if errors.Is(err, os.ErrNotExist) {
85+
return nil
86+
}
87+
88+
return fmt.Errorf("loading .env file: %w", err)
89+
}

0 commit comments

Comments
 (0)