Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions cmd/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,10 @@ var initCmd = &cobra.Command{
return err
}

if err := rt.HandleSessionReset(); err != nil {
return fmt.Errorf("failed to handle session reset: %w", err)
}

if err := proj.Initialize(initReset); err != nil {
return err
}
Expand Down
58 changes: 58 additions & 0 deletions cmd/init_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1060,4 +1060,62 @@ func TestInitCmd(t *testing.T) {
t.Errorf("Expected error message to contain 'failed to add current directory to trusted file', got: %v", err)
}
})

t.Run("CallsHandleSessionReset", func(t *testing.T) {
// Given a temporary directory with mocked dependencies
mocks := setupInitTest(t)

// And tracking whether Shell.CheckResetFlags is called (which HandleSessionReset calls)
var checkResetFlagsCalled bool
mocks.Shell.Shell.CheckResetFlagsFunc = func() (bool, error) {
checkResetFlagsCalled = true
return false, nil
}

// When executing the init command
cmd := createTestInitCmd()
ctx := context.WithValue(context.Background(), runtimeOverridesKey, mocks.Runtime)
cmd.SetArgs([]string{})
cmd.SetContext(ctx)
err := cmd.Execute()

// Then no error should occur
if err != nil {
t.Errorf("Expected success, got error: %v", err)
}

// And CheckResetFlags should have been called (indicating HandleSessionReset was called)
if !checkResetFlagsCalled {
t.Error("Expected CheckResetFlags to be called (via HandleSessionReset), but it was not")
}
})

t.Run("HandlesHandleSessionResetError", func(t *testing.T) {
// Given a temporary directory with mocked dependencies
mocks := setupInitTest(t)

// And CheckResetFlags returns an error (which HandleSessionReset will propagate)
expectedError := fmt.Errorf("failed to check reset flags")
mocks.Shell.Shell.CheckResetFlagsFunc = func() (bool, error) {
return false, expectedError
}

// When executing the init command
cmd := createTestInitCmd()
ctx := context.WithValue(context.Background(), runtimeOverridesKey, mocks.Runtime)
cmd.SetArgs([]string{})
cmd.SetContext(ctx)
err := cmd.Execute()

// Then an error should occur
if err == nil {
t.Error("Expected error when HandleSessionReset fails, got nil")
return
}

// And the error should contain the expected message
if !strings.Contains(err.Error(), "failed to handle session reset") {
t.Errorf("Expected error message to contain 'failed to handle session reset', got: %v", err)
}
})
}
24 changes: 12 additions & 12 deletions pkg/project/project.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,6 @@ func NewProject(contextName string, opts ...*Project) (*Project, error) {
rt.ContextName = contextName
rt.ConfigRoot = filepath.Join(rt.ProjectRoot, "contexts", contextName)

if err := rt.ApplyConfigDefaults(); err != nil {
return nil, err
}

var comp *composer.Composer
if overrides != nil && overrides.Composer != nil {
comp = overrides.Composer
Expand All @@ -80,7 +76,7 @@ func NewProject(contextName string, opts ...*Project) (*Project, error) {
}

var ws *workstation.Workstation
if rt.ConfigHandler.IsDevMode(rt.ContextName) {
if rt.ConfigHandler.IsDevMode(contextName) {
if overrides != nil && overrides.Workstation != nil {
ws = overrides.Workstation
} else {
Expand Down Expand Up @@ -119,6 +115,10 @@ func (p *Project) Configure(flagOverrides map[string]any) error {
}
}

if err := p.Runtime.ApplyConfigDefaults(flagOverrides); err != nil {
return fmt.Errorf("failed to apply config defaults: %w", err)
}

providerOverride := ""
if flagOverrides != nil {
if prov, ok := flagOverrides["provider"].(string); ok {
Expand Down Expand Up @@ -148,14 +148,14 @@ func (p *Project) Configure(flagOverrides map[string]any) error {
}

// Initialize runs the complete initialization sequence for the project.
// It initializes network, prepares context, generates infrastructure, prepares tools,
// and bootstraps the environment. The overwrite parameter controls whether
// infrastructure generation should overwrite existing files. Returns an error
// if any step fails.
// It prepares the workstation (creates services and assigns IPs), prepares context,
// generates infrastructure, prepares tools, and bootstraps the environment.
// The overwrite parameter controls whether infrastructure generation should overwrite
// existing files. Returns an error if any step fails.
func (p *Project) Initialize(overwrite bool) error {
if p.Workstation != nil && p.Workstation.NetworkManager != nil {
if err := p.Workstation.NetworkManager.AssignIPs(p.Workstation.Services); err != nil {
return fmt.Errorf("failed to assign IPs to network manager: %w", err)
if p.Workstation != nil {
if err := p.Workstation.Prepare(); err != nil {
return fmt.Errorf("failed to prepare workstation: %w", err)
}
}

Expand Down
150 changes: 97 additions & 53 deletions pkg/project/project_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"strings"
"testing"

v1alpha1 "github.com/windsorcli/cli/api/v1alpha1"
"github.com/windsorcli/cli/pkg/composer"
"github.com/windsorcli/cli/pkg/composer/blueprint"
"github.com/windsorcli/cli/pkg/provisioner"
Expand Down Expand Up @@ -277,35 +278,6 @@ func TestNewProject(t *testing.T) {
}
})

t.Run("ErrorOnApplyConfigDefaultsFailure", func(t *testing.T) {
mocks := setupProjectMocks(t)
mockConfig := mocks.ConfigHandler.(*config.MockConfigHandler)
mockConfig.IsLoadedFunc = func() bool {
return false
}
mockConfig.IsDevModeFunc = func(contextName string) bool {
return true
}
mockConfig.GetStringFunc = func(key string, defaultValue ...string) string {
return ""
}
mockConfig.SetFunc = func(key string, value any) error {
if key == "dev" {
return fmt.Errorf("set dev failed")
}
return nil
}

proj, err := NewProject("test-context", &Project{Runtime: mocks.Runtime})

if err == nil {
t.Fatal("Expected error for ApplyConfigDefaults failure")
}
if proj != nil {
t.Error("Expected Project to be nil on error")
}
})

t.Run("ErrorOnWorkstationCreationFailure", func(t *testing.T) {
mocks := setupProjectMocks(t)
mockConfig := mocks.ConfigHandler.(*config.MockConfigHandler)
Expand Down Expand Up @@ -421,29 +393,6 @@ func TestNewProject(t *testing.T) {
}
})

t.Run("ErrorOnRuntimeCreationFailure", func(t *testing.T) {
mockShell := shell.NewMockShell()
mockShell.GetProjectRootFunc = func() (string, error) {
return "", fmt.Errorf("failed to get project root")
}

proj, err := NewProject("test-context", &Project{
Runtime: &runtime.Runtime{
Shell: mockShell,
},
})

if err == nil {
t.Fatal("Expected error for runtime creation failure")
}
if proj != nil {
t.Error("Expected Project to be nil on error")
}
if !strings.Contains(err.Error(), "failed to initialize context") && !strings.Contains(err.Error(), "failed to get project root") && !strings.Contains(err.Error(), "config handler not available") {
t.Errorf("Expected error about initializing context, getting project root, or config handler, got: %v", err)
}
})

}

// =============================================================================
Expand Down Expand Up @@ -643,6 +592,93 @@ func TestProject_Configure(t *testing.T) {
}
})

t.Run("CallsApplyConfigDefaultsWithFlagOverrides", func(t *testing.T) {
// Given a project with flag overrides containing vm.driver=colima
mocks := setupProjectMocks(t)
mockConfig := mocks.ConfigHandler.(*config.MockConfigHandler)
mockConfig.IsLoadedFunc = func() bool {
return false
}
mockConfig.IsDevModeFunc = func(contextName string) bool {
return true
}
mockConfig.GetStringFunc = func(key string, defaultValue ...string) string {
return ""
}

var setDefaultConfig v1alpha1.Context
mockConfig.SetDefaultFunc = func(cfg v1alpha1.Context) error {
setDefaultConfig = cfg
return nil
}
mockConfig.SetFunc = func(key string, value any) error {
return nil
}

proj, err := NewProject("test-context", &Project{Runtime: mocks.Runtime})
if err != nil {
t.Fatalf("Failed to create project: %v", err)
}

flagOverrides := map[string]any{
"vm.driver": "colima",
"provider": "generic",
}

// When Configure is called with flag overrides
err = proj.Configure(flagOverrides)

// Then ApplyConfigDefaults should be called with flag overrides, resulting in DefaultConfig_Full
if err != nil {
t.Errorf("Expected no error, got: %v", err)
}

if setDefaultConfig.Network == nil || setDefaultConfig.Network.LoadBalancerIPs == nil {
t.Error("Expected DefaultConfig_Full with LoadBalancerIPs to be set (colima should use Full config)")
}

if setDefaultConfig.Cluster != nil && len(setDefaultConfig.Cluster.Workers.HostPorts) > 0 {
t.Error("Expected DefaultConfig_Full without hostports to be set (colima should not have hostports)")
}
})

t.Run("ErrorOnApplyConfigDefaultsFailure", func(t *testing.T) {
// Given a project where SetDefault fails
mocks := setupProjectMocks(t)
mockConfig := mocks.ConfigHandler.(*config.MockConfigHandler)
mockConfig.IsLoadedFunc = func() bool {
return false
}
mockConfig.IsDevModeFunc = func(contextName string) bool {
return true
}
mockConfig.GetStringFunc = func(key string, defaultValue ...string) string {
return ""
}

mockConfig.SetDefaultFunc = func(cfg v1alpha1.Context) error {
return fmt.Errorf("set default failed")
}

proj, err := NewProject("test-context", &Project{Runtime: mocks.Runtime})
if err != nil {
t.Fatalf("Failed to create project: %v", err)
}

// When Configure is called
err = proj.Configure(nil)

// Then an error should be returned
if err == nil {
t.Error("Expected error for ApplyConfigDefaults failure")
return
}

if !strings.Contains(err.Error(), "failed to apply config defaults") {
t.Errorf("Expected error about apply config defaults, got: %v", err)
}
})

}

func TestProject_Initialize(t *testing.T) {
Expand Down Expand Up @@ -672,6 +708,10 @@ func TestProject_Initialize(t *testing.T) {
t.Fatalf("Failed to create project: %v", err)
}

if err := proj.Configure(nil); err != nil {
t.Fatalf("Failed to configure project: %v", err)
}

if proj.Workstation == nil {
t.Fatal("Expected workstation to be created")
}
Expand Down Expand Up @@ -834,6 +874,10 @@ func TestProject_Initialize(t *testing.T) {
t.Fatalf("Failed to create project: %v", err)
}

if err := proj.Configure(nil); err != nil {
t.Fatalf("Failed to configure project: %v", err)
}

if proj.Workstation == nil {
t.Fatal("Expected workstation to be created")
}
Expand All @@ -851,7 +895,7 @@ func TestProject_Initialize(t *testing.T) {
return
}

if !strings.Contains(err.Error(), "failed to assign IPs to network manager") {
if !strings.Contains(err.Error(), "failed to assign IPs to services") {
t.Errorf("Expected specific error message, got: %v", err)
}
})
Expand Down
Loading
Loading