mirror of https://github.com/databricks/cli.git
Serialize dynamic value for `bundle validate` output (#1499)
## Changes Using dynamic values allows us to retain references like `${resources.jobs...}` even when the type of field is not integer, eg: `run_job_task`, or in general values that do not map to the Go types for a field. ## Tests Integration test
This commit is contained in:
parent
274688d8a2
commit
553fdd1e81
|
@ -471,3 +471,9 @@ func (r Root) GetLocation(path string) dyn.Location {
|
||||||
}
|
}
|
||||||
return v.Location()
|
return v.Location()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Value returns the dynamic configuration value of the root object. This value
|
||||||
|
// is the source of truth and is kept in sync with values in the typed configuration.
|
||||||
|
func (r Root) Value() dyn.Value {
|
||||||
|
return r.value
|
||||||
|
}
|
||||||
|
|
|
@ -119,7 +119,7 @@ func renderTextOutput(cmd *cobra.Command, b *bundle.Bundle, diags diag.Diagnosti
|
||||||
}
|
}
|
||||||
|
|
||||||
func renderJsonOutput(cmd *cobra.Command, b *bundle.Bundle, diags diag.Diagnostics) error {
|
func renderJsonOutput(cmd *cobra.Command, b *bundle.Bundle, diags diag.Diagnostics) error {
|
||||||
buf, err := json.MarshalIndent(b.Config, "", " ")
|
buf, err := json.MarshalIndent(b.Config.Value().AsAny(), "", " ")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,6 +51,13 @@ func writeConfigFile(t *testing.T, config map[string]any) (string, error) {
|
||||||
return filepath, err
|
return filepath, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func validateBundle(t *testing.T, ctx context.Context, path string) ([]byte, error) {
|
||||||
|
t.Setenv("BUNDLE_ROOT", path)
|
||||||
|
c := internal.NewCobraTestRunnerWithContext(t, ctx, "bundle", "validate", "--output", "json")
|
||||||
|
stdout, _, err := c.Run()
|
||||||
|
return stdout.Bytes(), err
|
||||||
|
}
|
||||||
|
|
||||||
func deployBundle(t *testing.T, ctx context.Context, path string) error {
|
func deployBundle(t *testing.T, ctx context.Context, path string) error {
|
||||||
t.Setenv("BUNDLE_ROOT", path)
|
t.Setenv("BUNDLE_ROOT", path)
|
||||||
c := internal.NewCobraTestRunnerWithContext(t, ctx, "bundle", "deploy", "--force-lock")
|
c := internal.NewCobraTestRunnerWithContext(t, ctx, "bundle", "deploy", "--force-lock")
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
package bundle
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/databricks/cli/internal/testutil"
|
||||||
|
"github.com/databricks/cli/libs/dyn"
|
||||||
|
"github.com/databricks/cli/libs/dyn/convert"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAccBundleValidate(t *testing.T) {
|
||||||
|
testutil.GetEnvOrSkipTest(t, "CLOUD_ENV")
|
||||||
|
|
||||||
|
tmpDir := t.TempDir()
|
||||||
|
testutil.WriteFile(t,
|
||||||
|
`
|
||||||
|
bundle:
|
||||||
|
name: "foobar"
|
||||||
|
|
||||||
|
resources:
|
||||||
|
jobs:
|
||||||
|
outer_loop:
|
||||||
|
name: outer loop
|
||||||
|
tasks:
|
||||||
|
- task_key: my task
|
||||||
|
run_job_task:
|
||||||
|
job_id: ${resources.jobs.inner_loop.id}
|
||||||
|
|
||||||
|
inner_loop:
|
||||||
|
name: inner loop
|
||||||
|
|
||||||
|
`, tmpDir, "databricks.yml")
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
stdout, err := validateBundle(t, ctx, tmpDir)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
config := make(map[string]any)
|
||||||
|
err = json.Unmarshal(stdout, &config)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
getValue := func(key string) any {
|
||||||
|
v, err := convert.FromTyped(config, dyn.NilValue)
|
||||||
|
require.NoError(t, err)
|
||||||
|
v, err = dyn.GetByPath(v, dyn.MustPathFromString(key))
|
||||||
|
require.NoError(t, err)
|
||||||
|
return v.AsAny()
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, "foobar", getValue("bundle.name"))
|
||||||
|
assert.Equal(t, "outer loop", getValue("resources.jobs.outer_loop.name"))
|
||||||
|
assert.Equal(t, "inner loop", getValue("resources.jobs.inner_loop.name"))
|
||||||
|
assert.Equal(t, "my task", getValue("resources.jobs.outer_loop.tasks[0].task_key"))
|
||||||
|
// Assert resource references are retained in the output.
|
||||||
|
assert.Equal(t, "${resources.jobs.inner_loop.id}", getValue("resources.jobs.outer_loop.tasks[0].run_job_task.job_id"))
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
package testutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TouchNotebook(t *testing.T, elems ...string) string {
|
||||||
|
path := filepath.Join(elems...)
|
||||||
|
err := os.MkdirAll(filepath.Dir(path), 0755)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
err = os.WriteFile(path, []byte("# Databricks notebook source"), 0644)
|
||||||
|
require.NoError(t, err)
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
|
||||||
|
func Touch(t *testing.T, elems ...string) string {
|
||||||
|
path := filepath.Join(elems...)
|
||||||
|
err := os.MkdirAll(filepath.Dir(path), 0755)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
f, err := os.Create(path)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
err = f.Close()
|
||||||
|
require.NoError(t, err)
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
|
||||||
|
func WriteFile(t *testing.T, content string, elems ...string) string {
|
||||||
|
path := filepath.Join(elems...)
|
||||||
|
err := os.MkdirAll(filepath.Dir(path), 0755)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
f, err := os.Create(path)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
_, err = f.WriteString(content)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
err = f.Close()
|
||||||
|
require.NoError(t, err)
|
||||||
|
return path
|
||||||
|
}
|
|
@ -1,26 +0,0 @@
|
||||||
package testutil
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TouchNotebook(t *testing.T, elems ...string) string {
|
|
||||||
path := filepath.Join(elems...)
|
|
||||||
os.MkdirAll(filepath.Dir(path), 0755)
|
|
||||||
err := os.WriteFile(path, []byte("# Databricks notebook source"), 0644)
|
|
||||||
require.NoError(t, err)
|
|
||||||
return path
|
|
||||||
}
|
|
||||||
|
|
||||||
func Touch(t *testing.T, elems ...string) string {
|
|
||||||
path := filepath.Join(elems...)
|
|
||||||
os.MkdirAll(filepath.Dir(path), 0755)
|
|
||||||
f, err := os.Create(path)
|
|
||||||
require.NoError(t, err)
|
|
||||||
f.Close()
|
|
||||||
return path
|
|
||||||
}
|
|
Loading…
Reference in New Issue