From e23793120b8ce3deeeede070813cd74689ed729c Mon Sep 17 00:00:00 2001
From: Dan Winter <dan.j.winter@gmail.com>
Date: Mon, 19 Nov 2018 09:58:25 -0700
Subject: [PATCH] fix(helm): --set for out of order list values (#4682)

When a user specifies value overrides for list values out of order,
strvals.listItem panics. Change strvals.listItem to handle this case by
re-initializing nil values to a new map.

Closes #4503

Co-authored-by: Cameron Childress <cameron@cchildress.org>
Co-authored-by: Kevin Collette <hal.collette@gmail.com>
Co-authored-by: Connor McKelvey <connormckelvey@gmail.com>
Co-authored-by: Dan Winter <dan.j.winter@gmail.com>

Signed-off-by: Dan Winter <dan.j.winter@gmail.com>
Signed-off-by: Cameron Childress <cameron@cchildress.org>
Signed-off-by: Kevin Collette <hal.collette@gmail.com>
Signed-off-by: Connor McKelvey <connormckelvey@gmail.com>
---
 cmd/helm/install_test.go   |  8 +++++++-
 pkg/strvals/parser.go      |  8 +++++++-
 pkg/strvals/parser_test.go | 24 ++++++++++++++++++++++++
 3 files changed, 38 insertions(+), 2 deletions(-)

diff --git a/cmd/helm/install_test.go b/cmd/helm/install_test.go
index 168c53fed..4a2055640 100644
--- a/cmd/helm/install_test.go
+++ b/cmd/helm/install_test.go
@@ -61,7 +61,13 @@ func TestInstall(t *testing.T) {
 			resp:     helm.ReleaseMock(&helm.MockReleaseOptions{Name: "virgil"}),
 			expected: "virgil",
 		},
-		// Install, values from yaml
+		{
+			name:     "install with multiple unordered list values",
+			args:     []string{"testdata/testcharts/alpine"},
+			flags:    strings.Split("--name virgil --set foo[1].bar=baz,foo[0].baz=bar", " "),
+			resp:     helm.ReleaseMock(&helm.MockReleaseOptions{Name: "virgil"}),
+			expected: "virgil",
+		},
 		{
 			name:     "install with values",
 			args:     []string{"testdata/testcharts/alpine"},
diff --git a/pkg/strvals/parser.go b/pkg/strvals/parser.go
index 532a8c4ac..9d52f34c0 100644
--- a/pkg/strvals/parser.go
+++ b/pkg/strvals/parser.go
@@ -288,7 +288,13 @@ func (t *parser) listItem(list []interface{}, i int) ([]interface{}, error) {
 		// We have a nested object. Send to t.key
 		inner := map[string]interface{}{}
 		if len(list) > i {
-			inner = list[i].(map[string]interface{})
+			var ok bool
+			inner, ok = list[i].(map[string]interface{})
+			if !ok {
+				// We have indices out of order. Initialize empty value.
+				list[i] = map[string]interface{}{}
+				inner = list[i].(map[string]interface{})
+			}
 		}
 
 		// Recurse
diff --git a/pkg/strvals/parser_test.go b/pkg/strvals/parser_test.go
index e5d878149..a096f16d2 100644
--- a/pkg/strvals/parser_test.go
+++ b/pkg/strvals/parser_test.go
@@ -294,6 +294,30 @@ func TestParseSet(t *testing.T) {
 			str:    "nested[1][1]=1",
 			expect: map[string]interface{}{"nested": []interface{}{nil, []interface{}{nil, 1}}},
 		},
+		{
+			str: "name1.name2[0].foo=bar,name1.name2[1].foo=bar",
+			expect: map[string]interface{}{
+				"name1": map[string]interface{}{
+					"name2": []map[string]interface{}{{"foo": "bar"}, {"foo": "bar"}},
+				},
+			},
+		},
+		{
+			str: "name1.name2[1].foo=bar,name1.name2[0].foo=bar",
+			expect: map[string]interface{}{
+				"name1": map[string]interface{}{
+					"name2": []map[string]interface{}{{"foo": "bar"}, {"foo": "bar"}},
+				},
+			},
+		},
+		{
+			str: "name1.name2[1].foo=bar",
+			expect: map[string]interface{}{
+				"name1": map[string]interface{}{
+					"name2": []map[string]interface{}{nil, {"foo": "bar"}},
+				},
+			},
+		},
 	}
 
 	for _, tt := range tests {
-- 
GitLab