diff --git a/.gitignore b/.gitignore index 438f867..ad9a234 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ dist bin +.idea diff --git a/README.md b/README.md index b6d66a1..cbf29a1 100644 --- a/README.md +++ b/README.md @@ -49,3 +49,46 @@ Once initialized, the CLI is ready to use: ```shell workos [cmd] [args] ``` + +### Environment Variables +WorkOS CLI support environment variables for initialization and environment management. + +| Environment Variable | Description | Supported Values | +|---------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------|----------------------| +| WORKOS_ACTIVE_ENVIRONMENT | Sets the selected environment in your .workos.json file. Use `headless` to override environment configs with other environment variable overrides. | | +| WORKOS_ENVIRONMENTS_HEADLESS_NAME | Sets the name of the environment | | +| WORKOS_ENVIRONMENTS_HEADLESS_ENDPOINT | Sets the base endpoint for the environment | | +| WORKOS_ENVIRONMENTS_HEADLESS_API_KEY | Sets the API key for the environment | | +| WORKOS_ENVIRONMENTS_HEADLESS_TYPE | Sets the env type for the environment | Production / Sandbox | + +#### Examples + +##### Set the active environment + +```shell +export WORKOS_ACTIVE_ENVIRONMENT=local +``` + +`.workos.json` +```json +{ + "environments": { + "local": { + "endpoint": "http://localhost:8001", + "apiKey": "", + "type": "Sandbox", + "name": "local" + } + } +} +``` + +##### Headless Mode + +```shell +export WORKOS_ACTIVE_ENVIRONMENT=headless +export WORKOS_ENVIRONMENTS_HEADLESS_NAME=local +export WORKOS_ENVIRONMENTS_HEADLESS_ENDPOINT=http://localhost:8001 +export WORKOS_ENVIRONMENTS_HEADLESS_API_KEY= +export WORKOS_ENVIRONMENTS_HEADLESS_TYPE=Sandbox +``` diff --git a/internal/config/config.go b/internal/config/config.go index 9d42df3..090a287 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -3,17 +3,19 @@ package config import ( "encoding/json" "errors" - "io/fs" - "os" - "github.com/spf13/cobra" "github.com/spf13/viper" + "io/fs" + "os" + "strings" ) const ( - FilePrefix = ".workos" - FileExtension = "json" - FileName = FilePrefix + "." + FileExtension + EnvVarPrefix = "WORKOS" + EnvVarHeadlessMode = "headless" + FilePrefix = ".workos" + FileExtension = "json" + FileName = FilePrefix + "." + FileExtension ) type Config struct { @@ -44,22 +46,50 @@ func (c Config) Write() error { return nil } -func LoadConfig() *Config { - // Look for .workos.json in HOME dir and create an empty version if it doesn't exist - homeDir, err := os.UserHomeDir() - cobra.CheckErr(err) - _, err = os.Stat(homeDir + "/" + FileName) +// Creates an empty config file if it doesn't exist +func createEmptyConfigFile(dir string) { + _, err := os.Stat(dir + "/" + FileName) if errors.Is(err, fs.ErrNotExist) { emptyJson := []byte("{}") - err = os.WriteFile(homeDir+"/"+FileName, emptyJson, 0644) + err = os.WriteFile(dir+"/"+FileName, emptyJson, 0644) cobra.CheckErr(err) } +} + +// Loads config values from environment variables if active environment is set to headless mode +// Supports overriding nested json keys with environment variables +// e.g. environments.headless.endpoint -> WORKOS_ENVIRONMENTS_HEADLESS_ENDPOINT +func loadEnvVarOverrides() { + viper.SetEnvPrefix(EnvVarPrefix) + // replace '.' in env var names with '_' to support overriding nested json keys + viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) + // read in environment variables that match + viper.AutomaticEnv() + + _ = viper.BindEnv("active_environment") + activeEnvironment := viper.Get("active_environment") + + // Binds environment variables to nested json keys which allows unmarshalling into struct + if activeEnvironment == EnvVarHeadlessMode { + _ = viper.BindEnv("environments.headless.endpoint") + _ = viper.BindEnv("environments.headless.type") + _ = viper.BindEnv("environments.headless.name") + _ = viper.BindEnv("environments.headless.api_key") + } +} + +func LoadConfig() *Config { + homeDir, err := os.UserHomeDir() + cobra.CheckErr(err) + createEmptyConfigFile(homeDir) // Load config from ~/.workos.json viper.AddConfigPath(homeDir) viper.SetConfigType(FileExtension) viper.SetConfigName(FilePrefix) - viper.AutomaticEnv() // read in environment variables that match + + loadEnvVarOverrides() + err = viper.ReadInConfig() cobra.CheckErr(err)