Add command that writes the materialized bundle configuration to stdout (#95)

Used to inspect the bundle configuration after loading and merging all
files.

Once we add variable interpolation this command could show the result
after interpolation as well.

Each of the mutations to this configuration is observable, so we could
add a mode that writes each of the intermediate versions to disk for
even more fine grained introspection.
This commit is contained in:
Pieter Noordhuis 2022-11-21 15:39:53 +01:00 committed by GitHub
parent 195eb7f0f9
commit 3b351d3b00
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 173 additions and 0 deletions

View File

@ -1,15 +1,21 @@
package bundle package bundle
import ( import (
"context"
"path/filepath" "path/filepath"
"github.com/databricks/bricks/bundle/config" "github.com/databricks/bricks/bundle/config"
"github.com/databricks/bricks/bundle/config/mutator"
) )
type Bundle struct { type Bundle struct {
Config config.Root Config config.Root
} }
func (b *Bundle) MutateForEnvironment(env string) error {
return mutator.Apply(&b.Config, mutator.DefaultMutatorsForEnvironment(env))
}
func Load(path string) (*Bundle, error) { func Load(path string) (*Bundle, error) {
bundle := &Bundle{ bundle := &Bundle{
Config: config.Root{ Config: config.Root{
@ -22,3 +28,26 @@ func Load(path string) (*Bundle, error) {
} }
return bundle, nil return bundle, nil
} }
func LoadFromRoot() (*Bundle, error) {
root, err := getRoot()
if err != nil {
return nil, err
}
return Load(root)
}
func ConfigureForEnvironment(ctx context.Context, env string) (context.Context, error) {
b, err := LoadFromRoot()
if err != nil {
return nil, err
}
err = b.MutateForEnvironment(env)
if err != nil {
return nil, err
}
return Context(ctx, b), nil
}

24
bundle/context.go Normal file
View File

@ -0,0 +1,24 @@
package bundle
import (
"context"
)
// Placeholder to use as unique key in context.Context.
var bundleKey int
// Context stores the specified bundle on a new context.
// The bundle is available through the `Get()` function.
func Context(ctx context.Context, b *Bundle) context.Context {
return context.WithValue(ctx, &bundleKey, b)
}
// Get returns the bundle as configured on the context.
// It panics if it isn't configured.
func Get(ctx context.Context) *Bundle {
bundle, ok := ctx.Value(&bundleKey).(*Bundle)
if !ok {
panic("context not configured with bundle")
}
return bundle
}

24
bundle/context_test.go Normal file
View File

@ -0,0 +1,24 @@
package bundle
import (
"context"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestGetPanics(t *testing.T) {
defer func() {
r := recover()
require.NotNil(t, r, "The function did not panic")
assert.Equal(t, r, "context not configured with bundle")
}()
Get(context.Background())
}
func TestGetSuccess(t *testing.T) {
ctx := Context(context.Background(), &Bundle{})
require.NotNil(t, Get(ctx))
}

31
cmd/bundle/environment.go Normal file
View File

@ -0,0 +1,31 @@
package bundle
import (
"os"
"github.com/spf13/cobra"
)
const envName = "DATABRICKS_BUNDLE_ENV"
const defaultEnvironment = "default"
// getEnvironment returns the name of the environment to operate in.
func getEnvironment(cmd *cobra.Command) (value string) {
// The command line flag takes precedence.
flag := cmd.Flag("environment")
if flag != nil {
value = flag.Value.String()
if value != "" {
return
}
}
// If it's not set, use the environment variable.
value = os.Getenv(envName)
if value != "" {
return
}
return defaultEnvironment
}

36
cmd/bundle/root.go Normal file
View File

@ -0,0 +1,36 @@
package bundle
import (
"github.com/databricks/bricks/bundle"
"github.com/databricks/bricks/cmd/root"
"github.com/spf13/cobra"
)
// rootCmd represents the root command for the bundle subcommand.
var rootCmd = &cobra.Command{
Use: "bundle",
Short: "Databricks Application Bundles",
}
// ConfigureBundle loads the bundle configuration
// and configures it on the command's context.
func ConfigureBundle(cmd *cobra.Command, args []string) error {
ctx, err := bundle.ConfigureForEnvironment(cmd.Context(), getEnvironment(cmd))
if err != nil {
return err
}
cmd.SetContext(ctx)
return nil
}
func AddCommand(cmd *cobra.Command) {
rootCmd.AddCommand(cmd)
}
func init() {
// All bundle commands take an "environment" parameter.
rootCmd.PersistentFlags().StringP("environment", "e", "", "Environment to use")
// Add to top level root.
root.RootCmd.AddCommand(rootCmd)
}

28
cmd/bundle/validate.go Normal file
View File

@ -0,0 +1,28 @@
package bundle
import (
"encoding/json"
"github.com/databricks/bricks/bundle"
"github.com/spf13/cobra"
)
var validate = &cobra.Command{
Use: "validate",
Short: "Validate configuration",
PreRunE: ConfigureBundle,
RunE: func(cmd *cobra.Command, args []string) error {
b := bundle.Get(cmd.Context())
buf, err := json.MarshalIndent(b.Config, "", " ")
if err != nil {
return err
}
cmd.OutOrStdout().Write(buf)
return nil
},
}
func init() {
AddCommand(validate)
}

View File

@ -2,6 +2,7 @@ package main
import ( import (
_ "github.com/databricks/bricks/cmd/api" _ "github.com/databricks/bricks/cmd/api"
_ "github.com/databricks/bricks/cmd/bundle"
_ "github.com/databricks/bricks/cmd/configure" _ "github.com/databricks/bricks/cmd/configure"
_ "github.com/databricks/bricks/cmd/fs" _ "github.com/databricks/bricks/cmd/fs"
_ "github.com/databricks/bricks/cmd/init" _ "github.com/databricks/bricks/cmd/init"