mirror of https://github.com/databricks/cli.git
Stop tracking file path locations in bundle resources (#1673)
## Changes Since locations are already tracked in the dynamic value tree, we no longer need to track it at the resource/artifact level. This PR: 1. Removes use of `paths.Paths`. Uses dyn.Location instead. 2. Refactors the validation of resources not being empty valued to be generic across all resource types. ## Tests Existing unit tests.
This commit is contained in:
parent
ad8e61c739
commit
7ae80de351
|
@ -34,11 +34,13 @@ func (m *prepare) Apply(ctx context.Context, b *bundle.Bundle) diag.Diagnostics
|
||||||
return diag.Errorf("artifact doesn't exist: %s", m.name)
|
return diag.Errorf("artifact doesn't exist: %s", m.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
l := b.Config.GetLocation("artifacts." + m.name)
|
||||||
|
dirPath := filepath.Dir(l.File)
|
||||||
|
|
||||||
// Check if source paths are absolute, if not, make them absolute
|
// Check if source paths are absolute, if not, make them absolute
|
||||||
for k := range artifact.Files {
|
for k := range artifact.Files {
|
||||||
f := &artifact.Files[k]
|
f := &artifact.Files[k]
|
||||||
if !filepath.IsAbs(f.Source) {
|
if !filepath.IsAbs(f.Source) {
|
||||||
dirPath := filepath.Dir(artifact.ConfigFilePath)
|
|
||||||
f.Source = filepath.Join(dirPath, f.Source)
|
f.Source = filepath.Join(dirPath, f.Source)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,7 +51,6 @@ func (m *prepare) Apply(ctx context.Context, b *bundle.Bundle) diag.Diagnostics
|
||||||
}
|
}
|
||||||
|
|
||||||
if !filepath.IsAbs(artifact.Path) {
|
if !filepath.IsAbs(artifact.Path) {
|
||||||
dirPath := filepath.Dir(artifact.ConfigFilePath)
|
|
||||||
artifact.Path = filepath.Join(dirPath, artifact.Path)
|
artifact.Path = filepath.Join(dirPath, artifact.Path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,18 +4,11 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/databricks/cli/bundle/config/paths"
|
|
||||||
"github.com/databricks/cli/libs/exec"
|
"github.com/databricks/cli/libs/exec"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Artifacts map[string]*Artifact
|
type Artifacts map[string]*Artifact
|
||||||
|
|
||||||
func (artifacts Artifacts) ConfigureConfigFilePath() {
|
|
||||||
for _, artifact := range artifacts {
|
|
||||||
artifact.ConfigureConfigFilePath()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type ArtifactType string
|
type ArtifactType string
|
||||||
|
|
||||||
const ArtifactPythonWheel ArtifactType = `whl`
|
const ArtifactPythonWheel ArtifactType = `whl`
|
||||||
|
@ -40,8 +33,6 @@ type Artifact struct {
|
||||||
BuildCommand string `json:"build,omitempty"`
|
BuildCommand string `json:"build,omitempty"`
|
||||||
|
|
||||||
Executable exec.ExecutableType `json:"executable,omitempty"`
|
Executable exec.ExecutableType `json:"executable,omitempty"`
|
||||||
|
|
||||||
paths.Paths
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Artifact) Build(ctx context.Context) ([]byte, error) {
|
func (a *Artifact) Build(ctx context.Context) ([]byte, error) {
|
||||||
|
|
|
@ -9,7 +9,6 @@ import (
|
||||||
|
|
||||||
"github.com/databricks/cli/bundle"
|
"github.com/databricks/cli/bundle"
|
||||||
"github.com/databricks/cli/bundle/config"
|
"github.com/databricks/cli/bundle/config"
|
||||||
"github.com/databricks/cli/bundle/config/paths"
|
|
||||||
"github.com/databricks/cli/bundle/config/resources"
|
"github.com/databricks/cli/bundle/config/resources"
|
||||||
"github.com/databricks/databricks-sdk-go/service/jobs"
|
"github.com/databricks/databricks-sdk-go/service/jobs"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
@ -65,9 +64,6 @@ func TestGenerateTrampoline(t *testing.T) {
|
||||||
Resources: config.Resources{
|
Resources: config.Resources{
|
||||||
Jobs: map[string]*resources.Job{
|
Jobs: map[string]*resources.Job{
|
||||||
"test": {
|
"test": {
|
||||||
Paths: paths.Paths{
|
|
||||||
ConfigFilePath: tmpDir,
|
|
||||||
},
|
|
||||||
JobSettings: &jobs.JobSettings{
|
JobSettings: &jobs.JobSettings{
|
||||||
Tasks: tasks,
|
Tasks: tasks,
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
package paths
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/databricks/cli/libs/dyn"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Paths struct {
|
|
||||||
// Absolute path on the local file system to the configuration file that holds
|
|
||||||
// the definition of this resource.
|
|
||||||
ConfigFilePath string `json:"-" bundle:"readonly"`
|
|
||||||
|
|
||||||
// DynamicValue stores the [dyn.Value] of the containing struct.
|
|
||||||
// This assumes that this struct is always embedded.
|
|
||||||
DynamicValue dyn.Value `json:"-"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Paths) ConfigureConfigFilePath() {
|
|
||||||
if !p.DynamicValue.IsValid() {
|
|
||||||
panic("DynamicValue not set")
|
|
||||||
}
|
|
||||||
p.ConfigFilePath = p.DynamicValue.Location().File
|
|
||||||
}
|
|
|
@ -21,81 +21,14 @@ type Resources struct {
|
||||||
Schemas map[string]*resources.Schema `json:"schemas,omitempty"`
|
Schemas map[string]*resources.Schema `json:"schemas,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type resource struct {
|
|
||||||
resource ConfigResource
|
|
||||||
resource_type string
|
|
||||||
key string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Resources) allResources() []resource {
|
|
||||||
all := make([]resource, 0)
|
|
||||||
for k, e := range r.Jobs {
|
|
||||||
all = append(all, resource{resource_type: "job", resource: e, key: k})
|
|
||||||
}
|
|
||||||
for k, e := range r.Pipelines {
|
|
||||||
all = append(all, resource{resource_type: "pipeline", resource: e, key: k})
|
|
||||||
}
|
|
||||||
for k, e := range r.Models {
|
|
||||||
all = append(all, resource{resource_type: "model", resource: e, key: k})
|
|
||||||
}
|
|
||||||
for k, e := range r.Experiments {
|
|
||||||
all = append(all, resource{resource_type: "experiment", resource: e, key: k})
|
|
||||||
}
|
|
||||||
for k, e := range r.ModelServingEndpoints {
|
|
||||||
all = append(all, resource{resource_type: "serving endpoint", resource: e, key: k})
|
|
||||||
}
|
|
||||||
for k, e := range r.RegisteredModels {
|
|
||||||
all = append(all, resource{resource_type: "registered model", resource: e, key: k})
|
|
||||||
}
|
|
||||||
for k, e := range r.QualityMonitors {
|
|
||||||
all = append(all, resource{resource_type: "quality monitor", resource: e, key: k})
|
|
||||||
}
|
|
||||||
return all
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Resources) VerifyAllResourcesDefined() error {
|
|
||||||
all := r.allResources()
|
|
||||||
for _, e := range all {
|
|
||||||
err := e.resource.Validate()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("%s %s is not defined", e.resource_type, e.key)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ConfigureConfigFilePath sets the specified path for all resources contained in this instance.
|
|
||||||
// This property is used to correctly resolve paths relative to the path
|
|
||||||
// of the configuration file they were defined in.
|
|
||||||
func (r *Resources) ConfigureConfigFilePath() {
|
|
||||||
for _, e := range r.Jobs {
|
|
||||||
e.ConfigureConfigFilePath()
|
|
||||||
}
|
|
||||||
for _, e := range r.Pipelines {
|
|
||||||
e.ConfigureConfigFilePath()
|
|
||||||
}
|
|
||||||
for _, e := range r.Models {
|
|
||||||
e.ConfigureConfigFilePath()
|
|
||||||
}
|
|
||||||
for _, e := range r.Experiments {
|
|
||||||
e.ConfigureConfigFilePath()
|
|
||||||
}
|
|
||||||
for _, e := range r.ModelServingEndpoints {
|
|
||||||
e.ConfigureConfigFilePath()
|
|
||||||
}
|
|
||||||
for _, e := range r.RegisteredModels {
|
|
||||||
e.ConfigureConfigFilePath()
|
|
||||||
}
|
|
||||||
for _, e := range r.QualityMonitors {
|
|
||||||
e.ConfigureConfigFilePath()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type ConfigResource interface {
|
type ConfigResource interface {
|
||||||
|
// Function to assert if the resource exists in the workspace configured in
|
||||||
|
// the input workspace client.
|
||||||
Exists(ctx context.Context, w *databricks.WorkspaceClient, id string) (bool, error)
|
Exists(ctx context.Context, w *databricks.WorkspaceClient, id string) (bool, error)
|
||||||
|
|
||||||
|
// Terraform equivalent name of the resource. For example "databricks_job"
|
||||||
|
// for jobs and "databricks_pipeline" for pipelines.
|
||||||
TerraformResourceName() string
|
TerraformResourceName() string
|
||||||
Validate() error
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Resources) FindResourceByConfigKey(key string) (ConfigResource, error) {
|
func (r *Resources) FindResourceByConfigKey(key string) (ConfigResource, error) {
|
||||||
|
|
|
@ -2,10 +2,8 @@ package resources
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/databricks/cli/bundle/config/paths"
|
|
||||||
"github.com/databricks/cli/libs/log"
|
"github.com/databricks/cli/libs/log"
|
||||||
"github.com/databricks/databricks-sdk-go"
|
"github.com/databricks/databricks-sdk-go"
|
||||||
"github.com/databricks/databricks-sdk-go/marshal"
|
"github.com/databricks/databricks-sdk-go/marshal"
|
||||||
|
@ -17,8 +15,6 @@ type Job struct {
|
||||||
Permissions []Permission `json:"permissions,omitempty"`
|
Permissions []Permission `json:"permissions,omitempty"`
|
||||||
ModifiedStatus ModifiedStatus `json:"modified_status,omitempty" bundle:"internal"`
|
ModifiedStatus ModifiedStatus `json:"modified_status,omitempty" bundle:"internal"`
|
||||||
|
|
||||||
paths.Paths
|
|
||||||
|
|
||||||
*jobs.JobSettings
|
*jobs.JobSettings
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,11 +44,3 @@ func (j *Job) Exists(ctx context.Context, w *databricks.WorkspaceClient, id stri
|
||||||
func (j *Job) TerraformResourceName() string {
|
func (j *Job) TerraformResourceName() string {
|
||||||
return "databricks_job"
|
return "databricks_job"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (j *Job) Validate() error {
|
|
||||||
if j == nil || !j.DynamicValue.IsValid() || j.JobSettings == nil {
|
|
||||||
return fmt.Errorf("job is not defined")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
|
@ -2,9 +2,7 @@ package resources
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/databricks/cli/bundle/config/paths"
|
|
||||||
"github.com/databricks/cli/libs/log"
|
"github.com/databricks/cli/libs/log"
|
||||||
"github.com/databricks/databricks-sdk-go"
|
"github.com/databricks/databricks-sdk-go"
|
||||||
"github.com/databricks/databricks-sdk-go/marshal"
|
"github.com/databricks/databricks-sdk-go/marshal"
|
||||||
|
@ -16,8 +14,6 @@ type MlflowExperiment struct {
|
||||||
Permissions []Permission `json:"permissions,omitempty"`
|
Permissions []Permission `json:"permissions,omitempty"`
|
||||||
ModifiedStatus ModifiedStatus `json:"modified_status,omitempty" bundle:"internal"`
|
ModifiedStatus ModifiedStatus `json:"modified_status,omitempty" bundle:"internal"`
|
||||||
|
|
||||||
paths.Paths
|
|
||||||
|
|
||||||
*ml.Experiment
|
*ml.Experiment
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,11 +39,3 @@ func (s *MlflowExperiment) Exists(ctx context.Context, w *databricks.WorkspaceCl
|
||||||
func (s *MlflowExperiment) TerraformResourceName() string {
|
func (s *MlflowExperiment) TerraformResourceName() string {
|
||||||
return "databricks_mlflow_experiment"
|
return "databricks_mlflow_experiment"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *MlflowExperiment) Validate() error {
|
|
||||||
if s == nil || !s.DynamicValue.IsValid() {
|
|
||||||
return fmt.Errorf("experiment is not defined")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
|
@ -2,9 +2,7 @@ package resources
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/databricks/cli/bundle/config/paths"
|
|
||||||
"github.com/databricks/cli/libs/log"
|
"github.com/databricks/cli/libs/log"
|
||||||
"github.com/databricks/databricks-sdk-go"
|
"github.com/databricks/databricks-sdk-go"
|
||||||
"github.com/databricks/databricks-sdk-go/marshal"
|
"github.com/databricks/databricks-sdk-go/marshal"
|
||||||
|
@ -16,8 +14,6 @@ type MlflowModel struct {
|
||||||
Permissions []Permission `json:"permissions,omitempty"`
|
Permissions []Permission `json:"permissions,omitempty"`
|
||||||
ModifiedStatus ModifiedStatus `json:"modified_status,omitempty" bundle:"internal"`
|
ModifiedStatus ModifiedStatus `json:"modified_status,omitempty" bundle:"internal"`
|
||||||
|
|
||||||
paths.Paths
|
|
||||||
|
|
||||||
*ml.Model
|
*ml.Model
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,11 +39,3 @@ func (s *MlflowModel) Exists(ctx context.Context, w *databricks.WorkspaceClient,
|
||||||
func (s *MlflowModel) TerraformResourceName() string {
|
func (s *MlflowModel) TerraformResourceName() string {
|
||||||
return "databricks_mlflow_model"
|
return "databricks_mlflow_model"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *MlflowModel) Validate() error {
|
|
||||||
if s == nil || !s.DynamicValue.IsValid() {
|
|
||||||
return fmt.Errorf("model is not defined")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
|
@ -2,9 +2,7 @@ package resources
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/databricks/cli/bundle/config/paths"
|
|
||||||
"github.com/databricks/cli/libs/log"
|
"github.com/databricks/cli/libs/log"
|
||||||
"github.com/databricks/databricks-sdk-go"
|
"github.com/databricks/databricks-sdk-go"
|
||||||
"github.com/databricks/databricks-sdk-go/marshal"
|
"github.com/databricks/databricks-sdk-go/marshal"
|
||||||
|
@ -20,10 +18,6 @@ type ModelServingEndpoint struct {
|
||||||
// as a reference in other resources. This value is returned by terraform.
|
// as a reference in other resources. This value is returned by terraform.
|
||||||
ID string `json:"id,omitempty" bundle:"readonly"`
|
ID string `json:"id,omitempty" bundle:"readonly"`
|
||||||
|
|
||||||
// Path to config file where the resource is defined. All bundle resources
|
|
||||||
// include this for interpolation purposes.
|
|
||||||
paths.Paths
|
|
||||||
|
|
||||||
// This is a resource agnostic implementation of permissions for ACLs.
|
// This is a resource agnostic implementation of permissions for ACLs.
|
||||||
// Implementation could be different based on the resource type.
|
// Implementation could be different based on the resource type.
|
||||||
Permissions []Permission `json:"permissions,omitempty"`
|
Permissions []Permission `json:"permissions,omitempty"`
|
||||||
|
@ -53,11 +47,3 @@ func (s *ModelServingEndpoint) Exists(ctx context.Context, w *databricks.Workspa
|
||||||
func (s *ModelServingEndpoint) TerraformResourceName() string {
|
func (s *ModelServingEndpoint) TerraformResourceName() string {
|
||||||
return "databricks_model_serving"
|
return "databricks_model_serving"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ModelServingEndpoint) Validate() error {
|
|
||||||
if s == nil || !s.DynamicValue.IsValid() {
|
|
||||||
return fmt.Errorf("serving endpoint is not defined")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
|
@ -2,9 +2,7 @@ package resources
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/databricks/cli/bundle/config/paths"
|
|
||||||
"github.com/databricks/cli/libs/log"
|
"github.com/databricks/cli/libs/log"
|
||||||
"github.com/databricks/databricks-sdk-go"
|
"github.com/databricks/databricks-sdk-go"
|
||||||
"github.com/databricks/databricks-sdk-go/marshal"
|
"github.com/databricks/databricks-sdk-go/marshal"
|
||||||
|
@ -16,8 +14,6 @@ type Pipeline struct {
|
||||||
Permissions []Permission `json:"permissions,omitempty"`
|
Permissions []Permission `json:"permissions,omitempty"`
|
||||||
ModifiedStatus ModifiedStatus `json:"modified_status,omitempty" bundle:"internal"`
|
ModifiedStatus ModifiedStatus `json:"modified_status,omitempty" bundle:"internal"`
|
||||||
|
|
||||||
paths.Paths
|
|
||||||
|
|
||||||
*pipelines.PipelineSpec
|
*pipelines.PipelineSpec
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,11 +39,3 @@ func (p *Pipeline) Exists(ctx context.Context, w *databricks.WorkspaceClient, id
|
||||||
func (p *Pipeline) TerraformResourceName() string {
|
func (p *Pipeline) TerraformResourceName() string {
|
||||||
return "databricks_pipeline"
|
return "databricks_pipeline"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Pipeline) Validate() error {
|
|
||||||
if p == nil || !p.DynamicValue.IsValid() {
|
|
||||||
return fmt.Errorf("pipeline is not defined")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
|
@ -2,9 +2,7 @@ package resources
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/databricks/cli/bundle/config/paths"
|
|
||||||
"github.com/databricks/cli/libs/log"
|
"github.com/databricks/cli/libs/log"
|
||||||
"github.com/databricks/databricks-sdk-go"
|
"github.com/databricks/databricks-sdk-go"
|
||||||
"github.com/databricks/databricks-sdk-go/marshal"
|
"github.com/databricks/databricks-sdk-go/marshal"
|
||||||
|
@ -21,10 +19,6 @@ type QualityMonitor struct {
|
||||||
// as a reference in other resources. This value is returned by terraform.
|
// as a reference in other resources. This value is returned by terraform.
|
||||||
ID string `json:"id,omitempty" bundle:"readonly"`
|
ID string `json:"id,omitempty" bundle:"readonly"`
|
||||||
|
|
||||||
// Path to config file where the resource is defined. All bundle resources
|
|
||||||
// include this for interpolation purposes.
|
|
||||||
paths.Paths
|
|
||||||
|
|
||||||
ModifiedStatus ModifiedStatus `json:"modified_status,omitempty" bundle:"internal"`
|
ModifiedStatus ModifiedStatus `json:"modified_status,omitempty" bundle:"internal"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,11 +44,3 @@ func (s *QualityMonitor) Exists(ctx context.Context, w *databricks.WorkspaceClie
|
||||||
func (s *QualityMonitor) TerraformResourceName() string {
|
func (s *QualityMonitor) TerraformResourceName() string {
|
||||||
return "databricks_quality_monitor"
|
return "databricks_quality_monitor"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *QualityMonitor) Validate() error {
|
|
||||||
if s == nil || !s.DynamicValue.IsValid() {
|
|
||||||
return fmt.Errorf("quality monitor is not defined")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
|
@ -2,9 +2,7 @@ package resources
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/databricks/cli/bundle/config/paths"
|
|
||||||
"github.com/databricks/cli/libs/log"
|
"github.com/databricks/cli/libs/log"
|
||||||
"github.com/databricks/databricks-sdk-go"
|
"github.com/databricks/databricks-sdk-go"
|
||||||
"github.com/databricks/databricks-sdk-go/marshal"
|
"github.com/databricks/databricks-sdk-go/marshal"
|
||||||
|
@ -21,10 +19,6 @@ type RegisteredModel struct {
|
||||||
// as a reference in other resources. This value is returned by terraform.
|
// as a reference in other resources. This value is returned by terraform.
|
||||||
ID string `json:"id,omitempty" bundle:"readonly"`
|
ID string `json:"id,omitempty" bundle:"readonly"`
|
||||||
|
|
||||||
// Path to config file where the resource is defined. All bundle resources
|
|
||||||
// include this for interpolation purposes.
|
|
||||||
paths.Paths
|
|
||||||
|
|
||||||
// This represents the input args for terraform, and will get converted
|
// This represents the input args for terraform, and will get converted
|
||||||
// to a HCL representation for CRUD
|
// to a HCL representation for CRUD
|
||||||
*catalog.CreateRegisteredModelRequest
|
*catalog.CreateRegisteredModelRequest
|
||||||
|
@ -54,11 +48,3 @@ func (s *RegisteredModel) Exists(ctx context.Context, w *databricks.WorkspaceCli
|
||||||
func (s *RegisteredModel) TerraformResourceName() string {
|
func (s *RegisteredModel) TerraformResourceName() string {
|
||||||
return "databricks_registered_model"
|
return "databricks_registered_model"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *RegisteredModel) Validate() error {
|
|
||||||
if s == nil || !s.DynamicValue.IsValid() {
|
|
||||||
return fmt.Errorf("registered model is not defined")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
|
@ -136,17 +136,6 @@ func (r *Root) updateWithDynamicValue(nv dyn.Value) error {
|
||||||
|
|
||||||
// Assign the normalized configuration tree.
|
// Assign the normalized configuration tree.
|
||||||
r.value = nv
|
r.value = nv
|
||||||
|
|
||||||
// At the moment the check has to be done as part of updateWithDynamicValue
|
|
||||||
// because otherwise ConfigureConfigFilePath will fail with a panic.
|
|
||||||
// In the future, we should move this check to a separate mutator in initialise phase.
|
|
||||||
err = r.Resources.VerifyAllResourcesDefined()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assign config file paths after converting to typed configuration.
|
|
||||||
r.ConfigureConfigFilePath()
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -238,15 +227,6 @@ func (r *Root) MarkMutatorExit(ctx context.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetConfigFilePath configures the path that its configuration
|
|
||||||
// was loaded from in configuration leafs that require it.
|
|
||||||
func (r *Root) ConfigureConfigFilePath() {
|
|
||||||
r.Resources.ConfigureConfigFilePath()
|
|
||||||
if r.Artifacts != nil {
|
|
||||||
r.Artifacts.ConfigureConfigFilePath()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initializes variables using values passed from the command line flag
|
// Initializes variables using values passed from the command line flag
|
||||||
// Input has to be a string of the form `foo=bar`. In this case the variable with
|
// Input has to be a string of the form `foo=bar`. In this case the variable with
|
||||||
// name `foo` is assigned the value `bar`
|
// name `foo` is assigned the value `bar`
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
package validate
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/databricks/cli/bundle"
|
||||||
|
"github.com/databricks/cli/libs/diag"
|
||||||
|
"github.com/databricks/cli/libs/dyn"
|
||||||
|
)
|
||||||
|
|
||||||
|
func AllResourcesHaveValues() bundle.Mutator {
|
||||||
|
return &allResourcesHaveValues{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type allResourcesHaveValues struct{}
|
||||||
|
|
||||||
|
func (m *allResourcesHaveValues) Name() string {
|
||||||
|
return "validate:AllResourcesHaveValues"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *allResourcesHaveValues) Apply(ctx context.Context, b *bundle.Bundle) diag.Diagnostics {
|
||||||
|
rv := b.Config.Value().Get("resources")
|
||||||
|
|
||||||
|
// Skip if there are no resources block defined, or the resources block is empty.
|
||||||
|
if rv.Kind() == dyn.KindInvalid || rv.Kind() == dyn.KindNil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := dyn.MapByPattern(
|
||||||
|
rv,
|
||||||
|
dyn.NewPattern(dyn.AnyKey(), dyn.AnyKey()),
|
||||||
|
func(p dyn.Path, v dyn.Value) (dyn.Value, error) {
|
||||||
|
if v.Kind() == dyn.KindInvalid || v.Kind() == dyn.KindNil {
|
||||||
|
// Type of the resource, stripped of the trailing 's' to make it
|
||||||
|
// singular.
|
||||||
|
rType := strings.TrimSuffix(p[0].Key(), "s")
|
||||||
|
|
||||||
|
rName := p[1].Key()
|
||||||
|
return v, fmt.Errorf("%s %s is not defined", rType, rName)
|
||||||
|
}
|
||||||
|
return v, nil
|
||||||
|
},
|
||||||
|
)
|
||||||
|
return diag.FromErr(err)
|
||||||
|
}
|
|
@ -39,7 +39,8 @@ func (m *compute) Apply(_ context.Context, b *bundle.Bundle) diag.Diagnostics {
|
||||||
for name, job := range b.Config.Resources.Jobs {
|
for name, job := range b.Config.Resources.Jobs {
|
||||||
// Compute config file path the job is defined in, relative to the bundle
|
// Compute config file path the job is defined in, relative to the bundle
|
||||||
// root
|
// root
|
||||||
relativePath, err := filepath.Rel(b.RootPath, job.ConfigFilePath)
|
l := b.Config.GetLocation("resources.jobs." + name)
|
||||||
|
relativePath, err := filepath.Rel(b.RootPath, l.File)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return diag.Errorf("failed to compute relative path for job %s: %v", name, err)
|
return diag.Errorf("failed to compute relative path for job %s: %v", name, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,4 @@ func SetLocation(b *bundle.Bundle, prefix string, filePath string) {
|
||||||
return v, dyn.ErrSkip
|
return v, dyn.ErrSkip
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
b.Config.ConfigureConfigFilePath()
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"github.com/databricks/cli/bundle/config"
|
"github.com/databricks/cli/bundle/config"
|
||||||
"github.com/databricks/cli/bundle/config/mutator"
|
"github.com/databricks/cli/bundle/config/mutator"
|
||||||
pythonmutator "github.com/databricks/cli/bundle/config/mutator/python"
|
pythonmutator "github.com/databricks/cli/bundle/config/mutator/python"
|
||||||
|
"github.com/databricks/cli/bundle/config/validate"
|
||||||
"github.com/databricks/cli/bundle/deploy/metadata"
|
"github.com/databricks/cli/bundle/deploy/metadata"
|
||||||
"github.com/databricks/cli/bundle/deploy/terraform"
|
"github.com/databricks/cli/bundle/deploy/terraform"
|
||||||
"github.com/databricks/cli/bundle/permissions"
|
"github.com/databricks/cli/bundle/permissions"
|
||||||
|
@ -19,6 +20,7 @@ func Initialize() bundle.Mutator {
|
||||||
return newPhase(
|
return newPhase(
|
||||||
"initialize",
|
"initialize",
|
||||||
[]bundle.Mutator{
|
[]bundle.Mutator{
|
||||||
|
validate.AllResourcesHaveValues(),
|
||||||
mutator.RewriteSyncPaths(),
|
mutator.RewriteSyncPaths(),
|
||||||
mutator.MergeJobClusters(),
|
mutator.MergeJobClusters(),
|
||||||
mutator.MergeJobParameters(),
|
mutator.MergeJobParameters(),
|
||||||
|
|
|
@ -7,7 +7,6 @@ import (
|
||||||
|
|
||||||
"github.com/databricks/cli/bundle"
|
"github.com/databricks/cli/bundle"
|
||||||
"github.com/databricks/cli/bundle/config"
|
"github.com/databricks/cli/bundle/config"
|
||||||
"github.com/databricks/cli/bundle/config/paths"
|
|
||||||
"github.com/databricks/cli/bundle/config/resources"
|
"github.com/databricks/cli/bundle/config/resources"
|
||||||
"github.com/databricks/databricks-sdk-go/service/compute"
|
"github.com/databricks/databricks-sdk-go/service/compute"
|
||||||
"github.com/databricks/databricks-sdk-go/service/jobs"
|
"github.com/databricks/databricks-sdk-go/service/jobs"
|
||||||
|
@ -124,9 +123,6 @@ func TestNoPanicWithNoPythonWheelTasks(t *testing.T) {
|
||||||
Resources: config.Resources{
|
Resources: config.Resources{
|
||||||
Jobs: map[string]*resources.Job{
|
Jobs: map[string]*resources.Job{
|
||||||
"test": {
|
"test": {
|
||||||
Paths: paths.Paths{
|
|
||||||
ConfigFilePath: tmpDir,
|
|
||||||
},
|
|
||||||
JobSettings: &jobs.JobSettings{
|
JobSettings: &jobs.JobSettings{
|
||||||
Tasks: []jobs.Task{
|
Tasks: []jobs.Task{
|
||||||
{
|
{
|
||||||
|
|
|
@ -15,7 +15,8 @@ func TestJobAndPipelineDevelopmentWithEnvironment(t *testing.T) {
|
||||||
assert.Len(t, b.Config.Resources.Pipelines, 1)
|
assert.Len(t, b.Config.Resources.Pipelines, 1)
|
||||||
|
|
||||||
p := b.Config.Resources.Pipelines["nyc_taxi_pipeline"]
|
p := b.Config.Resources.Pipelines["nyc_taxi_pipeline"]
|
||||||
assert.Equal(t, "environments_job_and_pipeline/databricks.yml", filepath.ToSlash(p.ConfigFilePath))
|
l := b.Config.GetLocation("resources.pipelines.nyc_taxi_pipeline")
|
||||||
|
assert.Equal(t, "environments_job_and_pipeline/databricks.yml", filepath.ToSlash(l.File))
|
||||||
assert.Equal(t, b.Config.Bundle.Mode, config.Development)
|
assert.Equal(t, b.Config.Bundle.Mode, config.Development)
|
||||||
assert.True(t, p.Development)
|
assert.True(t, p.Development)
|
||||||
require.Len(t, p.Libraries, 1)
|
require.Len(t, p.Libraries, 1)
|
||||||
|
@ -29,7 +30,8 @@ func TestJobAndPipelineStagingWithEnvironment(t *testing.T) {
|
||||||
assert.Len(t, b.Config.Resources.Pipelines, 1)
|
assert.Len(t, b.Config.Resources.Pipelines, 1)
|
||||||
|
|
||||||
p := b.Config.Resources.Pipelines["nyc_taxi_pipeline"]
|
p := b.Config.Resources.Pipelines["nyc_taxi_pipeline"]
|
||||||
assert.Equal(t, "environments_job_and_pipeline/databricks.yml", filepath.ToSlash(p.ConfigFilePath))
|
l := b.Config.GetLocation("resources.pipelines.nyc_taxi_pipeline")
|
||||||
|
assert.Equal(t, "environments_job_and_pipeline/databricks.yml", filepath.ToSlash(l.File))
|
||||||
assert.False(t, p.Development)
|
assert.False(t, p.Development)
|
||||||
require.Len(t, p.Libraries, 1)
|
require.Len(t, p.Libraries, 1)
|
||||||
assert.Equal(t, "./dlt/nyc_taxi_loader", p.Libraries[0].Notebook.Path)
|
assert.Equal(t, "./dlt/nyc_taxi_loader", p.Libraries[0].Notebook.Path)
|
||||||
|
@ -42,14 +44,16 @@ func TestJobAndPipelineProductionWithEnvironment(t *testing.T) {
|
||||||
assert.Len(t, b.Config.Resources.Pipelines, 1)
|
assert.Len(t, b.Config.Resources.Pipelines, 1)
|
||||||
|
|
||||||
p := b.Config.Resources.Pipelines["nyc_taxi_pipeline"]
|
p := b.Config.Resources.Pipelines["nyc_taxi_pipeline"]
|
||||||
assert.Equal(t, "environments_job_and_pipeline/databricks.yml", filepath.ToSlash(p.ConfigFilePath))
|
pl := b.Config.GetLocation("resources.pipelines.nyc_taxi_pipeline")
|
||||||
|
assert.Equal(t, "environments_job_and_pipeline/databricks.yml", filepath.ToSlash(pl.File))
|
||||||
assert.False(t, p.Development)
|
assert.False(t, p.Development)
|
||||||
require.Len(t, p.Libraries, 1)
|
require.Len(t, p.Libraries, 1)
|
||||||
assert.Equal(t, "./dlt/nyc_taxi_loader", p.Libraries[0].Notebook.Path)
|
assert.Equal(t, "./dlt/nyc_taxi_loader", p.Libraries[0].Notebook.Path)
|
||||||
assert.Equal(t, "nyc_taxi_production", p.Target)
|
assert.Equal(t, "nyc_taxi_production", p.Target)
|
||||||
|
|
||||||
j := b.Config.Resources.Jobs["pipeline_schedule"]
|
j := b.Config.Resources.Jobs["pipeline_schedule"]
|
||||||
assert.Equal(t, "environments_job_and_pipeline/databricks.yml", filepath.ToSlash(j.ConfigFilePath))
|
jl := b.Config.GetLocation("resources.jobs.pipeline_schedule")
|
||||||
|
assert.Equal(t, "environments_job_and_pipeline/databricks.yml", filepath.ToSlash(jl.File))
|
||||||
assert.Equal(t, "Daily refresh of production pipeline", j.Name)
|
assert.Equal(t, "Daily refresh of production pipeline", j.Name)
|
||||||
require.Len(t, j.Tasks, 1)
|
require.Len(t, j.Tasks, 1)
|
||||||
assert.NotEmpty(t, j.Tasks[0].PipelineTask.PipelineId)
|
assert.NotEmpty(t, j.Tasks[0].PipelineTask.PipelineId)
|
||||||
|
|
|
@ -31,7 +31,8 @@ func TestIncludeWithGlob(t *testing.T) {
|
||||||
|
|
||||||
job := b.Config.Resources.Jobs["my_job"]
|
job := b.Config.Resources.Jobs["my_job"]
|
||||||
assert.Equal(t, "1", job.ID)
|
assert.Equal(t, "1", job.ID)
|
||||||
assert.Equal(t, "include_with_glob/job.yml", filepath.ToSlash(job.ConfigFilePath))
|
l := b.Config.GetLocation("resources.jobs.my_job")
|
||||||
|
assert.Equal(t, "include_with_glob/job.yml", filepath.ToSlash(l.File))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestIncludeDefault(t *testing.T) {
|
func TestIncludeDefault(t *testing.T) {
|
||||||
|
@ -51,9 +52,11 @@ func TestIncludeForMultipleMatches(t *testing.T) {
|
||||||
|
|
||||||
first := b.Config.Resources.Jobs["my_first_job"]
|
first := b.Config.Resources.Jobs["my_first_job"]
|
||||||
assert.Equal(t, "1", first.ID)
|
assert.Equal(t, "1", first.ID)
|
||||||
assert.Equal(t, "include_multiple/my_first_job/resource.yml", filepath.ToSlash(first.ConfigFilePath))
|
fl := b.Config.GetLocation("resources.jobs.my_first_job")
|
||||||
|
assert.Equal(t, "include_multiple/my_first_job/resource.yml", filepath.ToSlash(fl.File))
|
||||||
|
|
||||||
second := b.Config.Resources.Jobs["my_second_job"]
|
second := b.Config.Resources.Jobs["my_second_job"]
|
||||||
assert.Equal(t, "2", second.ID)
|
assert.Equal(t, "2", second.ID)
|
||||||
assert.Equal(t, "include_multiple/my_second_job/resource.yml", filepath.ToSlash(second.ConfigFilePath))
|
sl := b.Config.GetLocation("resources.jobs.my_second_job")
|
||||||
|
assert.Equal(t, "include_multiple/my_second_job/resource.yml", filepath.ToSlash(sl.File))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package config_tests
|
package config_tests
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"path/filepath"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/databricks/cli/bundle/config"
|
"github.com/databricks/cli/bundle/config"
|
||||||
|
@ -15,7 +14,6 @@ func TestJobAndPipelineDevelopment(t *testing.T) {
|
||||||
assert.Len(t, b.Config.Resources.Pipelines, 1)
|
assert.Len(t, b.Config.Resources.Pipelines, 1)
|
||||||
|
|
||||||
p := b.Config.Resources.Pipelines["nyc_taxi_pipeline"]
|
p := b.Config.Resources.Pipelines["nyc_taxi_pipeline"]
|
||||||
assert.Equal(t, "job_and_pipeline/databricks.yml", filepath.ToSlash(p.ConfigFilePath))
|
|
||||||
assert.Equal(t, b.Config.Bundle.Mode, config.Development)
|
assert.Equal(t, b.Config.Bundle.Mode, config.Development)
|
||||||
assert.True(t, p.Development)
|
assert.True(t, p.Development)
|
||||||
require.Len(t, p.Libraries, 1)
|
require.Len(t, p.Libraries, 1)
|
||||||
|
@ -29,7 +27,6 @@ func TestJobAndPipelineStaging(t *testing.T) {
|
||||||
assert.Len(t, b.Config.Resources.Pipelines, 1)
|
assert.Len(t, b.Config.Resources.Pipelines, 1)
|
||||||
|
|
||||||
p := b.Config.Resources.Pipelines["nyc_taxi_pipeline"]
|
p := b.Config.Resources.Pipelines["nyc_taxi_pipeline"]
|
||||||
assert.Equal(t, "job_and_pipeline/databricks.yml", filepath.ToSlash(p.ConfigFilePath))
|
|
||||||
assert.False(t, p.Development)
|
assert.False(t, p.Development)
|
||||||
require.Len(t, p.Libraries, 1)
|
require.Len(t, p.Libraries, 1)
|
||||||
assert.Equal(t, "./dlt/nyc_taxi_loader", p.Libraries[0].Notebook.Path)
|
assert.Equal(t, "./dlt/nyc_taxi_loader", p.Libraries[0].Notebook.Path)
|
||||||
|
@ -42,14 +39,12 @@ func TestJobAndPipelineProduction(t *testing.T) {
|
||||||
assert.Len(t, b.Config.Resources.Pipelines, 1)
|
assert.Len(t, b.Config.Resources.Pipelines, 1)
|
||||||
|
|
||||||
p := b.Config.Resources.Pipelines["nyc_taxi_pipeline"]
|
p := b.Config.Resources.Pipelines["nyc_taxi_pipeline"]
|
||||||
assert.Equal(t, "job_and_pipeline/databricks.yml", filepath.ToSlash(p.ConfigFilePath))
|
|
||||||
assert.False(t, p.Development)
|
assert.False(t, p.Development)
|
||||||
require.Len(t, p.Libraries, 1)
|
require.Len(t, p.Libraries, 1)
|
||||||
assert.Equal(t, "./dlt/nyc_taxi_loader", p.Libraries[0].Notebook.Path)
|
assert.Equal(t, "./dlt/nyc_taxi_loader", p.Libraries[0].Notebook.Path)
|
||||||
assert.Equal(t, "nyc_taxi_production", p.Target)
|
assert.Equal(t, "nyc_taxi_production", p.Target)
|
||||||
|
|
||||||
j := b.Config.Resources.Jobs["pipeline_schedule"]
|
j := b.Config.Resources.Jobs["pipeline_schedule"]
|
||||||
assert.Equal(t, "job_and_pipeline/databricks.yml", filepath.ToSlash(j.ConfigFilePath))
|
|
||||||
assert.Equal(t, "Daily refresh of production pipeline", j.Name)
|
assert.Equal(t, "Daily refresh of production pipeline", j.Name)
|
||||||
require.Len(t, j.Tasks, 1)
|
require.Len(t, j.Tasks, 1)
|
||||||
assert.NotEmpty(t, j.Tasks[0].PipelineTask.PipelineId)
|
assert.NotEmpty(t, j.Tasks[0].PipelineTask.PipelineId)
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package config_tests
|
package config_tests
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"path/filepath"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/databricks/cli/bundle/config"
|
"github.com/databricks/cli/bundle/config"
|
||||||
|
@ -10,7 +9,6 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func assertExpected(t *testing.T, p *resources.ModelServingEndpoint) {
|
func assertExpected(t *testing.T, p *resources.ModelServingEndpoint) {
|
||||||
assert.Equal(t, "model_serving_endpoint/databricks.yml", filepath.ToSlash(p.ConfigFilePath))
|
|
||||||
assert.Equal(t, "model-name", p.Config.ServedModels[0].ModelName)
|
assert.Equal(t, "model-name", p.Config.ServedModels[0].ModelName)
|
||||||
assert.Equal(t, "1", p.Config.ServedModels[0].ModelVersion)
|
assert.Equal(t, "1", p.Config.ServedModels[0].ModelVersion)
|
||||||
assert.Equal(t, "model-name-1", p.Config.TrafficConfig.Routes[0].ServedModelName)
|
assert.Equal(t, "model-name-1", p.Config.TrafficConfig.Routes[0].ServedModelName)
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package config_tests
|
package config_tests
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"path/filepath"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/databricks/cli/bundle/config"
|
"github.com/databricks/cli/bundle/config"
|
||||||
|
@ -10,7 +9,6 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func assertExpectedModel(t *testing.T, p *resources.RegisteredModel) {
|
func assertExpectedModel(t *testing.T, p *resources.RegisteredModel) {
|
||||||
assert.Equal(t, "registered_model/databricks.yml", filepath.ToSlash(p.ConfigFilePath))
|
|
||||||
assert.Equal(t, "main", p.CatalogName)
|
assert.Equal(t, "main", p.CatalogName)
|
||||||
assert.Equal(t, "default", p.SchemaName)
|
assert.Equal(t, "default", p.SchemaName)
|
||||||
assert.Equal(t, "comment", p.Comment)
|
assert.Equal(t, "comment", p.Comment)
|
||||||
|
|
|
@ -1,12 +1,22 @@
|
||||||
package config_tests
|
package config_tests
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/databricks/cli/bundle"
|
||||||
|
"github.com/databricks/cli/bundle/config/validate"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestUndefinedJobLoadsWithError(t *testing.T) {
|
func TestUndefinedJobLoadsWithError(t *testing.T) {
|
||||||
_, diags := loadTargetWithDiags("./undefined_job", "default")
|
b := load(t, "./undefined_job")
|
||||||
|
diags := bundle.Apply(context.Background(), b, validate.AllResourcesHaveValues())
|
||||||
assert.ErrorContains(t, diags.Error(), "job undefined is not defined")
|
assert.ErrorContains(t, diags.Error(), "job undefined is not defined")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestUndefinedPipelineLoadsWithError(t *testing.T) {
|
||||||
|
b := load(t, "./undefined_pipeline")
|
||||||
|
diags := bundle.Apply(context.Background(), b, validate.AllResourcesHaveValues())
|
||||||
|
assert.ErrorContains(t, diags.Error(), "pipeline undefined is not defined")
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
bundle:
|
||||||
|
name: undefined-pipeline
|
||||||
|
|
||||||
|
resources:
|
||||||
|
pipelines:
|
||||||
|
undefined:
|
||||||
|
test:
|
||||||
|
name: "Test Pipeline"
|
|
@ -9,6 +9,12 @@ import (
|
||||||
"github.com/databricks/cli/libs/dyn/dynvar"
|
"github.com/databricks/cli/libs/dyn/dynvar"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Populate a destination typed value from a source dynamic value.
|
||||||
|
//
|
||||||
|
// At any point while walking the destination type tree using
|
||||||
|
// reflection, if this function sees an exported field with type dyn.Value it
|
||||||
|
// will populate that field with the appropriate source dynamic value.
|
||||||
|
// see PR: https://github.com/databricks/cli/pull/1010
|
||||||
func ToTyped(dst any, src dyn.Value) error {
|
func ToTyped(dst any, src dyn.Value) error {
|
||||||
dstv := reflect.ValueOf(dst)
|
dstv := reflect.ValueOf(dst)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue