2023-01-20 15:55:44 +00:00
|
|
|
package schema
|
|
|
|
|
|
|
|
import (
|
2023-01-23 14:00:11 +00:00
|
|
|
_ "embed"
|
2023-03-15 02:18:51 +00:00
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
2023-01-20 15:55:44 +00:00
|
|
|
"os"
|
2023-03-15 02:18:51 +00:00
|
|
|
"reflect"
|
2023-01-20 15:55:44 +00:00
|
|
|
|
2023-05-16 16:35:39 +00:00
|
|
|
"github.com/databricks/cli/bundle/config"
|
2023-08-01 14:09:27 +00:00
|
|
|
"github.com/databricks/cli/libs/jsonschema"
|
2023-03-15 02:18:51 +00:00
|
|
|
"github.com/databricks/databricks-sdk-go/openapi"
|
2023-01-20 15:55:44 +00:00
|
|
|
)
|
|
|
|
|
2023-03-15 02:18:51 +00:00
|
|
|
// A subset of Schema struct
|
2023-01-20 15:55:44 +00:00
|
|
|
type Docs struct {
|
2023-03-15 02:18:51 +00:00
|
|
|
Description string `json:"description"`
|
|
|
|
Properties map[string]*Docs `json:"properties,omitempty"`
|
|
|
|
Items *Docs `json:"items,omitempty"`
|
|
|
|
AdditionalProperties *Docs `json:"additionalproperties,omitempty"`
|
2023-01-20 15:55:44 +00:00
|
|
|
}
|
|
|
|
|
2023-03-15 02:18:51 +00:00
|
|
|
//go:embed docs/bundle_descriptions.json
|
|
|
|
var bundleDocs []byte
|
|
|
|
|
|
|
|
func BundleDocs(openapiSpecPath string) (*Docs, error) {
|
|
|
|
docs, err := initializeBundleDocs()
|
2023-01-20 15:55:44 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2023-03-15 02:18:51 +00:00
|
|
|
if openapiSpecPath != "" {
|
|
|
|
openapiSpec, err := os.ReadFile(openapiSpecPath)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
spec := &openapi.Specification{}
|
|
|
|
err = json.Unmarshal(openapiSpec, spec)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
openapiReader := &OpenapiReader{
|
|
|
|
OpenapiSpec: spec,
|
2023-08-01 14:09:27 +00:00
|
|
|
Memo: make(map[string]*jsonschema.Schema),
|
2023-03-15 02:18:51 +00:00
|
|
|
}
|
|
|
|
resourcesDocs, err := openapiReader.ResourcesDocs()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
resourceSchema, err := New(reflect.TypeOf(config.Resources{}), resourcesDocs)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
docs.Properties["resources"] = schemaToDocs(resourceSchema)
|
2023-01-20 15:55:44 +00:00
|
|
|
}
|
2023-08-17 15:22:32 +00:00
|
|
|
docs.refreshTargetsDocs()
|
2023-03-15 02:18:51 +00:00
|
|
|
return docs, nil
|
2023-01-20 15:55:44 +00:00
|
|
|
}
|
2023-01-23 14:00:11 +00:00
|
|
|
|
2023-08-17 15:22:32 +00:00
|
|
|
func (docs *Docs) refreshTargetsDocs() error {
|
|
|
|
targetsDocs, ok := docs.Properties["targets"]
|
|
|
|
if !ok || targetsDocs.AdditionalProperties == nil ||
|
|
|
|
targetsDocs.AdditionalProperties.Properties == nil {
|
|
|
|
return fmt.Errorf("invalid targets descriptions")
|
2023-03-15 02:18:51 +00:00
|
|
|
}
|
2023-08-17 15:22:32 +00:00
|
|
|
targetProperties := targetsDocs.AdditionalProperties.Properties
|
2023-03-15 02:18:51 +00:00
|
|
|
propertiesToCopy := []string{"artifacts", "bundle", "resources", "workspace"}
|
|
|
|
for _, p := range propertiesToCopy {
|
2023-08-17 15:22:32 +00:00
|
|
|
targetProperties[p] = docs.Properties[p]
|
2023-03-15 02:18:51 +00:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
2023-01-23 14:00:11 +00:00
|
|
|
|
2023-03-15 02:18:51 +00:00
|
|
|
func initializeBundleDocs() (*Docs, error) {
|
|
|
|
// load embedded descriptions
|
|
|
|
embedded := Docs{}
|
|
|
|
err := json.Unmarshal(bundleDocs, &embedded)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
// generate schema with the embedded descriptions
|
|
|
|
schema, err := New(reflect.TypeOf(config.Root{}), &embedded)
|
2023-01-23 14:00:11 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2023-03-15 02:18:51 +00:00
|
|
|
// converting the schema back to docs. This creates empty descriptions
|
|
|
|
// for any properties that were missing in the embedded descriptions
|
|
|
|
docs := schemaToDocs(schema)
|
|
|
|
return docs, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// *Docs are a subset of *Schema, this function selects that subset
|
2023-08-01 14:09:27 +00:00
|
|
|
func schemaToDocs(jsonSchema *jsonschema.Schema) *Docs {
|
2023-03-15 02:18:51 +00:00
|
|
|
// terminate recursion if schema is nil
|
2023-08-01 14:09:27 +00:00
|
|
|
if jsonSchema == nil {
|
2023-03-15 02:18:51 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
docs := &Docs{
|
2023-08-01 14:09:27 +00:00
|
|
|
Description: jsonSchema.Description,
|
2023-03-15 02:18:51 +00:00
|
|
|
}
|
2023-08-01 14:09:27 +00:00
|
|
|
if len(jsonSchema.Properties) > 0 {
|
2023-03-15 02:18:51 +00:00
|
|
|
docs.Properties = make(map[string]*Docs)
|
|
|
|
}
|
2023-08-01 14:09:27 +00:00
|
|
|
for k, v := range jsonSchema.Properties {
|
2023-03-15 02:18:51 +00:00
|
|
|
docs.Properties[k] = schemaToDocs(v)
|
|
|
|
}
|
2023-08-01 14:09:27 +00:00
|
|
|
docs.Items = schemaToDocs(jsonSchema.Items)
|
|
|
|
if additionalProperties, ok := jsonSchema.AdditionalProperties.(*jsonschema.Schema); ok {
|
2023-03-15 02:18:51 +00:00
|
|
|
docs.AdditionalProperties = schemaToDocs(additionalProperties)
|
|
|
|
}
|
|
|
|
return docs
|
2023-01-23 14:00:11 +00:00
|
|
|
}
|