Files
onyx-prebootstrap/internal/commands/switch.go

140 lines
3.9 KiB
Go

package commands
import (
"fmt"
"os"
"git.dws.rip/DWS/onyx/internal/core"
"github.com/spf13/cobra"
)
// NewSwitchCmd creates the switch command
func NewSwitchCmd() *cobra.Command {
var force bool
cmd := &cobra.Command{
Use: "switch <name>",
Short: "Switch to a different workstream",
Long: `Switch to a different workstream.
This command will:
1. Check for uncommitted changes (unless --force is used)
2. Load the target workstream
3. Checkout the latest commit in the target workstream
4. Update the current workstream pointer
⚠️ Warning: Switching discards uncommitted changes in your working directory.
Use 'onx save' to commit your work before switching, or use --force to bypass the safety check.`,
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
return runSwitch(args[0], force)
},
}
cmd.Flags().BoolVarP(&force, "force", "f", false, "Force switch even with uncommitted changes")
return cmd
}
// runSwitch executes the switch command
func runSwitch(name string, force bool) error {
// Get current directory
cwd, err := os.Getwd()
if err != nil {
return fmt.Errorf("failed to get current directory: %w", err)
}
// Check if this is an Onyx repository
if !core.IsOnyxRepo(cwd) {
return fmt.Errorf("not an Onyx repository")
}
// Open the repository
repo, err := core.Open(cwd)
if err != nil {
return fmt.Errorf("failed to open repository: %w", err)
}
defer repo.Close()
// Create workstream manager
wsManager := core.NewWorkstreamManager(repo)
// Get current workstream name before switching
currentName, err := wsManager.GetCurrentWorkstreamName()
if err != nil {
currentName = "none"
}
// Check if we're already on the target workstream
if currentName == name {
fmt.Printf("Already on workstream '%s'\n", name)
return nil
}
// Check for uncommitted changes unless force is enabled
if !force {
gitRepo := repo.GetGitRepo()
worktree, err := gitRepo.Worktree()
if err != nil {
return fmt.Errorf("failed to get worktree: %w", err)
}
status, err := worktree.Status()
if err != nil {
return fmt.Errorf("failed to check status: %w", err)
}
if !status.IsClean() {
// Show which files have changes
fmt.Println("Error: You have uncommitted changes:")
for file, fileStatus := range status {
if fileStatus.Worktree != ' ' || fileStatus.Staging != ' ' {
fmt.Printf(" %c%c %s\n", fileStatus.Staging, fileStatus.Worktree, file)
}
}
fmt.Println("\nPlease commit your changes or use --force to discard them:")
fmt.Printf(" onx save -m \"WIP\" # Save your work\n")
fmt.Printf(" onx switch %s --force # Discard changes and switch\n", name)
return fmt.Errorf("uncommitted changes present")
}
}
// Use ExecuteWithTransaction to capture state_before and state_after
err = core.ExecuteWithTransaction(repo, "switch", fmt.Sprintf("Switched from '%s' to '%s'", currentName, name), func() error {
return wsManager.SwitchWorkstream(name)
})
if err != nil {
return err
}
// Get the workstream we just switched to
targetWorkstream, err := wsManager.GetCurrentWorkstream()
if err != nil {
return fmt.Errorf("failed to get workstream after switch: %w", err)
}
// Display success message
fmt.Printf("Switched to workstream '%s'\n", name)
// Show workstream info
commitCount := targetWorkstream.GetCommitCount()
if commitCount == 0 {
fmt.Printf("\nThis is a new workstream based on '%s' with no commits yet.\n", targetWorkstream.BaseBranch)
fmt.Printf("Make changes and save them with 'onx save -m \"message\"'\n")
} else {
commitText := "commit"
if commitCount != 1 {
commitText = "commits"
}
fmt.Printf("\nThis workstream has %d %s.\n", commitCount, commitText)
// Show the latest commit
if latestCommit, err := targetWorkstream.GetLatestCommit(); err == nil {
fmt.Printf("Latest commit: %s\n", latestCommit.Message)
}
}
return nil
}