From a3e32c0adb0594b043d5a42987c270e3129f8bd8 Mon Sep 17 00:00:00 2001 From: Pieter Noordhuis Date: Thu, 24 Oct 2024 17:10:13 +0200 Subject: [PATCH] Marshal contents of 'serialized_dashboard' if not a string --- .../terraform/tfdyn/convert_dashboard.go | 41 +++++++++++++++-- .../terraform/tfdyn/convert_dashboard_test.go | 45 +++++++++++++++++++ 2 files changed, 83 insertions(+), 3 deletions(-) diff --git a/bundle/deploy/terraform/tfdyn/convert_dashboard.go b/bundle/deploy/terraform/tfdyn/convert_dashboard.go index f905ba9996..5d3a5d14f7 100644 --- a/bundle/deploy/terraform/tfdyn/convert_dashboard.go +++ b/bundle/deploy/terraform/tfdyn/convert_dashboard.go @@ -2,6 +2,7 @@ package tfdyn import ( "context" + "encoding/json" "fmt" "github.com/databricks/cli/bundle/internal/tf/schema" @@ -10,6 +11,34 @@ import ( "github.com/databricks/cli/libs/log" ) +const ( + filePathFieldName = "file_path" + serializedDashboardFieldName = "serialized_dashboard" +) + +// Marshal "serialized_dashboard" as JSON if it is set in the input but not in the output. +func marshalSerializedDashboard(vin dyn.Value, vout dyn.Value) (dyn.Value, error) { + // Skip if the "serialized_dashboard" field is already set. + if v := vout.Get(serializedDashboardFieldName); v.IsValid() { + return vout, nil + } + + // Skip if the "serialized_dashboard" field on the input is not set. + v := vin.Get(serializedDashboardFieldName) + if !v.IsValid() { + return vout, nil + } + + // Marshal the "serialized_dashboard" field as JSON. + data, err := json.Marshal(v.AsAny()) + if err != nil { + return dyn.InvalidValue, fmt.Errorf("failed to marshal serialized_dashboard: %w", err) + } + + // Set the "serialized_dashboard" field on the output. + return dyn.Set(vout, serializedDashboardFieldName, dyn.V(string(data))) +} + func convertDashboardResource(ctx context.Context, vin dyn.Value) (dyn.Value, error) { var err error @@ -22,8 +51,8 @@ func convertDashboardResource(ctx context.Context, vin dyn.Value) (dyn.Value, er // Include "serialized_dashboard" field if "file_path" is set. // Note: the Terraform resource supports "file_path" natively, but its // change detection mechanism doesn't work as expected at the time of writing (Sep 30). - if path, ok := vout.Get("file_path").AsString(); ok { - vout, err = dyn.Set(vout, "serialized_dashboard", dyn.V(fmt.Sprintf("${file(\"%s\")}", path))) + if path, ok := vout.Get(filePathFieldName).AsString(); ok { + vout, err = dyn.Set(vout, serializedDashboardFieldName, dyn.V(fmt.Sprintf("${file(\"%s\")}", path))) if err != nil { return dyn.InvalidValue, fmt.Errorf("failed to set serialized_dashboard: %w", err) } @@ -33,7 +62,7 @@ func convertDashboardResource(ctx context.Context, vin dyn.Value) (dyn.Value, er case 0: return v, nil case 1: - if p[0] == dyn.Key("file_path") { + if p[0] == dyn.Key(filePathFieldName) { return v, dyn.ErrDrop } } @@ -46,6 +75,12 @@ func convertDashboardResource(ctx context.Context, vin dyn.Value) (dyn.Value, er } } + // Marshal "serialized_dashboard" as JSON if it is set in the input but not in the output. + vout, err = marshalSerializedDashboard(vin, vout) + if err != nil { + return dyn.InvalidValue, err + } + return vout, nil } diff --git a/bundle/deploy/terraform/tfdyn/convert_dashboard_test.go b/bundle/deploy/terraform/tfdyn/convert_dashboard_test.go index 0c4866524b..0794ce15c4 100644 --- a/bundle/deploy/terraform/tfdyn/convert_dashboard_test.go +++ b/bundle/deploy/terraform/tfdyn/convert_dashboard_test.go @@ -82,3 +82,48 @@ func TestConvertDashboardFilePath(t *testing.T) { "file_path": "some/path", }) } + +func TestConvertDashboardSerializedDashboardString(t *testing.T) { + var src = resources.Dashboard{ + SerializedDashboard: `{ "json": true }`, + } + + vin, err := convert.FromTyped(src, dyn.NilValue) + require.NoError(t, err) + + ctx := context.Background() + out := schema.NewResources() + err = dashboardConverter{}.Convert(ctx, "my_dashboard", vin, out) + require.NoError(t, err) + + // Assert that the "serialized_dashboard" is included. + assert.Subset(t, out.Dashboard["my_dashboard"], map[string]any{ + "serialized_dashboard": `{ "json": true }`, + }) +} + +func TestConvertDashboardSerializedDashboardAny(t *testing.T) { + var src = resources.Dashboard{ + SerializedDashboard: map[string]any{ + "pages": []map[string]any{ + { + "displayName": "New Page", + "layout": []map[string]any{}, + }, + }, + }, + } + + vin, err := convert.FromTyped(src, dyn.NilValue) + require.NoError(t, err) + + ctx := context.Background() + out := schema.NewResources() + err = dashboardConverter{}.Convert(ctx, "my_dashboard", vin, out) + require.NoError(t, err) + + // Assert that the "serialized_dashboard" is included. + assert.Subset(t, out.Dashboard["my_dashboard"], map[string]any{ + "serialized_dashboard": `{"pages":[{"displayName":"New Page","layout":[]}]}`, + }) +}