Repository: grafana/tanka
Pull request #185 (2020-01-24 03:40:36)

Allow environment vendor overrides
Look for a vendor folder in the environment which will let you `jb install` a dep into the environment to override what's in the main project vendor folder

cyriltovena: Ho wow, I needed this for one loki cluster.
slim-bean: I'm not sure if I'm making a mistake with the change to find the `root` jsonnet file by skipping up a directory.  I think this is ok as I don't think it's valid for a flat structure?  (unless i'm misisng a use case/requirement).  That is there will always be a root jsonnet.json file and then an environments folder below?
slim-bean: After some discussion with @sh0rez we backed out most of the original changes to this PR and instead are just adding a check for a local vendor folder in the base dir of the environment.

You won't be able to use `jb` currently to add environment specific overrides but you can use wget to add anything you want overridden.

Patch:
diff --git a/pkg/jsonnet/jpath/jpath.go b/pkg/jsonnet/jpath/jpath.go
index 3558c32a..dd6d3007 100644
--- a/pkg/jsonnet/jpath/jpath.go
+++ b/pkg/jsonnet/jpath/jpath.go
@@ -53,10 +53,12 @@ func Resolve(workdir string) (path []string, base, root string, err error) {
 		return nil, "", "", err
 	}
 
+	// The importer iterates through this list in reverse order
 	return []string{
-		base,
 		filepath.Join(root, "vendor"),
+		filepath.Join(base, "vendor"), // Look for a vendor folder in the base dir before using the root vendor
 		filepath.Join(root, "lib"),
+		base,
 	}, base, root, nil
 }
 


Test patch:
diff --git a/pkg/jsonnet/imports_test.go b/pkg/jsonnet/imports_test.go
index 33fa1202..a7c2f05e 100644
--- a/pkg/jsonnet/imports_test.go
+++ b/pkg/jsonnet/imports_test.go
@@ -11,7 +11,7 @@ import (
 // TestTransitiveImports checks that TransitiveImports is able to report all
 // recursive imports of a file
 func TestTransitiveImports(t *testing.T) {
-	imports, err := TransitiveImports("testdata")
+	imports, err := TransitiveImports("testdata/importTree")
 	fmt.Println(imports)
 	require.NoError(t, err)
 	assert.Equal(t, []string{
diff --git a/pkg/jsonnet/jpath/jpath_test.go b/pkg/jsonnet/jpath/jpath_test.go
new file mode 100644
index 00000000..ebb4742b
--- /dev/null
+++ b/pkg/jsonnet/jpath/jpath_test.go
@@ -0,0 +1,29 @@
+package jpath_test
+
+import (
+	"encoding/json"
+	"path/filepath"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+
+	"github.com/grafana/tanka/pkg/jsonnet"
+)
+
+func TestResolve(t *testing.T) {
+	s, err := jsonnet.EvaluateFile(filepath.Join("./testdata/precedence/environments/default/main.jsonnet"))
+	require.NoError(t, err)
+
+	want := map[string]string{
+		"baseDir":        "baseDir",
+		"lib":            "/lib",
+		"baseDir-vendor": "baseDir-vendor",
+		"vendor":         "/vendor",
+	}
+
+	w, err := json.Marshal(want)
+	require.NoError(t, err)
+
+	assert.JSONEq(t, string(w), s)
+}
diff --git a/pkg/jsonnet/jpath/testdata/precedence/README.md b/pkg/jsonnet/jpath/testdata/precedence/README.md
new file mode 100644
index 00000000..588003b1
--- /dev/null
+++ b/pkg/jsonnet/jpath/testdata/precedence/README.md
@@ -0,0 +1,32 @@
+## `precedence` test
+
+This directory contains some Jsonnet testdata for testing correct import precedence.
+
+The desired precedence looks like the following (most specific wins):
+
+1. consider baseDir (dir containing `main.jsonnet`) first: The current
+   environment is most important
+2. then `/lib`: project libraries are more specific than any vendors
+3. then `<baseDir>/vendor`: to allow overriding project vendor on a environment level
+4. finally `/vendor`: external packages are least specific
+
+## internals
+
+How the test works:
+
+We basically put the same jsonnet file in multiple locations:
+
+```jsonnet
+{
+    value: "<location>"
+}
+```
+
+For example to check for `/lib` to precede both vendor folders, the following is used:
+
+- `/vendor/project_lib.jsonnet`: `value: "/vendor"`
+- `/<baseDir>/vendor/project_lib.jsonnet`: `value: "/baseDir-vendor"`
+- `/lib/project_lib.jsonnet`: `value: "/lib"`
+
+Then in `<baseDir>/main.jsonnet` we put `import "project_lib.jsonnet"` and
+expect `value` to be `/lib`.
diff --git a/pkg/jsonnet/jpath/testdata/precedence/environments/default/baseDir.jsonnet b/pkg/jsonnet/jpath/testdata/precedence/environments/default/baseDir.jsonnet
new file mode 100644
index 00000000..012884cb
--- /dev/null
+++ b/pkg/jsonnet/jpath/testdata/precedence/environments/default/baseDir.jsonnet
@@ -0,0 +1,3 @@
+{
+  value: "baseDir",
+}
diff --git a/pkg/jsonnet/jpath/testdata/precedence/environments/default/main.jsonnet b/pkg/jsonnet/jpath/testdata/precedence/environments/default/main.jsonnet
new file mode 100644
index 00000000..27844368
--- /dev/null
+++ b/pkg/jsonnet/jpath/testdata/precedence/environments/default/main.jsonnet
@@ -0,0 +1,6 @@
+{
+  baseDir: (import "baseDir.jsonnet").value,
+  lib: (import "lib.jsonnet").value,
+  "baseDir-vendor": (import "baseDir-vendor.jsonnet").value,
+  vendor: (import "vendor.jsonnet").value,
+}
diff --git a/pkg/jsonnet/jpath/testdata/precedence/environments/default/spec.json b/pkg/jsonnet/jpath/testdata/precedence/environments/default/spec.json
new file mode 100644
index 00000000..2bed8424
--- /dev/null
+++ b/pkg/jsonnet/jpath/testdata/precedence/environments/default/spec.json
@@ -0,0 +1,11 @@
+{
+  "apiVersion": "tanka.dev/v1alpha1",
+  "kind": "Environment",
+  "metadata": {
+    "name": "env-vendor"
+  },
+  "spec": {
+    "apiServer": "",
+    "namespace": "default"
+  }
+}
diff --git a/pkg/jsonnet/jpath/testdata/precedence/environments/default/vendor/baseDir-vendor.jsonnet b/pkg/jsonnet/jpath/testdata/precedence/environments/default/vendor/baseDir-vendor.jsonnet
new file mode 100644
index 00000000..3c1d5af9
--- /dev/null
+++ b/pkg/jsonnet/jpath/testdata/precedence/environments/default/vendor/baseDir-vendor.jsonnet
@@ -0,0 +1,3 @@
+{
+  value: "baseDir-vendor"
+}
diff --git a/pkg/jsonnet/jpath/testdata/precedence/environments/default/vendor/baseDir.jsonnet b/pkg/jsonnet/jpath/testdata/precedence/environments/default/vendor/baseDir.jsonnet
new file mode 100644
index 00000000..a5b70573
--- /dev/null
+++ b/pkg/jsonnet/jpath/testdata/precedence/environments/default/vendor/baseDir.jsonnet
@@ -0,0 +1,3 @@
+{
+  value: "/baseDir-vendor"
+}
diff --git a/pkg/jsonnet/jpath/testdata/precedence/environments/default/vendor/lib.jsonnet b/pkg/jsonnet/jpath/testdata/precedence/environments/default/vendor/lib.jsonnet
new file mode 100644
index 00000000..a5b70573
--- /dev/null
+++ b/pkg/jsonnet/jpath/testdata/precedence/environments/default/vendor/lib.jsonnet
@@ -0,0 +1,3 @@
+{
+  value: "/baseDir-vendor"
+}
diff --git a/pkg/jsonnet/testdata/jsonnetfile.json b/pkg/jsonnet/jpath/testdata/precedence/jsonnetfile.json
similarity index 100%
rename from pkg/jsonnet/testdata/jsonnetfile.json
rename to pkg/jsonnet/jpath/testdata/precedence/jsonnetfile.json
diff --git a/pkg/jsonnet/jpath/testdata/precedence/lib/baseDir.jsonnet b/pkg/jsonnet/jpath/testdata/precedence/lib/baseDir.jsonnet
new file mode 100644
index 00000000..a2803b65
--- /dev/null
+++ b/pkg/jsonnet/jpath/testdata/precedence/lib/baseDir.jsonnet
@@ -0,0 +1,3 @@
+{
+  value: "/lib"
+}
diff --git a/pkg/jsonnet/jpath/testdata/precedence/lib/lib.jsonnet b/pkg/jsonnet/jpath/testdata/precedence/lib/lib.jsonnet
new file mode 100644
index 00000000..a2803b65
--- /dev/null
+++ b/pkg/jsonnet/jpath/testdata/precedence/lib/lib.jsonnet
@@ -0,0 +1,3 @@
+{
+  value: "/lib"
+}
diff --git a/pkg/jsonnet/jpath/testdata/precedence/vendor/baseDir-vendor.jsonnet b/pkg/jsonnet/jpath/testdata/precedence/vendor/baseDir-vendor.jsonnet
new file mode 100644
index 00000000..59da02d6
--- /dev/null
+++ b/pkg/jsonnet/jpath/testdata/precedence/vendor/baseDir-vendor.jsonnet
@@ -0,0 +1,3 @@
+{
+  value: "/vendor"
+}
diff --git a/pkg/jsonnet/jpath/testdata/precedence/vendor/baseDir.jsonnet b/pkg/jsonnet/jpath/testdata/precedence/vendor/baseDir.jsonnet
new file mode 100644
index 00000000..59da02d6
--- /dev/null
+++ b/pkg/jsonnet/jpath/testdata/precedence/vendor/baseDir.jsonnet
@@ -0,0 +1,3 @@
+{
+  value: "/vendor"
+}
diff --git a/pkg/jsonnet/jpath/testdata/precedence/vendor/lib.jsonnet b/pkg/jsonnet/jpath/testdata/precedence/vendor/lib.jsonnet
new file mode 100644
index 00000000..59da02d6
--- /dev/null
+++ b/pkg/jsonnet/jpath/testdata/precedence/vendor/lib.jsonnet
@@ -0,0 +1,3 @@
+{
+  value: "/vendor"
+}
diff --git a/pkg/jsonnet/jpath/testdata/precedence/vendor/vendor.jsonnet b/pkg/jsonnet/jpath/testdata/precedence/vendor/vendor.jsonnet
new file mode 100644
index 00000000..59da02d6
--- /dev/null
+++ b/pkg/jsonnet/jpath/testdata/precedence/vendor/vendor.jsonnet
@@ -0,0 +1,3 @@
+{
+  value: "/vendor"
+}
diff --git a/pkg/jsonnet/testdata/README.md b/pkg/jsonnet/testdata/importTree/README.md
similarity index 100%
rename from pkg/jsonnet/testdata/README.md
rename to pkg/jsonnet/testdata/importTree/README.md
diff --git a/pkg/jsonnet/testdata/importTree/jsonnetfile.json b/pkg/jsonnet/testdata/importTree/jsonnetfile.json
new file mode 100644
index 00000000..0967ef42
--- /dev/null
+++ b/pkg/jsonnet/testdata/importTree/jsonnetfile.json
@@ -0,0 +1,1 @@
+{}