Skip to content

Commit

Permalink
Interpolate object parameters as JSON strings
Browse files Browse the repository at this point in the history
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`.

Signed-off-by: Leo Bergnéhr <[email protected]>
  • Loading branch information
lbergnehr committed Sep 25, 2024
1 parent 6b5e0f1 commit 0511ee1
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 7 deletions.
15 changes: 14 additions & 1 deletion pkg/runtime/runtime_manifest.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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
}
Expand Down
19 changes: 13 additions & 6 deletions pkg/runtime/runtime_manifest_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand All @@ -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)
}
Expand Down

0 comments on commit 0511ee1

Please sign in to comment.