# HG changeset patch
# User Florent Aide <florent.aide@gmail.com>
# Date 1697627078 -7200
#      Wed Oct 18 13:04:38 2023 +0200
# Node ID 3d9d30f69999e66becbf9e0bff94e57f473208c9
# Parent  ac27a21a752d0019cb108f683ad38bb9aea3e2aa
add test coverage for beaver namespaces as variables

diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -155,8 +155,7 @@
 
 ## Beaver variables
 
-`beaver` variables can be used inside your value files, and **only** inside value
-files, using the following syntax:
+`beaver` variables can be used inside your value files, using the following syntax:
 
 ```
 <[variable_name]>
@@ -199,6 +198,67 @@
 here `pg_tag` value will be `13.7-alpine` if you run
 `beaver build environments/demo`.
 
+### Beaver variables in the beaver namespace itself
+
+You can set some variables in the 'namespace' keyword of a beaver file.
+
+```yaml
+# example/base/beaver.yml
+namespace: <[myns]>
+charts:
+  demoytt:
+    type: ytt
+    path: demoytt.tmpl.yaml
+```
+
+in this case this means this base is not useable by itself but can now be adapted by the caller by setting a beaver
+variable to fill the slot
+
+```yaml
+# example/ns1/beaver.yml
+namespace: ns1
+inherit: ../base
+variables:
+- name: myns
+  value: ns1yo
+```
+
+This is a somewhat warped example but in this case the resulting ouput dir (namespace for beaver) will be example/build/ns1yo
+
+### variables inside the charts.disabled flag
+
+imagine a base with a chart that is disabled by default
+
+```yaml
+# example/base/beaver.yml
+namespace: example
+charts:
+  demoytt:
+    type: ytt
+    path: demoytt.tmpl.yaml
+    disabled: <[configmapDisabled]>
+variables:
+- name: configmapDisabled
+  value: true
+```
+
+and another file that inherits from this base and want to have this chart enabled
+
+```yaml
+# example/configmapenabled/beaver.yml
+namespace: ns1
+inherit: ../base
+variables:
+- name: configmapDisabled
+  value: false
+```
+
+This can be used to allow for options in some inheritance cases where you want to enable/disable a certain backend like
+a Redis server, a Postgresql server.
+Your base provides the diverse options and your inheritance will pick the ones they need.
+
+
+
 ## Output files
 
 `beaver` output files have the following format:
@@ -209,7 +269,7 @@
 
 all `apiVersion` slashes (`/`) are replaced by underscores (`_`).
 
-This convention will help you reviewing merge requests.
+This convention will help you review merge requests.
 
 By default `beaver` will store those files inside `${PWD}/build/<namespace>`, you
 can use `-o` or `--output` to specify an output directory.
@@ -247,7 +307,7 @@
 [ytt overlays](https://carvel.dev/ytt/docs/v0.39.0/ytt-overlays/) by providing
 `ytt.yaml` or `ytt.yml` files or a `ytt` folder inside your `beaver` project(s).
 
-You can use `beaver` variables inside ytt files (outside of ytt folder), because
+You can use `beaver` variables inside ytt files (outside ytt folder), because
 `beaver` considers those as value files.
 
 ## Create resources using kubectl create
diff --git a/runner/config_test.go b/runner/config_test.go
--- a/runner/config_test.go
+++ b/runner/config_test.go
@@ -21,6 +21,7 @@
 	shaFixtures           = "fixtures/f2"
 	helmNamespaceFixtures = "fixtures/f3"
 	disabledAsVar         = "fixtures/fDisabledAsVar"
+	namespaceAsVar        = "fixtures/fNamespaceAsVar"
 )
 
 func TestConfig(t *testing.T) {
@@ -292,7 +293,70 @@
 	if !tCase.FilePresent {
 		_, err = os.Stat(outPutConfigMapName)
 		require.Error(t, err)
-		// file should not exist since it is disabled by a variable in the noconfigmap/beaver.yaml
+		// file should not exist since it is disabled by a variable in the ns2/beaver.yaml
+		require.True(t, errors.Is(err, os.ErrNotExist))
+	} else {
+		_, err = os.Stat(outPutConfigMapName)
+		// file should exist
+		require.NoError(t, err)
+	}
+}
+
+type namespaceTCase struct {
+	Name             string
+	TestPath         string
+	ExpectedBuildDir string
+	FilePresent      bool
+}
+
+func TestNamaspaceAsVariable(t *testing.T) {
+	tCases := []namespaceTCase{
+		{
+			Name:             "ns1yo",
+			TestPath:         "ns1",
+			ExpectedBuildDir: filepath.Join(namespaceAsVar, "build", "ns1yo"),
+			FilePresent:      true,
+		},
+		{
+			Name:             "ns2yo",
+			TestPath:         "ns2",
+			ExpectedBuildDir: filepath.Join(namespaceAsVar, "build", "ns2yo"),
+			FilePresent:      true,
+		},
+	}
+	for _, tCase := range tCases {
+		t.Run(tCase.Name, func(t *testing.T) {
+			runTestBeaverNamespaceAsVariable(t, tCase)
+		})
+	}
+}
+
+func runTestBeaverNamespaceAsVariable(t *testing.T, tCase namespaceTCase) {
+	t.Helper()
+	defer func() {
+		require.NoError(t, runner.CleanDir(tCase.ExpectedBuildDir))
+		require.NoError(t, os.RemoveAll(tCase.ExpectedBuildDir))
+	}()
+
+	tl := testutils.NewTestLogger(t)
+	absRootDir, err := filepath.Abs(namespaceAsVar)
+	require.NoError(t, err)
+	c := runner.NewCmdConfig(tl.Logger(), absRootDir, tCase.TestPath, false, "", "")
+	tmpDir, err := os.MkdirTemp(os.TempDir(), "beaver-")
+	require.NoError(t, err)
+	defer func() {
+		assert.NoError(t, os.RemoveAll(tmpDir))
+	}()
+	require.NoError(t, c.Initialize(tmpDir))
+	r := runner.NewRunner(c)
+	require.NoError(t, r.Build(tmpDir))
+
+	// the output file should be in a directory that matches the variable namespace
+	outPutConfigMapName := filepath.Join(tCase.ExpectedBuildDir, "ConfigMap.v1.demo.yaml")
+	if !tCase.FilePresent {
+		_, err = os.Stat(outPutConfigMapName)
+		require.Error(t, err)
+		// file should not exist since it is disabled by a variable in the ns2/beaver.yaml
 		require.True(t, errors.Is(err, os.ErrNotExist))
 	} else {
 		_, err = os.Stat(outPutConfigMapName)
diff --git a/runner/fixtures/fDisabledAsVar/base/beaver.yaml b/runner/fixtures/fDisabledAsVar/base/beaver.yaml
--- a/runner/fixtures/fDisabledAsVar/base/beaver.yaml
+++ b/runner/fixtures/fDisabledAsVar/base/beaver.yaml
@@ -4,3 +4,6 @@
     type: ytt
     path: demoytt.tmpl.yaml
     disabled: <[configmapDisabled]>
+variables:
+- name: configmapDisabled
+  value: true
diff --git a/runner/fixtures/fDisabledAsVar/base/beaver.yaml b/runner/fixtures/fNamespaceAsVar/base/beaver.yaml
copy from runner/fixtures/fDisabledAsVar/base/beaver.yaml
copy to runner/fixtures/fNamespaceAsVar/base/beaver.yaml
--- a/runner/fixtures/fDisabledAsVar/base/beaver.yaml
+++ b/runner/fixtures/fNamespaceAsVar/base/beaver.yaml
@@ -1,6 +1,5 @@
-namespace: example
+namespace: <[myns]>
 charts:
   demoytt:
     type: ytt
     path: demoytt.tmpl.yaml
-    disabled: <[configmapDisabled]>
diff --git a/runner/fixtures/fDisabledAsVar/base/demoytt.tmpl.yaml b/runner/fixtures/fNamespaceAsVar/base/demoytt.tmpl.yaml
copy from runner/fixtures/fDisabledAsVar/base/demoytt.tmpl.yaml
copy to runner/fixtures/fNamespaceAsVar/base/demoytt.tmpl.yaml
diff --git a/runner/fixtures/fDisabledAsVar/base/demoytt.yaml b/runner/fixtures/fNamespaceAsVar/base/demoytt.yaml
copy from runner/fixtures/fDisabledAsVar/base/demoytt.yaml
copy to runner/fixtures/fNamespaceAsVar/base/demoytt.yaml
diff --git a/runner/fixtures/fDisabledAsVar/configmapenabled/beaver.yml b/runner/fixtures/fNamespaceAsVar/ns1/beaver.yml
copy from runner/fixtures/fDisabledAsVar/configmapenabled/beaver.yml
copy to runner/fixtures/fNamespaceAsVar/ns1/beaver.yml
--- a/runner/fixtures/fDisabledAsVar/configmapenabled/beaver.yml
+++ b/runner/fixtures/fNamespaceAsVar/ns1/beaver.yml
@@ -1,5 +1,5 @@
 namespace: ns1
 inherit: ../base
 variables:
-- name: configmapDisabled
-  value: false
+- name: myns
+  value: ns1yo
diff --git a/runner/fixtures/fDisabledAsVar/noconfigmap/beaver.yml b/runner/fixtures/fNamespaceAsVar/ns2/beaver.yml
copy from runner/fixtures/fDisabledAsVar/noconfigmap/beaver.yml
copy to runner/fixtures/fNamespaceAsVar/ns2/beaver.yml
--- a/runner/fixtures/fDisabledAsVar/noconfigmap/beaver.yml
+++ b/runner/fixtures/fNamespaceAsVar/ns2/beaver.yml
@@ -1,5 +1,5 @@
-namespace: ns1
+namespace: ns2
 inherit: ../base
 variables:
-- name: configmapDisabled
-  value: true
+- name: myns
+  value: ns2yo