# HG changeset patch
# User Florent Aide <florent.aide@gmail.com>
# Date 1652645549 -7200
#      Sun May 15 22:12:29 2022 +0200
# Node ID c4f0f586a2f15ddc7871939a2ac2d89eb1cfd76e
# Parent  dba164c9d6498ce1b1bd459627bcf78616383f68
move hydration code to CmdConfig and add variable merging

diff --git a/runner/cmd.go b/runner/cmd.go
--- a/runner/cmd.go
+++ b/runner/cmd.go
@@ -1,11 +1,15 @@
 package runner
 
 import (
+	"bytes"
+	"fmt"
 	"os"
 	"path/filepath"
+	"text/template"
 
 	"github.com/go-cmd/cmd"
 	"github.com/rs/zerolog"
+	"gopkg.in/yaml.v2"
 )
 
 func RunCMD(name string, args ...string) (err error, stdout, stderr []string) {
@@ -71,3 +75,65 @@
 	Files  []string
 	Values []Value
 }
+
+// hydrate expands templated variables in our config with concrete values
+func (c *CmdConfig) hydrate() error {
+	if err := c.hydrateHelmCharts(); err != nil {
+		return err
+	}
+	if err := c.hydrateYttCharts(); err != nil {
+		return err
+	}
+	return nil
+}
+
+func (c *CmdConfig) prepareVariables(v []Variable) map[string]string {
+	variables := make(map[string]string)
+	for _, variable := range v {
+		variables[variable.Name] = variable.Value
+	}
+	variables["namespace"] = c.Namespace
+	return variables
+}
+
+func (c *CmdConfig) hydrateYttCharts() error {
+	for entryFileName, entry := range c.Spec.Charts.Ytt {
+		for valIndex, val := range entry.Values {
+			valueTmpl, err := template.New("ytt entry value").Parse(val.Value)
+			if err != nil {
+				return fmt.Errorf("failed to parse ytt entry value as template: %q, %w", val.Value, err)
+			}
+			buf := new(bytes.Buffer)
+			if err := valueTmpl.Execute(buf, c.prepareVariables(c.Spec.Variables)); err != nil {
+				return fmt.Errorf("failed to hydrate ytt entry: %q, %w", val.Value, err)
+			}
+			// replace original content with hydrated version
+			c.Spec.Charts.Ytt[entryFileName].Values[valIndex].Value = buf.String()
+		}
+	}
+	return nil
+}
+
+func (c *CmdConfig) hydrateHelmCharts() error {
+	for name, chart := range c.Spec.Charts.Helm {
+		var newVals []string
+		for _, value := range chart.Values {
+			rawChartValue, err := yaml.Marshal(value)
+			if err != nil {
+				return fmt.Errorf("failed to get chart values as string: %w", err)
+			}
+			valueTmpl, err := template.New("chart").Parse(string(rawChartValue))
+			if err != nil {
+				return fmt.Errorf("failed to parse chart values as template: %q, %w", chart.Values, err)
+			}
+			buf := new(bytes.Buffer)
+			if err := valueTmpl.Execute(buf, c.prepareVariables(c.Spec.Variables)); err != nil {
+				return fmt.Errorf("failed to hydrate chart values entry: %q, %w", chart.Values, err)
+			}
+			newVals = append(newVals, buf.String())
+		}
+		chart.Values = newVals
+		c.Spec.Charts.Helm[name] = chart
+	}
+	return nil
+}
diff --git a/runner/config.go b/runner/config.go
--- a/runner/config.go
+++ b/runner/config.go
@@ -1,14 +1,7 @@
 package runner
 
 import (
-	"bytes"
-	"errors"
-	"fmt"
-	"os"
-	"text/template"
-
 	"github.com/spf13/viper"
-	yaml "gopkg.in/yaml.v2"
 )
 
 // Variable ...
@@ -70,67 +63,25 @@
 	return cfg, nil
 }
 
-func checkExists(path string) bool {
-	_, err := os.Stat(path)
-	return !errors.Is(err, os.ErrNotExist)
-}
-
-// hydrate expands templated variables in our config with concrete values
-func (c *Config) hydrate() error {
-	if err := c.hydrateHelmCharts(); err != nil {
-		return err
+// MergeVariables takes another config and will import those variables into
+// the current config by replacing old ones and adding the new ones
+func (c *Config) MergeVariables(other *Config) {
+	for _, variable := range other.Spec.Variables {
+		c.overlayVariable(variable)
 	}
-	if err := c.hydrateYttCharts(); err != nil {
-		return err
-	}
-	return nil
-}
-
-func (c *Config) prepareVariables(v []Variable) map[string]string {
-	variables := make(map[string]string)
-	for _, variable := range v {
-		variables[variable.Name] = variable.Value
-	}
-	variables["namespace"] = c.Namespace
-	return variables
 }
 
-func (c *Config) hydrateYttCharts() error {
-	for entryFileName, entry := range c.Spec.Charts.Ytt {
-		for valIndex, val := range entry.Values {
-			valueTmpl, err := template.New("ytt entry value").Parse(val.Value)
-			if err != nil {
-				return fmt.Errorf("failed to parse ytt entry value as template: %q, %w", val.Value, err)
-			}
-			buf := new(bytes.Buffer)
-			if err := valueTmpl.Execute(buf, c.prepareVariables(c.Spec.Variables)); err != nil {
-				return fmt.Errorf("failed to hydrate ytt entry: %q, %w", val.Value, err)
-			}
-			// replace original content with hydrated version
-			c.Spec.Charts.Ytt[entryFileName].Values[valIndex].Value = buf.String()
+// overlayVariable takes a variable in and either replaces an existing variable
+// of the same name or create a new variable in the config if no matching name
+// is found
+func (c *Config) overlayVariable(v Variable) {
+	// find same variable by name and replace is value
+	// if not found then create the variable
+	for index, originalVariable := range c.Spec.Variables {
+		if originalVariable.Name == v.Name {
+			c.Spec.Variables[index].Value = v.Value
+			return
 		}
 	}
-	return nil
+	c.Spec.Variables = append(c.Spec.Variables, v)
 }
-
-func (c *Config) hydrateHelmCharts() error {
-	for name, chart := range c.Spec.Charts.Helm {
-		rawChartValues, err := yaml.Marshal(chart.Values)
-		if err != nil {
-			return fmt.Errorf("failed to get chart values as string: %w", err)
-		}
-		valueTmpl, err := template.New("chart").Parse(string(rawChartValues))
-		if err != nil {
-			return fmt.Errorf("failed to parse chart values as template: %q, %w", chart.Values, err)
-		}
-		buf := new(bytes.Buffer)
-		if err := valueTmpl.Execute(buf, c.prepareVariables(c.Spec.Variables)); err != nil {
-			return fmt.Errorf("failed to hydrate chart values entry: %q, %w", chart.Values, err)
-		}
-		// replace original content with hydrated version
-		hydratedChart := chart
-		hydratedChart.Values = buf.String()
-		c.Spec.Charts.Helm[name] = hydratedChart
-	}
-	return nil
-}
diff --git a/runner/config_test.go b/runner/config_test.go
--- a/runner/config_test.go
+++ b/runner/config_test.go
@@ -37,3 +37,4 @@
 
 	// verify variables overwrite
 	assert.Equal(t, "admin", config.Spec.Charts.Ytt["odoo"].Values[2].Value)
+}