140 lines
3.9 KiB
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
|
|
}
|