diff --git a/docs/resources/env.md b/docs/resources/env.md index 3a5a7f3a..860c5170 100644 --- a/docs/resources/env.md +++ b/docs/resources/env.md @@ -44,6 +44,7 @@ resource "coder_env" "internal_api_url" { ### Optional +- `merge_strategy` (String) Controls how this environment variable is merged when multiple coder_env resources define the same name. `replace` (default): last value wins. `append`: appends to existing value with a colon `:` separator. `prepend`: prepends to existing value with a colon `:` separator. `error`: fail the build if another coder_env defines the same name. When multiple resources append or prepend to the same name, they are applied in alphabetical order by Terraform resource address. - `value` (String) The value of the environment variable. ### Read-Only diff --git a/provider/env.go b/provider/env.go index d45201ee..e00e7fa4 100644 --- a/provider/env.go +++ b/provider/env.go @@ -45,6 +45,16 @@ func envResource() *schema.Resource { ForceNew: true, Optional: true, }, + "merge_strategy": { + Type: schema.TypeString, + Description: "Controls how this environment variable is merged when multiple coder_env resources define the same name. `replace` (default): last value wins. `append`: appends to existing value with a colon `:` separator. `prepend`: prepends to existing value with a colon `:` separator. `error`: fail the build if another coder_env defines the same name. When multiple resources append or prepend to the same name, they are applied in alphabetical order by Terraform resource address.", + ForceNew: true, + Optional: true, + Default: "replace", + ValidateFunc: validation.StringInSlice([]string{ + "replace", "append", "prepend", "error", + }, false), + }, }, } } diff --git a/provider/env_test.go b/provider/env_test.go index a5892254..124e9f91 100644 --- a/provider/env_test.go +++ b/provider/env_test.go @@ -117,3 +117,78 @@ func TestEnvNoName(t *testing.T) { }}, }) } + +func TestEnvDefaultMergeStrategy(t *testing.T) { + t.Parallel() + resource.Test(t, resource.TestCase{ + ProviderFactories: coderFactory(), + IsUnitTest: true, + Steps: []resource.TestStep{{ + Config: ` + provider "coder" {} + resource "coder_env" "example" { + agent_id = "king" + name = "FOO" + value = "bar" + }`, + Check: func(state *terraform.State) error { + require.Len(t, state.Modules, 1) + require.Len(t, state.Modules[0].Resources, 1) + env := state.Modules[0].Resources["coder_env.example"] + require.NotNil(t, env) + require.Equal(t, "replace", env.Primary.Attributes["merge_strategy"]) + return nil + }, + }}, + }) +} + +func TestEnvValidMergeStrategies(t *testing.T) { + t.Parallel() + for _, strategy := range []string{"replace", "append", "prepend", "error"} { + t.Run(strategy, func(t *testing.T) { + t.Parallel() + resource.Test(t, resource.TestCase{ + ProviderFactories: coderFactory(), + IsUnitTest: true, + Steps: []resource.TestStep{{ + Config: ` + provider "coder" {} + resource "coder_env" "example" { + agent_id = "king" + name = "FOO" + value = "bar" + merge_strategy = "` + strategy + `" + }`, + Check: func(state *terraform.State) error { + require.Len(t, state.Modules, 1) + require.Len(t, state.Modules[0].Resources, 1) + env := state.Modules[0].Resources["coder_env.example"] + require.NotNil(t, env) + require.Equal(t, strategy, env.Primary.Attributes["merge_strategy"]) + return nil + }, + }}, + }) + }) + } +} + +func TestEnvInvalidMergeStrategy(t *testing.T) { + t.Parallel() + resource.Test(t, resource.TestCase{ + ProviderFactories: coderFactory(), + IsUnitTest: true, + Steps: []resource.TestStep{{ + Config: ` + provider "coder" {} + resource "coder_env" "example" { + agent_id = "king" + name = "FOO" + value = "bar" + merge_strategy = "concat" + }`, + ExpectError: regexp.MustCompile(`expected merge_strategy to be one of`), + }}, + }) +}