Repository: argoproj-labs/applicationset
Pull request #110 (2021-01-29 08:12:21)

Add support for support arbitrary key:value pairs in ListGenerator
Fix https://github.com/argoproj-labs/applicationset/issues/108

maruina: /assign @jgwest
OmerKahani: LGTM. Thanks @maruina 
maruina: I don't know if this PR covers everything in https://github.com/argoproj-labs/applicationset/issues/98 but I added a couple of tests. It might be a good start.

Patch:
diff --git a/api/v1alpha1/applicationset_types.go b/api/v1alpha1/applicationset_types.go
index 1c95f52..570189d 100644
--- a/api/v1alpha1/applicationset_types.go
+++ b/api/v1alpha1/applicationset_types.go
@@ -68,6 +68,8 @@ type ListGenerator struct {
 type ListGeneratorElement struct {
 	Cluster string `json:"cluster"`
 	Url     string `json:"url"`
+	// Values contains key/value pairs which are passed directly as parameters to the template
+	Values map[string]string `json:"values,omitempty"`
 }
 
 // ClusterGenerator defines a generator to match against clusters registered with ArgoCD.
diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go
index a4e1d97..d51e4dd 100644
--- a/api/v1alpha1/zz_generated.deepcopy.go
+++ b/api/v1alpha1/zz_generated.deepcopy.go
@@ -274,7 +274,9 @@ func (in *ListGenerator) DeepCopyInto(out *ListGenerator) {
 	if in.Elements != nil {
 		in, out := &in.Elements, &out.Elements
 		*out = make([]ListGeneratorElement, len(*in))
-		copy(*out, *in)
+		for i := range *in {
+			(*in)[i].DeepCopyInto(&(*out)[i])
+		}
 	}
 	in.Template.DeepCopyInto(&out.Template)
 }
@@ -292,6 +294,13 @@ func (in *ListGenerator) DeepCopy() *ListGenerator {
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *ListGeneratorElement) DeepCopyInto(out *ListGeneratorElement) {
 	*out = *in
+	if in.Values != nil {
+		in, out := &in.Values, &out.Values
+		*out = make(map[string]string, len(*in))
+		for key, val := range *in {
+			(*out)[key] = val
+		}
+	}
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ListGeneratorElement.
diff --git a/examples/list.yaml b/examples/list.yaml
index 97c6c17..7cdbc55 100644
--- a/examples/list.yaml
+++ b/examples/list.yaml
@@ -9,15 +9,21 @@ spec:
       elements:
       - cluster: engineering-dev
         url: https://1.2.3.4
+        values:
+          project: dev
       - cluster: engineering-prod
         url: https://2.4.6.8
+        values:
+          project: prod
       - cluster: finance-preprod
         url: https://9.8.7.6
+        values:
+          project: preprod
   template:
     metadata:
       name: '{{cluster}}-guestbook'
     spec:
-      project: ""
+      project: '{{values.project}}'
       source:
         repoURL: https://github.com/infra-team/cluster-deployments.git
         targetRevision: HEAD
diff --git a/manifests/crds/argoproj.io_applicationsets.yaml b/manifests/crds/argoproj.io_applicationsets.yaml
index f4e2e06..9421913 100644
--- a/manifests/crds/argoproj.io_applicationsets.yaml
+++ b/manifests/crds/argoproj.io_applicationsets.yaml
@@ -886,6 +886,12 @@ spec:
                               type: string
                             url:
                               type: string
+                            values:
+                              additionalProperties:
+                                type: string
+                              description: Values contains key/value pairs which are
+                                passed directly as parameters to the template
+                              type: object
                           required:
                           - cluster
                           - url
diff --git a/manifests/install.yaml b/manifests/install.yaml
index d6f4941..c21923a 100644
--- a/manifests/install.yaml
+++ b/manifests/install.yaml
@@ -716,6 +716,11 @@ spec:
                               type: string
                             url:
                               type: string
+                            values:
+                              additionalProperties:
+                                type: string
+                              description: Values contains key/value pairs which are passed directly as parameters to the template
+                              type: object
                           required:
                           - cluster
                           - url
diff --git a/pkg/generators/list.go b/pkg/generators/list.go
index ee3fd32..8997bfa 100644
--- a/pkg/generators/list.go
+++ b/pkg/generators/list.go
@@ -1,6 +1,7 @@
 package generators
 
 import (
+	"fmt"
 	"time"
 
 	argoprojiov1alpha1 "github.com/argoproj-labs/applicationset/api/v1alpha1"
@@ -37,9 +38,12 @@ func (g *ListGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.Appli
 	res := make([]map[string]string, len(appSetGenerator.List.Elements))
 
 	for i, tmpItem := range appSetGenerator.List.Elements {
-		params := make(map[string]string, 2)
+		params := make(map[string]string, 2+len(tmpItem.Values))
 		params[utils.ClusterListGeneratorKeyName] = tmpItem.Cluster
 		params[utils.UrlGeneratorKeyName] = tmpItem.Url
+		for key, value := range tmpItem.Values {
+			params[fmt.Sprintf("values.%s", key)] = value
+		}
 		res[i] = params
 	}
 


Test patch:
diff --git a/pkg/generators/list_test.go b/pkg/generators/list_test.go
new file mode 100644
index 0000000..74b36ac
--- /dev/null
+++ b/pkg/generators/list_test.go
@@ -0,0 +1,40 @@
+package generators
+
+import (
+	"testing"
+
+	argoprojiov1alpha1 "github.com/argoproj-labs/applicationset/api/v1alpha1"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestGenerateListParams(t *testing.T) {
+	testCases := []struct {
+		elements []argoprojiov1alpha1.ListGeneratorElement
+		expected []map[string]string
+	}{
+		{
+			elements: []argoprojiov1alpha1.ListGeneratorElement{{Cluster: "cluster", Url: "url", Values: map[string]string{}}}, expected: []map[string]string{{
+				"cluster": "cluster", "url": "url"},
+			},
+		},
+		{
+			elements: []argoprojiov1alpha1.ListGeneratorElement{{Cluster: "cluster", Url: "url", Values: map[string]string{"foo": "bar"}}}, expected: []map[string]string{{
+				"cluster": "cluster", "url": "url", "values.foo": "bar",
+			}},
+		},
+	}
+
+	for _, testCase := range testCases {
+
+		var listGenerator = NewListGenerator()
+
+		got, err := listGenerator.GenerateParams(&argoprojiov1alpha1.ApplicationSetGenerator{List: &argoprojiov1alpha1.ListGenerator{
+			Elements: testCase.elements,
+		}})
+
+		assert.NoError(t, err)
+		assert.ElementsMatch(t, testCase.expected, got)
+
+	}
+}