diff --git a/apply/apply.go b/apply/apply.go index 2adf2f42b..1fcb179db 100644 --- a/apply/apply.go +++ b/apply/apply.go @@ -219,16 +219,26 @@ func applyTFE(fs afero.Fs, plan *plan.Plan, tmpl *templates.T) error { } logrus.Debug("applying tfe") - path := fmt.Sprintf("%s/tfe", rootPath) + path := filepath.Join(rootPath, "tfe") err := fs.MkdirAll(path, 0755) if err != nil { return errors.Wrapf(err, "unable to make directory %s", path) } - err = applyTree(fs, tmpl.Components[v2.ComponentKindTerraform], tmpl.Common, path, plan.TFE) + + // only create the locals.tf.json template is one doesn't exist yet + tfePath := filepath.Join(rootPath, "tfe", "locals.tf.json") + _, err = fs.Stat(tfePath) if err != nil { - return err + if errors.Is(err, os.ErrNotExist) { + err = applyTree(fs, tmpl.TFE, tmpl.Common, path, plan.TFE) + if err != nil { + return err + } + } else { + return errors.Wrapf(err, "unable to stat on %s", tfePath) + } } - err = applyTree(fs, tmpl.TFE, tmpl.Common, path, plan.TFE) + err = applyTree(fs, tmpl.Components[v2.ComponentKindTerraform], tmpl.Common, path, plan.TFE) if err != nil { return err } @@ -243,7 +253,6 @@ func applyTFE(fs afero.Fs, plan *plan.Plan, tmpl *templates.T) error { } } - tfePath := filepath.Join("terraform", "tfe", "locals.tf.json") _, err = fs.Stat(tfePath) if err != nil { return errors.Wrapf(err, "unable to stat on %s", tfePath) diff --git a/apply/apply_test.go b/apply/apply_test.go index 415ba9688..2b2aec259 100644 --- a/apply/apply_test.go +++ b/apply/apply_test.go @@ -1,8 +1,10 @@ package apply import ( + "encoding/json" "errors" "fmt" + "io" "io/ioutil" "math/rand" "os" @@ -429,6 +431,115 @@ func TestApplyModuleInvocation(t *testing.T) { r.Equal(expected, string(i)) } +func TestTFEConfigOmitEmpty(t *testing.T) { + r := require.New(t) + testFS, d, err := util.TestFs() + r.NoError(err) + defer os.RemoveAll(d) + pwdFS, err := util.PwdFs() + r.NoError(err) + afs := afero.NewCopyOnWriteFs(pwdFS, testFS) + + plan := &plan.Plan{ + TFE: &plan.TFEConfig{}, + Envs: map[string]plan.Env{ + "prod": { + Components: map[string]plan.Component{ + "test": {}, + }, + Env: "prod", + }, + }, + } + existingLocals := LocalsTFE{ + Locals: &Locals{ + Envs: map[string]map[string]*TFEWorkspace{ + "prod": { + "test": &TFEWorkspace{}, + }, + }, + }, + } + path := fmt.Sprintf("%s/tfe", rootPath) + err = afs.MkdirAll(path, 0755) + r.NoError(err) + localsPath := filepath.Join("terraform", "tfe", "locals.tf.json") + existingLocalsFile, err := afs.OpenFile(localsPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0755) + r.NoError(err) + err = json.NewEncoder(existingLocalsFile).Encode(&existingLocals) + r.NoError(err) + existingLocalsFile.Close() + + err = applyTFE(afs, plan, templates.Templates) + r.NoError(err) + alteredLocalsFile, err := afs.Open(localsPath) + r.NoError(err) + b, err := io.ReadAll(alteredLocalsFile) + r.NoError(err) + r.Equal( + strings.Join(strings.Fields(`{"locals":{"envs":{"prod":{"test":{}}}}}`), ""), + strings.Join(strings.Fields(string(b)), "")) +} + +func TestTFEConfig(t *testing.T) { + r := require.New(t) + testFS, d, err := util.TestFs() + r.NoError(err) + defer os.RemoveAll(d) + pwdFS, err := util.PwdFs() + r.NoError(err) + afs := afero.NewCopyOnWriteFs(pwdFS, testFS) + + plan := &plan.Plan{ + TFE: &plan.TFEConfig{}, + Envs: map[string]plan.Env{ + "prod": { + Components: map[string]plan.Component{ + "test": {}, + }, + Env: "prod", + }, + }, + } + emptyTrigger := []string{} + tfVersion := "0.13.5" + existingLocals := LocalsTFE{ + Locals: &Locals{ + Envs: map[string]map[string]*TFEWorkspace{ + "prod": { + "test": &TFEWorkspace{ + TriggerPrefixes: &emptyTrigger, + TerraformVersion: &tfVersion, + }, + }, + }, + }, + } + path := fmt.Sprintf("%s/tfe", rootPath) + err = afs.MkdirAll(path, 0755) + r.NoError(err) + localsPath := filepath.Join("terraform", "tfe", "locals.tf.json") + existingLocalsFile, err := afs.OpenFile(localsPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0755) + r.NoError(err) + err = json.NewEncoder(existingLocalsFile).Encode(&existingLocals) + r.NoError(err) + existingLocalsFile.Close() + + err = applyTFE(afs, plan, templates.Templates) + r.NoError(err) + locals := LocalsTFE{} + alteredLocalsFile, err := afs.Open(localsPath) + r.NoError(err) + err = json.NewDecoder(alteredLocalsFile).Decode(&locals) + r.NoError(err) + _, ok := locals.Locals.Envs["prod"] + r.True(ok) + _, ok = locals.Locals.Envs["prod"]["test"] + r.True(ok) + r.Equal(*existingLocals.Locals.Envs["prod"]["test"].TerraformVersion, *locals.Locals.Envs["prod"]["test"].TerraformVersion) + r.Equal(*existingLocals.Locals.Envs["prod"]["test"].TriggerPrefixes, *locals.Locals.Envs["prod"]["test"].TriggerPrefixes) +} + func TestApplyModuleInvocationWithEmptyVariables(t *testing.T) { r := require.New(t) testFs, d, err := util.TestFs()