From a21fbdd3835cf0a97d7fe6f23a30ed87d5033761 Mon Sep 17 00:00:00 2001 From: Shreyas Goenka Date: Sun, 21 May 2023 22:37:38 +0200 Subject: [PATCH] refactor logic out of the cmd --- cmd/bundle/init.go | 48 +----------------------------------- libs/template/materialize.go | 24 ++++++++++++++++++ libs/template/schema.go | 43 +++++++++++++++++++++++++++++++- libs/template/schema_test.go | 6 ++--- libs/template/validators.go | 1 + 5 files changed, 71 insertions(+), 51 deletions(-) create mode 100644 libs/template/materialize.go diff --git a/cmd/bundle/init.go b/cmd/bundle/init.go index 498fad8d1..973c709e4 100644 --- a/cmd/bundle/init.go +++ b/cmd/bundle/init.go @@ -1,63 +1,17 @@ package bundle import ( - "encoding/json" - "os" - "path/filepath" - "github.com/databricks/cli/libs/template" "github.com/spf13/cobra" ) -const ConfigFileName = "config.json" -const SchemaFileName = "schema.json" -const TemplateDirName = "template" - var initCmd = &cobra.Command{ Use: "init", Short: "Initialize Template", Long: `Initialize template`, Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - templateLocation := args[0] - - // read the file containing schema for template input parameters - schemaBytes, err := os.ReadFile(filepath.Join(templateLocation, SchemaFileName)) - if err != nil { - return err - } - schema := template.Schema{} - err = json.Unmarshal(schemaBytes, &schema) - if err != nil { - return err - } - - // read user config to initalize the template with - var config map[string]interface{} - b, err := os.ReadFile(filepath.Join(targetDir, ConfigFileName)) - if err != nil { - return err - } - err = json.Unmarshal(b, &config) - if err != nil { - return err - } - - // cast any fields that are supported to be integers. The json unmarshalling - // for a generic map converts all numbers to floating point - err = schema.CastFloatToInt(config) - if err != nil { - return err - } - - // validate config according to schema - err = schema.ValidateConfig(config) - if err != nil { - return err - } - - // materialize the template - return template.WalkFileTree(config, filepath.Join(args[0], TemplateDirName), targetDir) + return template.Materialize(args[0], targetDir) }, } diff --git a/libs/template/materialize.go b/libs/template/materialize.go new file mode 100644 index 000000000..8501616c0 --- /dev/null +++ b/libs/template/materialize.go @@ -0,0 +1,24 @@ +package template + +import "path/filepath" + +const ConfigFileName = "config.json" +const SchemaFileName = "schema.json" +const TemplateDirName = "template" + +func Materialize(templatePath, instancePath string) error { + // read the file containing schema for template input parameters + schema, err := ReadSchema(filepath.Join(templatePath, SchemaFileName)) + if err != nil { + return err + } + + // read user config to initalize the template with + config, err := schema.ReadConfig(filepath.Join(instancePath, ConfigFileName)) + if err != nil { + return err + } + + // materialize the template + return WalkFileTree(config, filepath.Join(templatePath, TemplateDirName), instancePath) +} diff --git a/libs/template/schema.go b/libs/template/schema.go index 9a9f2fe31..0efbad554 100644 --- a/libs/template/schema.go +++ b/libs/template/schema.go @@ -1,7 +1,9 @@ package template import ( + "encoding/json" "fmt" + "os" "reflect" ) @@ -31,7 +33,7 @@ func isIntegerValue(v float64) bool { // integeres according to the schema // // Needed because the default json unmarshaller for maps converts all numbers to floats -func (schema Schema) CastFloatToInt(config map[string]any) error { +func castFloatToInt(config map[string]any, schema Schema) error { for k, v := range config { // error because all config keys should be defined in schema too if _, ok := schema[k]; !ok { @@ -93,3 +95,42 @@ func (schema Schema) ValidateConfig(config map[string]any) error { } return nil } + +func ReadSchema(path string) (Schema, error) { + schemaBytes, err := os.ReadFile(path) + if err != nil { + return nil, err + } + schema := Schema{} + err = json.Unmarshal(schemaBytes, &schema) + if err != nil { + return nil, err + } + return schema, nil +} + +func (schema Schema) ReadConfig(path string) (map[string]any, error) { + var config map[string]any + b, err := os.ReadFile(path) + if err != nil { + return nil, err + } + err = json.Unmarshal(b, &config) + if err != nil { + return nil, err + } + + // cast any fields that are supposed to be integers. The json unmarshalling + // for a generic map converts all numbers to floating point + err = castFloatToInt(config, schema) + if err != nil { + return nil, err + } + + // validate config according to schema + err = schema.ValidateConfig(config) + if err != nil { + return nil, err + } + return config, nil +} diff --git a/libs/template/schema_test.go b/libs/template/schema_test.go index 123e9c9ba..75d8f5034 100644 --- a/libs/template/schema_test.go +++ b/libs/template/schema_test.go @@ -56,7 +56,7 @@ func TestTemplateSchemaCastFloatToInt(t *testing.T) { assert.IsType(t, true, config["bool_val"]) assert.IsType(t, "abc", config["string_val"]) - err = schema.CastFloatToInt(config) + err = castFloatToInt(config, schema) require.NoError(t, err) // assert type after casting, that the float value was converted to an integer @@ -86,7 +86,7 @@ func TestTemplateSchemaCastFloatToIntFailsForUnknownTypes(t *testing.T) { err = json.Unmarshal([]byte(configJson), &config) require.NoError(t, err) - err = schema.CastFloatToInt(config) + err = castFloatToInt(config, schema) assert.ErrorContains(t, err, "bar is not defined as an input parameter for the template") } @@ -109,7 +109,7 @@ func TestTemplateSchemaCastFloatToIntFailsWhenWithNonIntValues(t *testing.T) { err = json.Unmarshal([]byte(configJson), &config) require.NoError(t, err) - err = schema.CastFloatToInt(config) + err = castFloatToInt(config, schema) assert.ErrorContains(t, err, "expected foo to have integer value but it is 1.1") } diff --git a/libs/template/validators.go b/libs/template/validators.go index 39e7fe9c4..000344167 100644 --- a/libs/template/validators.go +++ b/libs/template/validators.go @@ -46,3 +46,4 @@ var validators map[FieldType]Validator = map[FieldType]Validator{ FieldTypeInt: validateInteger, FieldTypeFloat: validateFloat, } +