# HG changeset patch
# User Florent Aide <florent.aide@gmail.com>
# Date 1654615741 -7200
#      Tue Jun 07 17:29:01 2022 +0200
# Node ID 5597730a795c859c8fc43d4be93f51b126afd11d
# Parent  99503dc86cb6590feae8a76e9d7b54cb4a626ee8
allow charts to use relative paths && launch commands in config dir

diff --git a/runner/config.go b/runner/config.go
--- a/runner/config.go
+++ b/runner/config.go
@@ -34,7 +34,7 @@
 	Args []Arg  `mapstructure:"args"`
 }
 
-func (k CmdCreate) BuildArgs(namespace string, args []Arg) []string {
+func (k CmdCreateKey) BuildArgs(namespace string, args []Arg) []string {
 	output := []string{
 		"-n", namespace,
 		"create",
@@ -63,6 +63,22 @@
 	APIVersion string `mapstructure:"apiVersion"`
 	Kind       string `mapstructure:"kind"`
 	Spec       Spec   `mapstructure:"spec"`
+	Dir        string // the directory in which we found the config file
+}
+
+// Absolutize makes all chart paths absolute
+func (c *Config) Absolutize(dir string) error {
+	for name, chart := range c.Spec.Charts {
+		resolvedChartPath := filepath.Join(dir, chart.Path)
+		absChartPath, err := filepath.Abs(resolvedChartPath)
+		if err != nil {
+			return fmt.Errorf("failed to find abs() for %s: %w", resolvedChartPath, err)
+		}
+
+		chart.Path = absChartPath
+		c.Spec.Charts[name] = chart
+	}
+	return nil
 }
 
 // NewConfig returns a *Config
@@ -88,7 +104,7 @@
 	cmdConfig.RootDir = rootDir
 	cmdConfig.Layers = append(cmdConfig.Layers, configDir)
 	cmdConfig.Spec.Charts = make(map[string]CmdChart)
-	cmdConfig.Spec.Creates = make(map[CmdCreate][]Arg)
+	cmdConfig.Spec.Creates = make(map[CmdCreateKey]CmdCreate)
 	cmdConfig.Namespace = ""
 	cmdConfig.Logger = logger
 	return cmdConfig
@@ -115,6 +131,10 @@
 		if err != nil {
 			return fmt.Errorf("failed to create config from %s: %w", dir, err)
 		}
+		config.Dir = dir
+		if err := config.Absolutize(dir); err != nil {
+			return fmt.Errorf("failed to absolutize config from dir: %s, %w", dir, err)
+		}
 		// first config dir must return a real config...
 		// others can be skipped
 		if config == nil && len(configLayers) == 0 {
@@ -146,9 +166,7 @@
 		configLayers[i], configLayers[j] = configLayers[j], configLayers[i]
 	}
 
-	fmt.Printf("%+v\n", configLayers)
 	for _, config := range configLayers {
-		fmt.Printf("%+v\n", config)
 		c.Namespace = config.Spec.NameSpace
 		c.MergeVariables(config)
 
@@ -157,8 +175,11 @@
 		}
 
 		for _, k := range config.Spec.Creates {
-			cmdCreate := CmdCreate{Type: k.Type, Name: k.Name}
-			c.Spec.Creates[cmdCreate] = k.Args
+			cmdCreate := CmdCreateKey{Type: k.Type, Name: k.Name}
+			c.Spec.Creates[cmdCreate] = CmdCreate{
+				Dir:  config.Dir,
+				Args: k.Args,
+			}
 		}
 	}
 
@@ -184,11 +205,16 @@
 	return cfg, nil
 }
 
-type CmdCreate struct {
+type CmdCreateKey struct {
 	Type string `mapstructure:"type"`
 	Name string `mapstructure:"name"`
 }
 
+type CmdCreate struct {
+	Dir  string
+	Args []Arg
+}
+
 type CmdConfig struct {
 	Spec      CmdSpec
 	RootDir   string
@@ -202,7 +228,7 @@
 	Variables []Variable
 	Charts    CmdCharts
 	Ytt       Ytt
-	Creates   map[CmdCreate][]Arg
+	Creates   map[CmdCreateKey]CmdCreate
 }
 
 type Ytt []string
@@ -220,7 +246,7 @@
 				if !stat.IsDir() {
 					hydratedPaths, err := hydrateFiles(tmpDir, variables, []string{entryPath})
 					if err != nil {
-						return nil, fmt.Errorf("Failed to hydrate %s: %w", entryPath, err)
+						return nil, fmt.Errorf("failed to hydrate %s: %w", entryPath, err)
 					}
 					entryPath = hydratedPaths[0]
 				}
diff --git a/runner/config_test.go b/runner/config_test.go
--- a/runner/config_test.go
+++ b/runner/config_test.go
@@ -12,7 +12,7 @@
 )
 
 var (
-	fixtures       = "fixtures/f1"
+	fixtures = "fixtures/f1"
 )
 
 func TestConfig(t *testing.T) {
@@ -21,8 +21,8 @@
 	// first config.spec.variables entry name should be VAULT_KV in our test file
 	assert.Equal(t, "VAULT_KV", config.Spec.Variables[0].Name)
 	assert.Equal(t, "orus.io", config.Spec.Variables[0].Value)
-	assert.Equal(t, "vendor/helm/postgresql", config.Spec.Charts["postgres"].Path)
-	assert.Equal(t, "vendor/ytt/odoo", config.Spec.Charts["odoo"].Path)
+	assert.Equal(t, "../vendor/helm/postgresql", config.Spec.Charts["postgres"].Path)
+	assert.Equal(t, "../vendor/ytt/odoo", config.Spec.Charts["odoo"].Path)
 }
 
 func TestYttBuildArgs(t *testing.T) {
@@ -73,8 +73,18 @@
 	}()
 	require.NoError(t, c.Initialize(tmpDir))
 	require.Equal(t, 1, len(c.Spec.Creates))
-	for k, a := range c.Spec.Creates {
-		args := k.BuildArgs(c.Namespace, a)
+
+	assert.True(t, filepath.IsAbs(c.Spec.Charts["postgres"].Path))
+	crKey := runner.CmdCreateKey{
+		Type: "configmap",
+		Name: "xbus-pipelines",
+	}
+	cr, ok := c.Spec.Creates[crKey]
+	assert.True(t, ok)
+	require.Equal(t, 1, len(cr.Args))
+
+	for k, create := range c.Spec.Creates {
+		args := k.BuildArgs(c.Namespace, create.Args)
 		assert.Equal(
 			t,
 			[]string{
diff --git a/runner/fixtures/f1/base/beaver.yml b/runner/fixtures/f1/base/beaver.yml
--- a/runner/fixtures/f1/base/beaver.yml
+++ b/runner/fixtures/f1/base/beaver.yml
@@ -9,13 +9,13 @@
   charts:
     postgres:
       type: helm
-      path: vendor/helm/postgresql
+      path: ../vendor/helm/postgresql
     odoo:
       type: ytt
-      path: vendor/ytt/odoo
+      path: ../vendor/ytt/odoo
   create:
   - type: configmap
     name: xbus-pipelines
     args:
     - flag: --from-file
-      value: base/pipelines
+      value: pipelines
diff --git a/runner/main.go b/runner/main.go
--- a/runner/main.go
+++ b/runner/main.go
@@ -52,10 +52,13 @@
 			return fmt.Errorf("unsupported chart %s type: %q", chart.Path, chart.Type)
 		}
 	}
-	for create, args := range r.config.Spec.Creates {
-		strArgs := create.BuildArgs(r.config.Namespace, args)
-		name := fmt.Sprintf("%s_%s", create.Type, create.Name)
-		cmds[name] = cmd.NewCmd(kubectlCmd, strArgs...)
+
+	for key, create := range r.config.Spec.Creates {
+		strArgs := key.BuildArgs(r.config.Namespace, create.Args)
+		name := fmt.Sprintf("%s_%s", key.Type, key.Name)
+		c := cmd.NewCmd(kubectlCmd, strArgs...)
+		c.Dir = create.Dir
+		cmds[name] = c
 	}
 
 	// run commands or print them
@@ -96,7 +99,7 @@
 	}
 
 	// create ytt additional command
-	args , err := r.config.PrepareYttArgs(tmpDir, r.config.Layers, compiled)
+	args, err := r.config.PrepareYttArgs(tmpDir, r.config.Layers, compiled)
 	if err != nil {
 		return fmt.Errorf("cannot prepare ytt args: %w", err)
 	}