From 860c08472efdc87d4f5906ebe482d6ebb823466a Mon Sep 17 00:00:00 2001 From: jackwrfuller Date: Sat, 7 Dec 2024 15:25:46 +1100 Subject: [PATCH 1/9] add support for global .env file --- ahoy.go | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/ahoy.go b/ahoy.go index 1213a8b..17e9aa7 100644 --- a/ahoy.go +++ b/ahoy.go @@ -172,9 +172,38 @@ func getSubCommands(includes []string) []cli.Command { return subCommands } +// Given a filepath, return a string array of environment variables. +func getEnvironmentVars(envFile string) []string { + var envVars []string + + env, err := os.ReadFile(envFile) + if err != nil { + return nil + } + + lines := strings.Split(string(env), "\n") + for _, line := range lines { + line = strings.TrimSpace(line) + + // Ignore empty lines and comments (lines starting with '#'). + if line == "" || strings.HasPrefix(line, "#") { + continue + } + + envVars = append(envVars, line) + } + + return envVars +} + func getCommands(config Config) []cli.Command { exportCmds := []cli.Command{} + // Get environment variables defined in '.env' file + // located in the Ahoy source directory. + globalEnvFile := filepath.Join(AhoyConf.srcDir, ".env") + envVars := getEnvironmentVars(globalEnvFile) + var keys []string for k := range config.Commands { keys = append(keys, k) @@ -247,6 +276,7 @@ func getCommands(config Config) []cli.Command { command.Stdout = os.Stdout command.Stdin = os.Stdin command.Stderr = os.Stderr + command.Env = append(command.Env, envVars...) if err := command.Run(); err != nil { fmt.Fprintln(os.Stderr) os.Exit(1) From 983dd6c7cc5b6d9daaa2914011a6586fd2d3e42d Mon Sep 17 00:00:00 2001 From: jackwrfuller Date: Sat, 7 Dec 2024 15:40:36 +1100 Subject: [PATCH 2/9] add global env file specifier in the config --- ahoy.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ahoy.go b/ahoy.go index 17e9aa7..1c959aa 100644 --- a/ahoy.go +++ b/ahoy.go @@ -24,6 +24,7 @@ type Config struct { AhoyAPI string Commands map[string]Command Entrypoint []string + Env string } // Command is an ahoy command detailed in ahoy.yml files. Multiple @@ -203,6 +204,11 @@ func getCommands(config Config) []cli.Command { // located in the Ahoy source directory. globalEnvFile := filepath.Join(AhoyConf.srcDir, ".env") envVars := getEnvironmentVars(globalEnvFile) + + // If a global environment variable file is defined, use that too. + if config.Env != "" { + envVars = append(envVars, getEnvironmentVars(config.Env)...) + } var keys []string for k := range config.Commands { From 71ee5b44182bc5a07af0bb5484fb444ec949da52 Mon Sep 17 00:00:00 2001 From: jackwrfuller Date: Sat, 7 Dec 2024 15:46:20 +1100 Subject: [PATCH 3/9] add command-level env file support --- ahoy.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ahoy.go b/ahoy.go index 1c959aa..b5a60be 100644 --- a/ahoy.go +++ b/ahoy.go @@ -33,6 +33,7 @@ type Command struct { Description string Usage string Cmd string + Env string Hide bool Optional bool Imports []string @@ -273,6 +274,11 @@ func getCommands(config Config) []cli.Command { } } cmdItems = append(cmdEntrypoint, cmdArgs...) + + // If defined, included specified command-level environment variables + if cmd.Env != "" { + envVars = append(envVars, getEnvironmentVars(cmd.Env)...) + } if verbose { log.Println("===> AHOY", name, "from", sourcefile, ":", cmdItems) From 10e3dca5b996d7e9f2df5c6e6ccdae7b923a0691 Mon Sep 17 00:00:00 2001 From: jackwrfuller Date: Mon, 9 Dec 2024 11:58:18 +1100 Subject: [PATCH 4/9] add tests for env var feature --- ahoy.go | 15 +++++++-------- testdata/.env | 2 ++ testdata/.env.cmd | 2 ++ testdata/env.ahoy.yml | 17 +++++++++++++++++ tests/environment-variables.bats | 21 +++++++++++++++++++++ 5 files changed, 49 insertions(+), 8 deletions(-) create mode 100644 testdata/.env create mode 100644 testdata/.env.cmd create mode 100644 testdata/env.ahoy.yml create mode 100644 tests/environment-variables.bats diff --git a/ahoy.go b/ahoy.go index b5a60be..a6bc2dc 100644 --- a/ahoy.go +++ b/ahoy.go @@ -180,7 +180,8 @@ func getEnvironmentVars(envFile string) []string { env, err := os.ReadFile(envFile) if err != nil { - return nil + logger("fatal", "Invalid env file: " + envFile) + return nil } lines := strings.Split(string(env), "\n") @@ -200,15 +201,12 @@ func getEnvironmentVars(envFile string) []string { func getCommands(config Config) []cli.Command { exportCmds := []cli.Command{} - - // Get environment variables defined in '.env' file - // located in the Ahoy source directory. - globalEnvFile := filepath.Join(AhoyConf.srcDir, ".env") - envVars := getEnvironmentVars(globalEnvFile) + envVars := []string{} // If a global environment variable file is defined, use that too. if config.Env != "" { - envVars = append(envVars, getEnvironmentVars(config.Env)...) + globalEnvFile := filepath.Join(AhoyConf.srcDir, config.Env) + envVars = append(envVars, getEnvironmentVars(globalEnvFile)...) } var keys []string @@ -277,7 +275,8 @@ func getCommands(config Config) []cli.Command { // If defined, included specified command-level environment variables if cmd.Env != "" { - envVars = append(envVars, getEnvironmentVars(cmd.Env)...) + cmdEnvFile := filepath.Join(AhoyConf.srcDir, cmd.Env) + envVars = append(envVars, getEnvironmentVars(cmdEnvFile)...) } if verbose { diff --git a/testdata/.env b/testdata/.env new file mode 100644 index 0000000..c90c12d --- /dev/null +++ b/testdata/.env @@ -0,0 +1,2 @@ +GLOBAL=global +TO_BE_OVERRIDEN=before diff --git a/testdata/.env.cmd b/testdata/.env.cmd new file mode 100644 index 0000000..c3ed933 --- /dev/null +++ b/testdata/.env.cmd @@ -0,0 +1,2 @@ +COMMAND=123456789 +TO_BE_OVERRIDEN=after diff --git a/testdata/env.ahoy.yml b/testdata/env.ahoy.yml new file mode 100644 index 0000000..df0f47e --- /dev/null +++ b/testdata/env.ahoy.yml @@ -0,0 +1,17 @@ +ahoyapi: v2 +env: ./.env +commands: + test-global: + cmd: echo $GLOBAL + + test-cmd: + cmd: echo $COMMAND + env: .env.cmd + + test-override: + cmd: echo $TO_BE_OVERRIDEN + env: .env.cmd + + test-invalid-env: + cmd: echo "This should not print!" + env: .env.thisfiledoesntexist diff --git a/tests/environment-variables.bats b/tests/environment-variables.bats new file mode 100644 index 0000000..b3923f2 --- /dev/null +++ b/tests/environment-variables.bats @@ -0,0 +1,21 @@ +#!/usr/bin/env bats + +@test "Command-level variables can be defined and used" { + run ./ahoy -f testdata/env.ahoy.yml test-cmd + [[ "$output" == "123456789" ]] +} + +@test "Environment variables can be overriden" { + run ./ahoy -f testdata/env.ahoy.yml test-override + [[ "$output" = "after" ]] +} + +@test "Global variables can be defined and used" { + run ./ahoy -f testdata/env.ahoy.yml test-global + [[ "$output" = "global" ]] +} + +@test "Fail when attempting to load invalid env files" { + run ./ahoy -f testdata/env.ahoy.yml test-invalid-env + [ $status -eq 1 ] +} From eef9e13829aa78f0d2b25126a85e5da509aca816 Mon Sep 17 00:00:00 2001 From: jackwrfuller Date: Mon, 9 Dec 2024 12:20:21 +1100 Subject: [PATCH 5/9] fix formatting --- ahoy.go | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/ahoy.go b/ahoy.go index a6bc2dc..52eeb83 100644 --- a/ahoy.go +++ b/ahoy.go @@ -187,15 +187,13 @@ func getEnvironmentVars(envFile string) []string { lines := strings.Split(string(env), "\n") for _, line := range lines { line = strings.TrimSpace(line) - + // Ignore empty lines and comments (lines starting with '#'). if line == "" || strings.HasPrefix(line, "#") { continue } - envVars = append(envVars, line) } - return envVars } @@ -205,8 +203,8 @@ func getCommands(config Config) []cli.Command { // If a global environment variable file is defined, use that too. if config.Env != "" { - globalEnvFile := filepath.Join(AhoyConf.srcDir, config.Env) - envVars = append(envVars, getEnvironmentVars(globalEnvFile)...) + globalEnvFile := filepath.Join(AhoyConf.srcDir, config.Env) + envVars = append(envVars, getEnvironmentVars(globalEnvFile)...) } var keys []string @@ -275,7 +273,7 @@ func getCommands(config Config) []cli.Command { // If defined, included specified command-level environment variables if cmd.Env != "" { - cmdEnvFile := filepath.Join(AhoyConf.srcDir, cmd.Env) + cmdEnvFile := filepath.Join(AhoyConf.srcDir, cmd.Env) envVars = append(envVars, getEnvironmentVars(cmdEnvFile)...) } From 47ea535787f321d46e18d8ca4182360e61150d2e Mon Sep 17 00:00:00 2001 From: jackwrfuller Date: Mon, 9 Dec 2024 12:35:25 +1100 Subject: [PATCH 6/9] align with gofmt standards --- ahoy.go | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/ahoy.go b/ahoy.go index 52eeb83..c556422 100644 --- a/ahoy.go +++ b/ahoy.go @@ -177,13 +177,13 @@ func getSubCommands(includes []string) []cli.Command { // Given a filepath, return a string array of environment variables. func getEnvironmentVars(envFile string) []string { var envVars []string - + env, err := os.ReadFile(envFile) if err != nil { - logger("fatal", "Invalid env file: " + envFile) - return nil + logger("fatal", "Invalid env file: "+envFile) + return nil } - + lines := strings.Split(string(env), "\n") for _, line := range lines { line = strings.TrimSpace(line) @@ -199,14 +199,14 @@ func getEnvironmentVars(envFile string) []string { func getCommands(config Config) []cli.Command { exportCmds := []cli.Command{} - envVars := []string{} + envVars := []string{} // If a global environment variable file is defined, use that too. if config.Env != "" { - globalEnvFile := filepath.Join(AhoyConf.srcDir, config.Env) - envVars = append(envVars, getEnvironmentVars(globalEnvFile)...) + globalEnvFile := filepath.Join(AhoyConf.srcDir, config.Env) + envVars = append(envVars, getEnvironmentVars(globalEnvFile)...) } - + var keys []string for k := range config.Commands { keys = append(keys, k) @@ -270,10 +270,10 @@ func getCommands(config Config) []cli.Command { } } cmdItems = append(cmdEntrypoint, cmdArgs...) - + // If defined, included specified command-level environment variables if cmd.Env != "" { - cmdEnvFile := filepath.Join(AhoyConf.srcDir, cmd.Env) + cmdEnvFile := filepath.Join(AhoyConf.srcDir, cmd.Env) envVars = append(envVars, getEnvironmentVars(cmdEnvFile)...) } From ad656c8528c9159025c8a7fbc2b8e28f3ed82158 Mon Sep 17 00:00:00 2001 From: jackwrfuller Date: Tue, 10 Dec 2024 08:56:44 +1100 Subject: [PATCH 7/9] add clarifying comments --- ahoy.go | 6 ++++-- testdata/.env | 4 ++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/ahoy.go b/ahoy.go index c556422..4a02200 100644 --- a/ahoy.go +++ b/ahoy.go @@ -201,7 +201,7 @@ func getCommands(config Config) []cli.Command { exportCmds := []cli.Command{} envVars := []string{} - // If a global environment variable file is defined, use that too. + // Get environment variables from the 'global' environment variable file, if it is defined. if config.Env != "" { globalEnvFile := filepath.Join(AhoyConf.srcDir, config.Env) envVars = append(envVars, getEnvironmentVars(globalEnvFile)...) @@ -271,7 +271,9 @@ func getCommands(config Config) []cli.Command { } cmdItems = append(cmdEntrypoint, cmdArgs...) - // If defined, included specified command-level environment variables + // If defined, included specified command-level environment variables. + // Note that this will intentionally override any conflicting variables + // defined in the 'global' env file. if cmd.Env != "" { cmdEnvFile := filepath.Join(AhoyConf.srcDir, cmd.Env) envVars = append(envVars, getEnvironmentVars(cmdEnvFile)...) diff --git a/testdata/.env b/testdata/.env index c90c12d..4a12d01 100644 --- a/testdata/.env +++ b/testdata/.env @@ -1,2 +1,6 @@ +# Variables defined in this file should be accessible to all Ahoy commands, +# since it is to be included in the 'global' environment variable. GLOBAL=global + +# This variable is to be overiden by the command-level env file, '.env.cmd' TO_BE_OVERRIDEN=before From 7415d63293e630e1c7d3852a9f93bf1577493d75 Mon Sep 17 00:00:00 2001 From: jackwrfuller Date: Tue, 10 Dec 2024 09:08:08 +1100 Subject: [PATCH 8/9] fix typo in TO_BE_OVERRIDEN --- testdata/.env | 2 +- testdata/.env.cmd | 2 +- testdata/env.ahoy.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/testdata/.env b/testdata/.env index 4a12d01..226facc 100644 --- a/testdata/.env +++ b/testdata/.env @@ -3,4 +3,4 @@ GLOBAL=global # This variable is to be overiden by the command-level env file, '.env.cmd' -TO_BE_OVERRIDEN=before +TO_BE_OVERRIDDEN=before diff --git a/testdata/.env.cmd b/testdata/.env.cmd index c3ed933..625957a 100644 --- a/testdata/.env.cmd +++ b/testdata/.env.cmd @@ -1,2 +1,2 @@ COMMAND=123456789 -TO_BE_OVERRIDEN=after +TO_BE_OVERRIDDEN=after diff --git a/testdata/env.ahoy.yml b/testdata/env.ahoy.yml index df0f47e..4c3bdf6 100644 --- a/testdata/env.ahoy.yml +++ b/testdata/env.ahoy.yml @@ -9,7 +9,7 @@ commands: env: .env.cmd test-override: - cmd: echo $TO_BE_OVERRIDEN + cmd: echo $TO_BE_OVERRIDDEN env: .env.cmd test-invalid-env: From d27c7ede10e02a91a6c2e7bf8d33d7f63d7d63aa Mon Sep 17 00:00:00 2001 From: Drew Robinson Date: Mon, 16 Dec 2024 18:23:00 +1100 Subject: [PATCH 9/9] Fix typo in .env example file --- testdata/.env | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testdata/.env b/testdata/.env index 226facc..4b374d9 100644 --- a/testdata/.env +++ b/testdata/.env @@ -2,5 +2,5 @@ # since it is to be included in the 'global' environment variable. GLOBAL=global -# This variable is to be overiden by the command-level env file, '.env.cmd' +# This variable is to be overridden by the command-level env file, '.env.cmd'. TO_BE_OVERRIDDEN=before