Skip to content

Commit dbadcf7

Browse files
authored
feat: add merge_strategy attribute to coder_env resource (#489)
Add an optional merge_strategy attribute that controls how environment variables are combined when multiple coder_env resources define the same name. Valid values: replace (default), append, prepend, error. - Default 'replace' preserves backward compatibility - ForceNew: true ensures strategy changes recreate the resource - Validated with StringInSlice matching existing codebase patterns - Added tests for default value, all valid values, and invalid rejection - Updated docs with merge_strategy description and PATH append example
1 parent b3ec3a9 commit dbadcf7

3 files changed

Lines changed: 86 additions & 0 deletions

File tree

docs/resources/env.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ resource "coder_env" "internal_api_url" {
4444

4545
### Optional
4646

47+
- `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.
4748
- `value` (String) The value of the environment variable.
4849

4950
### Read-Only

provider/env.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,16 @@ func envResource() *schema.Resource {
4545
ForceNew: true,
4646
Optional: true,
4747
},
48+
"merge_strategy": {
49+
Type: schema.TypeString,
50+
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.",
51+
ForceNew: true,
52+
Optional: true,
53+
Default: "replace",
54+
ValidateFunc: validation.StringInSlice([]string{
55+
"replace", "append", "prepend", "error",
56+
}, false),
57+
},
4858
},
4959
}
5060
}

provider/env_test.go

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,3 +117,78 @@ func TestEnvNoName(t *testing.T) {
117117
}},
118118
})
119119
}
120+
121+
func TestEnvDefaultMergeStrategy(t *testing.T) {
122+
t.Parallel()
123+
resource.Test(t, resource.TestCase{
124+
ProviderFactories: coderFactory(),
125+
IsUnitTest: true,
126+
Steps: []resource.TestStep{{
127+
Config: `
128+
provider "coder" {}
129+
resource "coder_env" "example" {
130+
agent_id = "king"
131+
name = "FOO"
132+
value = "bar"
133+
}`,
134+
Check: func(state *terraform.State) error {
135+
require.Len(t, state.Modules, 1)
136+
require.Len(t, state.Modules[0].Resources, 1)
137+
env := state.Modules[0].Resources["coder_env.example"]
138+
require.NotNil(t, env)
139+
require.Equal(t, "replace", env.Primary.Attributes["merge_strategy"])
140+
return nil
141+
},
142+
}},
143+
})
144+
}
145+
146+
func TestEnvValidMergeStrategies(t *testing.T) {
147+
t.Parallel()
148+
for _, strategy := range []string{"replace", "append", "prepend", "error"} {
149+
t.Run(strategy, func(t *testing.T) {
150+
t.Parallel()
151+
resource.Test(t, resource.TestCase{
152+
ProviderFactories: coderFactory(),
153+
IsUnitTest: true,
154+
Steps: []resource.TestStep{{
155+
Config: `
156+
provider "coder" {}
157+
resource "coder_env" "example" {
158+
agent_id = "king"
159+
name = "FOO"
160+
value = "bar"
161+
merge_strategy = "` + strategy + `"
162+
}`,
163+
Check: func(state *terraform.State) error {
164+
require.Len(t, state.Modules, 1)
165+
require.Len(t, state.Modules[0].Resources, 1)
166+
env := state.Modules[0].Resources["coder_env.example"]
167+
require.NotNil(t, env)
168+
require.Equal(t, strategy, env.Primary.Attributes["merge_strategy"])
169+
return nil
170+
},
171+
}},
172+
})
173+
})
174+
}
175+
}
176+
177+
func TestEnvInvalidMergeStrategy(t *testing.T) {
178+
t.Parallel()
179+
resource.Test(t, resource.TestCase{
180+
ProviderFactories: coderFactory(),
181+
IsUnitTest: true,
182+
Steps: []resource.TestStep{{
183+
Config: `
184+
provider "coder" {}
185+
resource "coder_env" "example" {
186+
agent_id = "king"
187+
name = "FOO"
188+
value = "bar"
189+
merge_strategy = "concat"
190+
}`,
191+
ExpectError: regexp.MustCompile(`expected merge_strategy to be one of`),
192+
}},
193+
})
194+
}

0 commit comments

Comments
 (0)