mirror of https://github.com/databricks/cli.git
Add environments to project configuration (#68)
This commit is contained in:
parent
6bcb33bf07
commit
6258a1637d
|
@ -29,7 +29,14 @@ func loadCliProfiles() (profiles []prompt.Answer, err error) {
|
||||||
Value: v.Name(),
|
Value: v.Name(),
|
||||||
Details: fmt.Sprintf(`Connecting to "%s" workspace`, host),
|
Details: fmt.Sprintf(`Connecting to "%s" workspace`, host),
|
||||||
Callback: func(ans prompt.Answer, config *project.Config, _ prompt.Results) {
|
Callback: func(ans prompt.Answer, config *project.Config, _ prompt.Results) {
|
||||||
config.Profile = ans.Value
|
if config.Environments == nil {
|
||||||
|
config.Environments = make(map[string]project.Environment)
|
||||||
|
}
|
||||||
|
config.Environments[project.DefaultEnvironment] = project.Environment{
|
||||||
|
Workspace: project.Workspace{
|
||||||
|
Profile: ans.Value,
|
||||||
|
},
|
||||||
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,6 +50,13 @@ type Config struct {
|
||||||
// created by administrator users or admin-level automation, like Terraform
|
// created by administrator users or admin-level automation, like Terraform
|
||||||
// and/or SCIM provisioning.
|
// and/or SCIM provisioning.
|
||||||
Assertions *Assertions `json:"assertions,omitempty"`
|
Assertions *Assertions `json:"assertions,omitempty"`
|
||||||
|
|
||||||
|
// Environments contain this project's defined environments.
|
||||||
|
// They can be used to differentiate settings and resources between
|
||||||
|
// development, staging, production, etc.
|
||||||
|
// If not specified, the code below initializes this field with a
|
||||||
|
// single default-initialized environment called "development".
|
||||||
|
Environments map[string]Environment `json:"environments"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c Config) IsDevClusterDefined() bool {
|
func (c Config) IsDevClusterDefined() bool {
|
||||||
|
@ -83,7 +90,7 @@ func loadProjectConf(root string) (c Config, err error) {
|
||||||
baseDir := filepath.Base(root)
|
baseDir := filepath.Base(root)
|
||||||
// If bricks config file is missing we assume the project root dir name
|
// If bricks config file is missing we assume the project root dir name
|
||||||
// as the name of the project
|
// as the name of the project
|
||||||
return Config{Name: baseDir}, nil
|
return validateAndApplyProjectDefaults(Config{Name: baseDir})
|
||||||
}
|
}
|
||||||
|
|
||||||
config, err := os.Open(configFilePath)
|
config, err := os.Open(configFilePath)
|
||||||
|
@ -102,6 +109,11 @@ func loadProjectConf(root string) (c Config, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateAndApplyProjectDefaults(c Config) (Config, error) {
|
func validateAndApplyProjectDefaults(c Config) (Config, error) {
|
||||||
|
// If no environments are specified, define default environment under default name.
|
||||||
|
if c.Environments == nil {
|
||||||
|
c.Environments = make(map[string]Environment)
|
||||||
|
c.Environments[DefaultEnvironment] = Environment{}
|
||||||
|
}
|
||||||
// defaultCluster := clusters.ClusterInfo{
|
// defaultCluster := clusters.ClusterInfo{
|
||||||
// NodeTypeID: "smallest",
|
// NodeTypeID: "smallest",
|
||||||
// SparkVersion: "latest",
|
// SparkVersion: "latest",
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
package project
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
const bricksEnv = "BRICKS_ENV"
|
||||||
|
|
||||||
|
const DefaultEnvironment = "development"
|
||||||
|
|
||||||
|
// Workspace defines configurables at the workspace level.
|
||||||
|
type Workspace struct {
|
||||||
|
Profile string `json:"profile,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Environment defines all configurables for a single environment.
|
||||||
|
type Environment struct {
|
||||||
|
Workspace Workspace `json:"workspace"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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(bricksEnv)
|
||||||
|
if value != "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return DefaultEnvironment
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
package project
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestEnvironmentFromCommand(t *testing.T) {
|
||||||
|
var cmd cobra.Command
|
||||||
|
cmd.Flags().String("environment", "", "specify environment")
|
||||||
|
cmd.Flags().Set("environment", "env-from-arg")
|
||||||
|
t.Setenv(bricksEnv, "")
|
||||||
|
|
||||||
|
value := getEnvironment(&cmd)
|
||||||
|
assert.Equal(t, "env-from-arg", value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEnvironmentFromEnvironment(t *testing.T) {
|
||||||
|
var cmd cobra.Command
|
||||||
|
cmd.Flags().String("environment", "", "specify environment")
|
||||||
|
cmd.Flags().Set("environment", "")
|
||||||
|
t.Setenv(bricksEnv, "env-from-env")
|
||||||
|
|
||||||
|
value := getEnvironment(&cmd)
|
||||||
|
assert.Equal(t, "env-from-env", value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEnvironmentDefault(t *testing.T) {
|
||||||
|
var cmd cobra.Command
|
||||||
|
cmd.Flags().String("environment", "", "specify environment")
|
||||||
|
cmd.Flags().Set("environment", "")
|
||||||
|
t.Setenv(bricksEnv, "")
|
||||||
|
|
||||||
|
value := getEnvironment(&cmd)
|
||||||
|
assert.Equal(t, DefaultEnvironment, value)
|
||||||
|
}
|
|
@ -17,10 +17,12 @@ type project struct {
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
|
|
||||||
root string
|
root string
|
||||||
|
env string
|
||||||
|
|
||||||
config *Config
|
config *Config
|
||||||
wsc *workspaces.WorkspacesClient
|
environment *Environment
|
||||||
me *scim.User
|
wsc *workspaces.WorkspacesClient
|
||||||
|
me *scim.User
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure is used as a PreRunE function for all commands that
|
// Configure is used as a PreRunE function for all commands that
|
||||||
|
@ -32,7 +34,7 @@ func Configure(cmd *cobra.Command, args []string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, err := Initialize(cmd.Context(), root)
|
ctx, err := Initialize(cmd.Context(), root, getEnvironment(cmd))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -44,33 +46,46 @@ func Configure(cmd *cobra.Command, args []string) error {
|
||||||
// Placeholder to use as unique key in context.Context.
|
// Placeholder to use as unique key in context.Context.
|
||||||
var projectKey int
|
var projectKey int
|
||||||
|
|
||||||
// Initialize loads a project configuration given a root.
|
// Initialize loads a project configuration given a root and environment.
|
||||||
// It stores the project on a new context.
|
// It stores the project on a new context.
|
||||||
// The project is available through the `Get()` function.
|
// The project is available through the `Get()` function.
|
||||||
func Initialize(ctx context.Context, root string) (context.Context, error) {
|
func Initialize(ctx context.Context, root, env string) (context.Context, error) {
|
||||||
config, err := loadProjectConf(root)
|
config, err := loadProjectConf(root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Confirm that the specified environment is valid.
|
||||||
|
environment, ok := config.Environments[env]
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("environment [%s] not defined", env)
|
||||||
|
}
|
||||||
|
|
||||||
p := project{
|
p := project{
|
||||||
root: root,
|
root: root,
|
||||||
config: &config,
|
env: env,
|
||||||
}
|
|
||||||
|
config: &config,
|
||||||
if config.Profile == "" {
|
environment: &environment,
|
||||||
// Bricks config doesn't define the profile to use, so go sdk will figure
|
|
||||||
// out the auth credentials based on the enviroment.
|
|
||||||
// eg. DATABRICKS_CONFIG_PROFILE can be used to select which profile to use or
|
|
||||||
// DATABRICKS_HOST and DATABRICKS_TOKEN can be used to set the workspace auth creds
|
|
||||||
p.wsc = workspaces.New()
|
|
||||||
} else {
|
|
||||||
p.wsc = workspaces.New(&databricks.Config{Profile: config.Profile})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p.initializeWorkspacesClient(ctx)
|
||||||
return context.WithValue(ctx, &projectKey, &p), nil
|
return context.WithValue(ctx, &projectKey, &p), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *project) initializeWorkspacesClient(ctx context.Context) {
|
||||||
|
var config databricks.Config
|
||||||
|
|
||||||
|
// If the config specifies a profile, or other authentication related properties,
|
||||||
|
// pass them along to the SDK here. If nothing is defined, the SDK will figure
|
||||||
|
// out which autentication mechanism to use using enviroment variables.
|
||||||
|
if p.environment.Workspace.Profile != "" {
|
||||||
|
config.Profile = p.environment.Workspace.Profile
|
||||||
|
}
|
||||||
|
|
||||||
|
p.wsc = workspaces.New(&config)
|
||||||
|
}
|
||||||
|
|
||||||
// Get returns the project as configured on the context.
|
// Get returns the project as configured on the context.
|
||||||
// It panics if it isn't configured.
|
// It panics if it isn't configured.
|
||||||
func Get(ctx context.Context) *project {
|
func Get(ctx context.Context) *project {
|
||||||
|
@ -90,6 +105,14 @@ func (p *project) Root() string {
|
||||||
return p.root
|
return p.root
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *project) Config() Config {
|
||||||
|
return *p.config
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *project) Environment() Environment {
|
||||||
|
return *p.environment
|
||||||
|
}
|
||||||
|
|
||||||
func (p *project) Me() (*scim.User, error) {
|
func (p *project) Me() (*scim.User, error) {
|
||||||
p.mu.Lock()
|
p.mu.Lock()
|
||||||
defer p.mu.Unlock()
|
defer p.mu.Unlock()
|
||||||
|
|
|
@ -9,7 +9,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestProjectInitialize(t *testing.T) {
|
func TestProjectInitialize(t *testing.T) {
|
||||||
ctx, err := Initialize(context.Background(), "./testdata")
|
ctx, err := Initialize(context.Background(), "./testdata", DefaultEnvironment)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Equal(t, Get(ctx).config.Name, "dev")
|
assert.Equal(t, Get(ctx).config.Name, "dev")
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue