diff --git a/src/cmd/cli/command/color.go b/src/cmd/cli/command/color.go index 5cd9ea0ab..108ef54a7 100644 --- a/src/cmd/cli/command/color.go +++ b/src/cmd/cli/command/color.go @@ -32,7 +32,7 @@ func (c *ColorMode) Set(value string) error { return nil } } - return fmt.Errorf("color mode not one of %v", allColorModes) + return fmt.Errorf("invalid color: %q, not one of %v", value, allColorModes) } func (c ColorMode) Type() string { diff --git a/src/cmd/cli/command/session.go b/src/cmd/cli/command/session.go index 2362b9748..a087fef07 100644 --- a/src/cmd/cli/command/session.go +++ b/src/cmd/cli/command/session.go @@ -51,9 +51,7 @@ func newCommandSessionWithOpts(cmd *cobra.Command, opts commandSessionOpts) (*se } func newSessionLoaderOptionsForCommand(cmd *cobra.Command) session.SessionLoaderOptions { - stack, _ := cmd.Flags().GetString("stack") configPaths, _ := cmd.Flags().GetStringArray("file") - provider, _ := cmd.Flag("provider").Value.(*client.ProviderID) projectName, _ := cmd.Flags().GetString("project-name") // Avoid common mistakes @@ -77,9 +75,8 @@ func newSessionLoaderOptionsForCommand(cmd *cobra.Command) session.SessionLoader ComposeFilePaths: configPaths, ProjectName: projectName, GetStackOpts: stacks.GetStackOpts{ - ProviderID: *provider, Interactive: !global.NonInteractive, - Stack: stack, + Default: global.Stack, }, } } diff --git a/src/pkg/session/session.go b/src/pkg/session/session.go index 6268227c9..238375438 100644 --- a/src/pkg/session/session.go +++ b/src/pkg/session/session.go @@ -68,13 +68,6 @@ func (sl *SessionLoader) LoadSession(ctx context.Context) (*Session, error) { } func (sl *SessionLoader) loadStack(ctx context.Context) (*stacks.Parameters, string, error) { - if sl.sm == nil { - return &stacks.Parameters{ - Name: stacks.DefaultBeta, - Provider: sl.opts.ProviderID, - }, "no stack manager available", nil - } - stack, whence, err := sl.sm.GetStack(ctx, sl.opts.GetStackOpts) if err != nil { return nil, whence, err diff --git a/src/pkg/session/session_test.go b/src/pkg/session/session_test.go index 47afa6738..ef57ee4ca 100644 --- a/src/pkg/session/session_test.go +++ b/src/pkg/session/session_test.go @@ -91,7 +91,9 @@ func TestLoadSession(t *testing.T) { name: "specified stack", options: SessionLoaderOptions{ GetStackOpts: stacks.GetStackOpts{ - Stack: "existingstack", + Default: stacks.Parameters{ + Name: "existingstack", + }, }, }, existingStack: &stacks.Parameters{ @@ -122,9 +124,9 @@ func TestLoadSession(t *testing.T) { sm := &mockStacksManager{} if tt.existingStack == nil { - if tt.options.GetStackOpts.Stack != "" { + if tt.options.Default.Name != "" { // For specified non-existing stack, return ErrNotExist - sm.On("GetStack", ctx, mock.Anything).Maybe().Return(nil, "", &stacks.ErrNotExist{StackName: tt.options.GetStackOpts.Stack}) + sm.On("GetStack", ctx, mock.Anything).Maybe().Return(nil, "", &stacks.ErrNotExist{StackName: tt.options.Default.Name}) } else if tt.getStackError != nil { sm.On("GetStack", ctx, mock.Anything).Maybe().Return(nil, "", tt.getStackError) } @@ -149,11 +151,11 @@ func TestLoadSession(t *testing.T) { assert.NotNil(t, session.Loader) assert.NotNil(t, session.Provider) - if tt.options.ProviderID == client.ProviderAWS { + if tt.options.Default.Provider == client.ProviderAWS { _, ok := session.Provider.(*aws.ByocAws) assert.True(t, ok) } - if tt.options.ProviderID == client.ProviderGCP { + if tt.options.Default.Provider == client.ProviderGCP { _, ok := session.Provider.(*gcp.ByocGcp) assert.True(t, ok) } @@ -175,18 +177,3 @@ func TestLoadSession(t *testing.T) { }) } } - -func TestLoadSession_NoStackManager(t *testing.T) { - ctx := t.Context() - - options := SessionLoaderOptions{ - GetStackOpts: stacks.GetStackOpts{ - ProviderID: client.ProviderDefang, - }, - } - - loader := NewSessionLoader(client.MockFabricClient{}, nil, options) - session, err := loader.LoadSession(ctx) - require.NoError(t, err) - assert.NotNil(t, session) -} diff --git a/src/pkg/stacks/manager.go b/src/pkg/stacks/manager.go index 3d98ce857..d7c2c246c 100644 --- a/src/pkg/stacks/manager.go +++ b/src/pkg/stacks/manager.go @@ -201,47 +201,43 @@ func (sm *manager) Create(params Parameters) (string, error) { } type GetStackOpts struct { - ProviderID client.ProviderID - Stack string - Interactive bool - AllowStackCreation bool + Default Parameters + Interactive bool + SelectStackOptions } -func (sl *manager) GetStack(ctx context.Context, opts GetStackOpts) (*Parameters, string, error) { +func (sm *manager) GetStack(ctx context.Context, opts GetStackOpts) (*Parameters, string, error) { // use --stack if available - if opts.Stack != "" { - return sl.getSpecifiedStack(ctx, opts.Stack) + if opts.Default.Name != "" { + return sm.getSpecifiedStack(ctx, opts.Default.Name) // TODO: merge with opts.Default? } // use --provider if available - if opts.ProviderID != client.ProviderAuto && opts.ProviderID != "" { + if opts.Default.Provider != client.ProviderAuto && opts.Default.Provider != "" { whence := "DEFANG_PROVIDER" - envProvider := os.Getenv("DEFANG_PROVIDER") - if envProvider != opts.ProviderID.String() { + var fromEnv client.ProviderID + if err := fromEnv.Set(os.Getenv("DEFANG_PROVIDER")); err == nil && fromEnv != opts.Default.Provider { whence = "--provider flag" } - return &Parameters{ - Name: DefaultBeta, - Provider: opts.ProviderID, - }, whence, nil + fallback := opts.Default + fallback.Name = DefaultBeta + return &fallback, whence, nil } // fallback to interactive if opts.Interactive { - return sl.getStackInteractively(ctx, opts) + return sm.getStackInteractively(ctx, opts) // TODO: merge with opts.Default? } - // fallback to default stack - stack, whence, err := sl.getDefaultStack(ctx) + // fallback to default stack for project + stack, whence, err := sm.getDefaultStack(ctx) if err != nil { if !errors.Is(err, ErrDefaultStackNotSet) { return nil, "", err } - whence := "fallback stack" - // fallback to fallback - stack = &Parameters{ - Name: DefaultBeta, - Provider: client.ProviderDefang, - } - return stack, whence, nil + // no default stack for project; use fallback + whence := "fallback stack" + fallback := opts.Default + fallback.Name = DefaultBeta + return &fallback, whence, nil } return stack, whence, nil @@ -289,9 +285,8 @@ func (sm *manager) getSpecifiedStack(ctx context.Context, name string) (*Paramet func (sm *manager) getStackInteractively(ctx context.Context, opts GetStackOpts) (*Parameters, string, error) { stackSelector := NewSelector(sm.ec, sm) - stack, err := stackSelector.SelectStack(ctx, SelectStackOptions{ - AllowStackCreation: opts.AllowStackCreation, - }) + // TODO: pass fallback stack to selector wizard for pre-filling + stack, err := stackSelector.SelectStack(ctx, opts.SelectStackOptions) if err != nil { return nil, "", fmt.Errorf("failed to select stack: %w", err) } diff --git a/src/pkg/stacks/manager_test.go b/src/pkg/stacks/manager_test.go index 347ddcaf3..366a7b7c1 100644 --- a/src/pkg/stacks/manager_test.go +++ b/src/pkg/stacks/manager_test.go @@ -664,7 +664,7 @@ func TestGetStack(t *testing.T) { name: "stack specified but not found", projectName: "foo", options: GetStackOpts{ - Stack: "missingstack", + Default: Parameters{Name: "missingstack"}, }, expectedError: "stack \"missingstack\" does not exist", expectedEnv: map[string]string{}, @@ -673,7 +673,7 @@ func TestGetStack(t *testing.T) { name: "local stack specified", projectName: "foo", options: GetStackOpts{ - Stack: "localstack", + Default: Parameters{Name: "localstack"}, }, localStack: &Parameters{ Name: "localstack", @@ -698,7 +698,7 @@ func TestGetStack(t *testing.T) { name: "remote stack specified", projectName: "foo", options: GetStackOpts{ - Stack: "remotestack", + Default: Parameters{Name: "remotestack"}, }, remoteStack: &Parameters{ Name: "remotestack", @@ -725,7 +725,7 @@ func TestGetStack(t *testing.T) { name: "local and remote stack", projectName: "foo", options: GetStackOpts{ - Stack: "bothstack", + Default: Parameters{Name: "bothstack"}, }, localStack: &Parameters{ Name: "bothstack", @@ -767,8 +767,10 @@ func TestGetStack(t *testing.T) { name: "interactive selection", projectName: "foo", options: GetStackOpts{ - Interactive: true, - AllowStackCreation: true, + Interactive: true, + SelectStackOptions: SelectStackOptions{ + AllowStackCreation: true, + }, }, remoteStack: &Parameters{ Name: "existingstack", @@ -784,9 +786,14 @@ func TestGetStack(t *testing.T) { "stack": "existingstack", }, expectedStack: &Parameters{ - Name: "existingstack", - Provider: client.ProviderGCP, - Variables: map[string]string{}, + Name: "existingstack", + Provider: client.ProviderGCP, + Region: "us-central1", + Variables: map[string]string{ + "DEFANG_PROVIDER": "gcp", + "GCP_PROJECT": "existing-gcp-project", + "FOO": "existing-bar", + }, }, expectedEnv: map[string]string{ "DEFANG_PROVIDER": "gcp", @@ -798,7 +805,7 @@ func TestGetStack(t *testing.T) { name: "stack with compose vars updates loader", projectName: "foo", options: GetStackOpts{ - Stack: "composestack", + Default: Parameters{Name: "composestack"}, }, localStack: &Parameters{ Name: "composestack",