From 5d2c0e3885070359c22310dd79fa5fe594c8e0f5 Mon Sep 17 00:00:00 2001 From: shreyas-goenka <88374338+shreyas-goenka@users.noreply.github.com> Date: Tue, 10 Sep 2024 20:19:34 +0530 Subject: [PATCH] Alias variables block in the `Target` struct (#1748) ## Changes This PR aliases and overrides the schema associated with the variables block in `target` to allow for directly specifying a variable value in the JSON schema (without an levels of nesting). This is needed because this direct value is resolved by dynamically parsing the configuration tree. https://github.com/databricks/cli/blob/ca6332a5a4325aff1be848536f45d13bd74d93b3/bundle/config/root.go#L424 ## Tests Existing unit tests. --- bundle/config/root_test.go | 2 +- bundle/config/target.go | 21 +++++++++++++++- bundle/config/variable/variable.go | 5 ++++ bundle/internal/schema/main.go | 16 ++++++++++++ bundle/schema/jsonschema.json | 39 +++++++++++++++++++++++++++++- 5 files changed, 80 insertions(+), 3 deletions(-) diff --git a/bundle/config/root_test.go b/bundle/config/root_test.go index c95e6e86..d2c7a9b1 100644 --- a/bundle/config/root_test.go +++ b/bundle/config/root_test.go @@ -139,7 +139,7 @@ func TestRootMergeTargetOverridesWithVariables(t *testing.T) { }, Targets: map[string]*Target{ "development": { - Variables: map[string]*variable.Variable{ + Variables: map[string]*variable.TargetVariable{ "foo": { Default: "bar", Description: "wrong", diff --git a/bundle/config/target.go b/bundle/config/target.go index a2ef4d73..fc6ba7b5 100644 --- a/bundle/config/target.go +++ b/bundle/config/target.go @@ -38,7 +38,26 @@ type Target struct { // Override default values or lookup name for defined variables // Does not permit defining new variables or redefining existing ones // in the scope of an target - Variables map[string]*variable.Variable `json:"variables,omitempty"` + // + // There are two valid ways to define a variable override in a target: + // 1. Direct value override. We normalize this to the variable.Variable + // struct format when loading the configuration YAML: + // + // variables: + // foo: "value" + // + // 2. Override matching the variable.Variable struct. + // + // variables: + // foo: + // default: "value" + // + // OR + // + // variables: + // foo: + // lookup: "resource_name" + Variables map[string]*variable.TargetVariable `json:"variables,omitempty"` Git Git `json:"git,omitempty"` diff --git a/bundle/config/variable/variable.go b/bundle/config/variable/variable.go index ba94f9c8..2362ad10 100644 --- a/bundle/config/variable/variable.go +++ b/bundle/config/variable/variable.go @@ -16,6 +16,11 @@ const ( VariableTypeComplex VariableType = "complex" ) +// We alias it here to override the JSON schema associated with a variable value +// in a target override. This is because we allow for directly specifying the value +// in addition to the variable.Variable struct format in a target override. +type TargetVariable Variable + // An input variable for the bundle config type Variable struct { // A type of the variable. This is used to validate the value of the variable diff --git a/bundle/internal/schema/main.go b/bundle/internal/schema/main.go index 3c1fb5da..4a237147 100644 --- a/bundle/internal/schema/main.go +++ b/bundle/internal/schema/main.go @@ -21,6 +21,22 @@ func addInterpolationPatterns(typ reflect.Type, s jsonschema.Schema) jsonschema. return s } + // The variables block in a target override allows for directly specifying + // the value of the variable. + if typ == reflect.TypeOf(variable.TargetVariable{}) { + return jsonschema.Schema{ + AnyOf: []jsonschema.Schema{ + // We keep the original schema so that autocomplete suggestions + // continue to work. + s, + // All values are valid for a variable value, be it primitive types + // like string/bool or complex ones like objects/arrays. Thus we override + // the schema to allow all valid JSON values. + {}, + }, + } + } + switch s.Type { case jsonschema.ArrayType, jsonschema.ObjectType: // arrays and objects can have complex variable values specified. diff --git a/bundle/schema/jsonschema.json b/bundle/schema/jsonschema.json index 4fe978b8..2db1a5ab 100644 --- a/bundle/schema/jsonschema.json +++ b/bundle/schema/jsonschema.json @@ -642,6 +642,29 @@ } ] }, + "variable.TargetVariable": { + "anyOf": [ + { + "type": "object", + "properties": { + "default": { + "$ref": "#/$defs/interface" + }, + "description": { + "$ref": "#/$defs/string" + }, + "lookup": { + "$ref": "#/$defs/github.com/databricks/cli/bundle/config/variable.Lookup" + }, + "type": { + "$ref": "#/$defs/github.com/databricks/cli/bundle/config/variable.VariableType" + } + }, + "additionalProperties": false + }, + {} + ] + }, "variable.Variable": { "type": "object", "properties": { @@ -995,7 +1018,7 @@ "$ref": "#/$defs/github.com/databricks/cli/bundle/config.Sync" }, "variables": { - "$ref": "#/$defs/map/github.com/databricks/cli/bundle/config/variable.Variable" + "$ref": "#/$defs/map/github.com/databricks/cli/bundle/config/variable.TargetVariable" }, "workspace": { "$ref": "#/$defs/github.com/databricks/cli/bundle/config.Workspace" @@ -4993,6 +5016,20 @@ } ] }, + "variable.TargetVariable": { + "anyOf": [ + { + "type": "object", + "additionalProperties": { + "$ref": "#/$defs/github.com/databricks/cli/bundle/config/variable.TargetVariable" + } + }, + { + "type": "string", + "pattern": "\\$\\{(var(\\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\\[[0-9]+\\])*)+)\\}" + } + ] + }, "variable.Variable": { "anyOf": [ {