diff --git a/README.md b/README.md index 90e7357..2193cb7 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,18 @@ environment: MY_OTHER_ENV: "Another value I need" ``` +### Dotenv File +`.env` files can be loaded in by specifying the `load_env` tag. Any vars specified in the `environment` section will override values set in the dotenv file specified. + +```yaml +# .biome.yaml +name: my-biome +load_env: my_env_file.env # Specify the name of the file to load in +environment: + MY_USEFUL_ENV: "A value I need" + MY_OTHER_ENV: "Another value I need" +``` + ### AWS Environment By specifying the `aws_profile` configuration value, Biome will load that [AWS Profile](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html) from `~/.aws/credentials` and configure the environment variables and a session for this command. diff --git a/example.biome.yaml b/example.biome.yaml index 281509d..c5c2c8d 100644 --- a/example.biome.yaml +++ b/example.biome.yaml @@ -1,5 +1,6 @@ name: my-staging-biome # Required for identifying this biome aws_profile: my_staging_aws_profile # Will set the AWS environment vars +load_env: example_file.env # Load additional envs from a dotenv file environment: # Additional environment vars to load in ENVIRONMENT: staging MY_USEFUL_ENV: "A value I need" diff --git a/go.mod b/go.mod index c4ce8c2..99bd520 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,7 @@ require ( github.com/aws/aws-sdk-go-v2/credentials v1.12.4 github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.15.9 github.com/aws/aws-sdk-go-v2/service/sts v1.16.6 + github.com/joho/godotenv v1.4.0 github.com/meltwater/dragoman v1.2.2 github.com/stretchr/testify v1.7.1 gopkg.in/yaml.v3 v3.0.1 diff --git a/go.sum b/go.sum index aae46f9..1fb7956 100644 --- a/go.sum +++ b/go.sum @@ -37,6 +37,8 @@ github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg= +github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= diff --git a/src/lib/types/biome.go b/src/lib/types/biome.go index 99e6066..2559eb1 100644 --- a/src/lib/types/biome.go +++ b/src/lib/types/biome.go @@ -6,8 +6,9 @@ type Biome struct { } type BiomeConfig struct { - Name string - AwsProfile string `yaml:"aws_profile"` - Commands []string `yaml:"commands"` - Environment map[string]interface{} `yaml:"environment"` + Name string + AwsProfile string `yaml:"aws_profile"` + Commands []string `yaml:"commands"` + ExternalEnvFile string `yaml:"load_env"` + Environment map[string]interface{} `yaml:"environment"` } diff --git a/src/services/biome_configuration_service.go b/src/services/biome_configuration_service.go index 5339a87..6e51a4f 100644 --- a/src/services/biome_configuration_service.go +++ b/src/services/biome_configuration_service.go @@ -10,6 +10,7 @@ import ( "github.com/jeff-roche/biome/src/lib/setters" "github.com/jeff-roche/biome/src/lib/types" "github.com/jeff-roche/biome/src/repos" + "github.com/joho/godotenv" ) var defaultFileNames = []string{".biome.yaml", ".biome.yml"} @@ -72,12 +73,37 @@ func (svc *BiomeConfigurationService) LoadBiomeFromFile(biomeName string, fpath return nil } +// Activate biome will load up the configuration and run any setup commands before running the specified program func (svc *BiomeConfigurationService) ActivateBiome() error { if svc.ActiveBiome == nil { return fmt.Errorf("no biome loaded") } - // AWS Profile Configuration + // AWS + if err := svc.loadAws(); err != nil { + return err + } + + // Dot Env + if err := svc.loadFromEnv(svc.ActiveBiome.Config.ExternalEnvFile); err != nil { + return err + } + + // Parse all Envs + if err := svc.loadEnvs(); err != nil { + return err + } + + // Additional Commands + if err := svc.runSetupCommands(); err != nil { + return err + } + + return nil +} + +// loadAws will load in the AWS profile if one was specified +func (svc *BiomeConfigurationService) loadAws() error { if svc.ActiveBiome.Config.AwsProfile != "" { envCfg, err := svc.awsStsRepo.ConfigureSession(svc.ActiveBiome.Config.AwsProfile) if err != nil { @@ -87,6 +113,32 @@ func (svc *BiomeConfigurationService) ActivateBiome() error { svc.awsStsRepo.SetAwsEnvs(envCfg) } + return nil +} + +// loadFromEnv will load in addition environment variables from the ENV file +// Any envs specified in the biome config will override vars specified in the dotenv +func (svc *BiomeConfigurationService) loadFromEnv(fname string) error { + if fname != "" { + loadedEnvs, err := godotenv.Read(fname) + if err != nil { + return err + } + + for key, val := range loadedEnvs { + + // Only save the key if one wasn't specified in the biome config + if _, exists := svc.ActiveBiome.Config.Environment[key]; !exists { + svc.ActiveBiome.Config.Environment[key] = val + } + } + } + + return nil +} + +// loadEnvs will parse all the envs in the Environment map and load them into memory +func (svc *BiomeConfigurationService) loadEnvs() error { // Loop over the envs and set them for env, val := range svc.ActiveBiome.Config.Environment { setter, err := setters.GetEnvironmentSetter(env, val) @@ -100,12 +152,18 @@ func (svc *BiomeConfigurationService) ActivateBiome() error { } } - // Any other environment setup commands + return nil +} + +// runSetupCommands will run any command line commands specified in the biome configuration +func (svc *BiomeConfigurationService) runSetupCommands() error { if len(svc.ActiveBiome.Config.Commands) > 0 { for _, cmd := range svc.ActiveBiome.Config.Commands { parts := strings.Split(cmd, " ") - cmdr.Run(parts[0], parts[1:]...) + if err := cmdr.Run(parts[0], parts[1:]...); err != nil { + return err + } } }