diff --git a/internal/exec/helmfile.go b/internal/exec/helmfile.go index fef8419a72..d75ff0bc3a 100644 --- a/internal/exec/helmfile.go +++ b/internal/exec/helmfile.go @@ -240,7 +240,8 @@ func ExecuteHelmfile(info schema.ConfigAndStacksInfo) error { if atmosConfig.Components.Helmfile.UseEKS { envVars = append(envVars, envVarsEKS...) } - + envVars = append(envVars, fmt.Sprintf("ATMOS_CLI_CONFIG_PATH=%s", atmosConfig.CliConfigPath)) + envVars = append(envVars, fmt.Sprintf("ATMOS_BASE_PATH=%s", atmosConfig.BasePath)) u.LogTrace("Using ENV vars:") for _, v := range envVars { u.LogTrace(v) diff --git a/internal/exec/terraform.go b/internal/exec/terraform.go index e19e24a721..29a3a7a17e 100644 --- a/internal/exec/terraform.go +++ b/internal/exec/terraform.go @@ -222,7 +222,8 @@ func ExecuteTerraform(info schema.ConfigAndStacksInfo) error { u.LogWarning(fmt.Sprintf("detected '%s' set in the environment; this may interfere with Atmos's control of Terraform.", varName)) } } - + info.ComponentEnvList = append(info.ComponentEnvList, fmt.Sprintf("ATMOS_CLI_CONFIG_PATH=%s", atmosConfig.CliConfigPath)) + info.ComponentEnvList = append(info.ComponentEnvList, fmt.Sprintf("ATMOS_BASE_PATH=%s", atmosConfig.BasePath)) // Set `TF_IN_AUTOMATION` ENV var to `true` to suppress verbose instructions after terraform commands // https://developer.hashicorp.com/terraform/cli/config/environment-variables#tf_in_automation info.ComponentEnvList = append(info.ComponentEnvList, "TF_IN_AUTOMATION=true") diff --git a/pkg/config/config.go b/pkg/config/config.go index 66f9adbf02..2c12d8f0ce 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -139,7 +139,7 @@ func InitCliConfig(configAndStacksInfo schema.ConfigAndStacksInfo, processStacks // Process config in system folder configFilePath1 := "" - + atmosConfigFilePath := "" // https://pureinfotech.com/list-environment-variables-windows-10/ // https://docs.microsoft.com/en-us/windows/deployment/usmt/usmt-recognized-environment-variables // https://softwareengineering.stackexchange.com/questions/299869/where-is-the-appropriate-place-to-put-application-configuration-files-for-each-p @@ -161,6 +161,7 @@ func InitCliConfig(configAndStacksInfo schema.ConfigAndStacksInfo, processStacks } if found { configFound = true + atmosConfigFilePath = configFile1 } } @@ -176,6 +177,7 @@ func InitCliConfig(configAndStacksInfo schema.ConfigAndStacksInfo, processStacks } if found { configFound = true + atmosConfigFilePath = configFile2 } // Process config in the current dir @@ -190,6 +192,7 @@ func InitCliConfig(configAndStacksInfo schema.ConfigAndStacksInfo, processStacks } if found { configFound = true + atmosConfigFilePath = configFile3 } // Process config from the path in ENV var `ATMOS_CLI_CONFIG_PATH` @@ -203,6 +206,7 @@ func InitCliConfig(configAndStacksInfo schema.ConfigAndStacksInfo, processStacks } if found { configFound = true + atmosConfigFilePath = configFile4 } } @@ -217,6 +221,7 @@ func InitCliConfig(configAndStacksInfo schema.ConfigAndStacksInfo, processStacks } if found { configFound = true + atmosConfigFilePath = configFile5 } } } @@ -256,7 +261,16 @@ func InitCliConfig(configAndStacksInfo schema.ConfigAndStacksInfo, processStacks if err != nil { return atmosConfig, err } - + // Set the CLI config path in the atmosConfig struct + if filepath.IsAbs(atmosConfigFilePath) { + atmosConfig.CliConfigPath = atmosConfigFilePath + } else { + absPath, err := filepath.Abs(atmosConfigFilePath) + if err != nil { + return atmosConfig, err + } + atmosConfig.CliConfigPath = absPath + } // Process ENV vars err = processEnvVars(&atmosConfig) if err != nil { diff --git a/pkg/schema/schema.go b/pkg/schema/schema.go index bcb9efa4c9..eb968c16d0 100644 --- a/pkg/schema/schema.go +++ b/pkg/schema/schema.go @@ -36,7 +36,8 @@ type AtmosConfiguration struct { // Stores is never read from yaml, it is populated in processStoreConfig and it's used to pass to the populated store // registry through to the yaml parsing functions when !store is run and to pass the registry to the hooks // functions to be able to call stores from within hooks. - Stores store.StoreRegistry `yaml:"stores_registry,omitempty" json:"stores_registry,omitempty" mapstructure:"stores_registry"` + Stores store.StoreRegistry `yaml:"stores_registry,omitempty" json:"stores_registry,omitempty" mapstructure:"stores_registry"` + CliConfigPath string `yaml:"cli_config_path" json:"cli_config_path,omitempty" mapstructure:"cli_config_path"` } type Validate struct { diff --git a/tests/fixtures/components/terraform/env-example/main.tf b/tests/fixtures/components/terraform/env-example/main.tf new file mode 100644 index 0000000000..7746c6e101 --- /dev/null +++ b/tests/fixtures/components/terraform/env-example/main.tf @@ -0,0 +1,13 @@ +terraform { + required_providers { + environment = { + source = "EppO/environment" + version = "~> 1.3.0" # Check for latest version + } + } +} + +# Get all environment variables matching patterns +data "environment_variables" "required" { + filter = "^ATMOS_.*|^EXAMPLE$" # Regex pattern +} diff --git a/tests/fixtures/components/terraform/env-example/outputs.tf b/tests/fixtures/components/terraform/env-example/outputs.tf new file mode 100644 index 0000000000..d21bb03405 --- /dev/null +++ b/tests/fixtures/components/terraform/env-example/outputs.tf @@ -0,0 +1,25 @@ +output "atmos_cli_config_path" { + value = data.environment_variables.required.items["ATMOS_CLI_CONFIG_PATH"] + description = "The path to the Atmos CLI configuration file" +} + +output "atmos_base_path" { + value = data.environment_variables.required.items["ATMOS_BASE_PATH"] + description = "The base path used by Atmos" +} + +output "example" { + value = data.environment_variables.required.items["EXAMPLE"] + description = "Example environment variable" +} + +# Output all matched variables +output "all_atmos_vars" { + value = data.environment_variables.required.items + description = "All matched environment variables" +} + +variable "stage" { + type = string + description = "Deployment stage/environment (e.g., dev, prod)" +} diff --git a/tests/fixtures/scenarios/env/atmos.yaml b/tests/fixtures/scenarios/env/atmos.yaml new file mode 100644 index 0000000000..0b07b4bdff --- /dev/null +++ b/tests/fixtures/scenarios/env/atmos.yaml @@ -0,0 +1,21 @@ +base_path: "./" + +components: + terraform: + base_path: "../../components/terraform" + apply_auto_approve: true + deploy_run_init: true + init_run_reconfigure: true + auto_generate_backend_file: false + +stacks: + base_path: "stacks" + included_paths: + - "deploy/**/*" + excluded_paths: + - "**/_defaults.yaml" + name_pattern: "{stage}" + +logs: + file: "/dev/stderr" + level: Info diff --git a/tests/fixtures/scenarios/env/stacks/catalog/example.yaml b/tests/fixtures/scenarios/env/stacks/catalog/example.yaml new file mode 100644 index 0000000000..07059db32d --- /dev/null +++ b/tests/fixtures/scenarios/env/stacks/catalog/example.yaml @@ -0,0 +1,10 @@ +# yaml-language-server: $schema=https://atmos.tools/schemas/atmos/atmos-manifest/1.0/atmos-manifest.json +env: + EXAMPLE: "test" + +components: + terraform: + env-example: + metadata: + component: env-example + vars: {} diff --git a/tests/fixtures/scenarios/env/stacks/deploy/dev.yaml b/tests/fixtures/scenarios/env/stacks/deploy/dev.yaml new file mode 100644 index 0000000000..a5fa85adfc --- /dev/null +++ b/tests/fixtures/scenarios/env/stacks/deploy/dev.yaml @@ -0,0 +1,12 @@ +# yaml-language-server: $schema=https://atmos.tools/schemas/atmos/atmos-manifest/1.0/atmos-manifest.json + +vars: + stage: dev + +import: + - catalog/example + +components: + terraform: + env-example: + vars: {} diff --git a/tests/fixtures/scenarios/env/stacks/deploy/prod.yaml b/tests/fixtures/scenarios/env/stacks/deploy/prod.yaml new file mode 100644 index 0000000000..ded0e5e741 --- /dev/null +++ b/tests/fixtures/scenarios/env/stacks/deploy/prod.yaml @@ -0,0 +1,12 @@ +# yaml-language-server: $schema=https://atmos.tools/schemas/atmos/atmos-manifest/1.0/atmos-manifest.json + +vars: + stage: prod + +import: + - catalog/example + +components: + terraform: + env-example: + vars: {} diff --git a/tests/fixtures/scenarios/env/stacks/deploy/staging.yaml b/tests/fixtures/scenarios/env/stacks/deploy/staging.yaml new file mode 100644 index 0000000000..09b34a8a74 --- /dev/null +++ b/tests/fixtures/scenarios/env/stacks/deploy/staging.yaml @@ -0,0 +1,12 @@ +# yaml-language-server: $schema=https://atmos.tools/schemas/atmos/atmos-manifest/1.0/atmos-manifest.json + +vars: + stage: staging + +import: + - catalog/example + +components: + terraform: + env-example: + vars: {} diff --git a/tests/snapshots/TestCLICommands_atmos_describe_config.stdout.golden b/tests/snapshots/TestCLICommands_atmos_describe_config.stdout.golden index 89551af680..5a4d543646 100644 --- a/tests/snapshots/TestCLICommands_atmos_describe_config.stdout.golden +++ b/tests/snapshots/TestCLICommands_atmos_describe_config.stdout.golden @@ -148,5 +148,6 @@ "editorconfig": { "color": true } - } + }, + "cli_config_path": "/absolute/path/to/repo/examples/demo-stacks/atmos" } diff --git a/tests/snapshots/TestCLICommands_atmos_describe_config_-f_yaml.stdout.golden b/tests/snapshots/TestCLICommands_atmos_describe_config_-f_yaml.stdout.golden index 7ca1700008..c50127f755 100644 --- a/tests/snapshots/TestCLICommands_atmos_describe_config_-f_yaml.stdout.golden +++ b/tests/snapshots/TestCLICommands_atmos_describe_config_-f_yaml.stdout.golden @@ -46,4 +46,5 @@ default: false validate: editorconfig: color: true +cli_config_path: /absolute/path/to/repo/examples/demo-stacks/atmos diff --git a/tests/test-cases/env.yaml b/tests/test-cases/env.yaml new file mode 100644 index 0000000000..5f7011c190 --- /dev/null +++ b/tests/test-cases/env.yaml @@ -0,0 +1,22 @@ +# yaml-language-server: $schema=schema.json +tests: + - name: atmos_terraform_apply_env + snapshot: false + enabled: true + description: "Ensure atmos export atmos_base_path and atmos_cli_config_path" + workdir: "fixtures/scenarios/env" + command: "atmos" + args: + - "terraform" + - "apply" + - "env-example" + - "-s" + - "dev" + expect: + diff: [] + stdout: + - 'atmos_base_path = "./"' + - 'atmos_cli_config_path = ".*tests.*fixtures.*scenarios.*env.*atmos"' + stderr: + - "^$" + exit_code: 0