From 78fa7f13ad1f9a38636adc354cf1683e4c479db2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leo=20Bergn=C3=A9hr?= Date: Wed, 25 Sep 2024 10:44:05 +0200 Subject: [PATCH] Interpolate object parameters as JSON strings When trating object parameters as `map`s, the interpolation of the object itself changes to the string representation of `map` instead of the previous JSON string representation. In order to keep the old behaviour of interpolating the object parameter to a JSON string, this change introduces a new type, `FormattedObject`, which implements the [`fmt.Formatter`](https://pkg.go.dev/fmt#Formatter) interface. The implemented `Format` function turns the object's string representation into a JSON string, instad of the default Go representation of a `map`. Example: ```yaml parameter: - name: foo type: object default: bar: 1 install: mymixin: # Interpolating a nested property of the object parameter. val: "${ bundle.parameter.foo.bar }" # -> `val: '1'` # Interpolating the object parameter directly. obj: "${ bundle.parameter.foo }" # -> `obj: '{"bar":1}'` ``` A shortcoming of this implementation is that interpolating nested properties which also are `map` types will result in the interpolated value being the string representation of `map`. --- pkg/runtime/runtime_manifest.go | 15 ++++++++++++++- pkg/runtime/runtime_manifest_test.go | 19 +++++++++++++------ 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/pkg/runtime/runtime_manifest.go b/pkg/runtime/runtime_manifest.go index 653a98280..45f514b13 100644 --- a/pkg/runtime/runtime_manifest.go +++ b/pkg/runtime/runtime_manifest.go @@ -132,6 +132,19 @@ func (m *RuntimeManifest) loadDependencyDefinitions() error { return nil } +// This wrapper type serve as a way of formatting a `map[string]interface{}` as +// JSON when the templating by mustache is done. It makes it possible to +// maintain the JSON string representation of the map while still allowing the +// map to be used as a context in the templating, allowing for accessing the +// map's keys in the template. +type FormattedObject map[string]interface{} + +// Format the `FormattedObject` as a JSON string. +func (fo FormattedObject) Format(f fmt.State, c rune) { + jsonStr, _ := json.Marshal(fo) + fmt.Fprintf(f, string(jsonStr)) +} + func (m *RuntimeManifest) resolveParameter(pd manifest.ParameterDefinition) (interface{}, error) { getValue := func(envVar string) (interface{}, error) { value := m.config.Getenv(envVar) @@ -140,7 +153,7 @@ func (m *RuntimeManifest) resolveParameter(pd manifest.ParameterDefinition) (int if err := json.Unmarshal([]byte(value), &obj); err != nil { return nil, err } - return obj, nil + return FormattedObject(obj), nil } return value, nil } diff --git a/pkg/runtime/runtime_manifest_test.go b/pkg/runtime/runtime_manifest_test.go index 0ffeb018b..349e06c68 100644 --- a/pkg/runtime/runtime_manifest_test.go +++ b/pkg/runtime/runtime_manifest_test.go @@ -48,7 +48,8 @@ install: - mymixin: Parameters: Thing: ${ bundle.parameters.person } - Object: ${ bundle.parameters.contact.name } + ObjectName: ${ bundle.parameters.contact.name } + Object: '${ bundle.parameters.contact }' ` rm := runtimeManifestFromStepYaml(t, testConfig, mContent) s := rm.Install[0] @@ -66,13 +67,19 @@ install: assert.Equal(t, "Ralpha", val) assert.NotContains(t, "place", pms, "parameters that don't apply to the current action should not be resolved") - // New assertions for the contact parameter - require.IsType(t, "string", pms["Object"], "Data.mymixin.Parameters.Object has incorrect type") - contactName := pms["Object"].(string) - require.IsType(t, "string", contactName, "Data.mymixin.Parameters.Object.name has incorrect type") - + // Asserting `bundle.parameters.contact.name` works. + require.IsType(t, "string", pms["ObjectName"], "Data.mymixin.Parameters.ObjectName has incorrect type") + contactName := pms["ObjectName"].(string) + require.IsType(t, "string", contactName, "Data.mymixin.Parameters.ObjectName.name has incorrect type") assert.Equal(t, "Breta", contactName) + // Asserting `bundle.parameters.contact` evaluates to the JSON string + // representation of the object. + require.IsType(t, "string", pms["Object"], "Data.mymixin.Parameters.Object has incorrect type") + contact := pms["Object"].(string) + require.IsType(t, "string", contact, "Data.mymixin.Parameters.Object has incorrect type") + assert.Equal(t, "{\"name\":\"Breta\"}", contact) + err = rm.Initialize(ctx) require.NoError(t, err) }