package cmd import ( "bufio" "fmt" "os" "strings" "github.com/spf13/cobra" "github.com/iwasforcedtobehere/git-automation-cli/internal/git" "github.com/iwasforcedtobehere/git-automation-cli/internal/validation" ) var commitCmd = &cobra.Command{ Use: "commit", Short: "Commit utilities", Long: `Create and manage Git commits with templates and helpers. Supports conventional commit format and commit message templates.`, } var commitCreateCmd = &cobra.Command{ Use: "create [message]", Short: "Create a new commit", Args: cobra.MinimumNArgs(1), RunE: func(cmd *cobra.Command, args []string) error { ctx := cmd.Context() message := strings.Join(args, " ") // Validate Git repository if validationResult := validation.ValidateGitRepository(ctx); !validationResult.IsValid { return fmt.Errorf(validationResult.GetErrors()) } // Validate commit message if validationResult := validation.ValidateCommitMessage(message); !validationResult.IsValid { return fmt.Errorf("invalid commit message: %s", validationResult.GetErrors()) } // Check if working directory is clean if validationResult := validation.ValidateWorkingDirectory(ctx); !validationResult.IsValid { return fmt.Errorf(validationResult.GetErrors()) } // Add all changes if err := git.AddAll(ctx); err != nil { return fmt.Errorf("failed to add changes: %w", err) } // Create commit if err := git.Commit(ctx, message); err != nil { return fmt.Errorf("failed to create commit: %w", err) } fmt.Printf("Created commit: %s\n", message) return nil }, } var commitAmendCmd = &cobra.Command{ Use: "amend", Short: "Amend the last commit", RunE: func(cmd *cobra.Command, args []string) error { ctx := cmd.Context() // Validate Git repository if validationResult := validation.ValidateGitRepository(ctx); !validationResult.IsValid { return fmt.Errorf(validationResult.GetErrors()) } // Check if working directory is clean if validationResult := validation.ValidateWorkingDirectory(ctx); !validationResult.IsValid { return fmt.Errorf(validationResult.GetErrors()) } // Add all changes if err := git.AddAll(ctx); err != nil { return fmt.Errorf("failed to add changes: %w", err) } // Amend commit var err error _, err = git.Run(ctx, "commit", "--amend", "--no-edit") if err != nil { return fmt.Errorf("failed to amend commit: %w", err) } fmt.Println("Amended last commit") return nil }, } var commitFixupCmd = &cobra.Command{ Use: "fixup [commit]", Short: "Create a fixup commit", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { ctx := cmd.Context() commit := args[0] // Validate Git repository if validationResult := validation.ValidateGitRepository(ctx); !validationResult.IsValid { return fmt.Errorf(validationResult.GetErrors()) } // Check if working directory is clean if validationResult := validation.ValidateWorkingDirectory(ctx); !validationResult.IsValid { return fmt.Errorf(validationResult.GetErrors()) } // Add all changes if err := git.AddAll(ctx); err != nil { return fmt.Errorf("failed to add changes: %w", err) } // Create fixup commit var err error _, err = git.Run(ctx, "commit", "--fixup", commit) if err != nil { return fmt.Errorf("failed to create fixup commit: %w", err) } fmt.Printf("Created fixup commit for %s\n", commit) return nil }, } var commitConventionalCmd = &cobra.Command{ Use: "conventional", Short: "Create a conventional commit", RunE: func(cmd *cobra.Command, args []string) error { ctx := cmd.Context() // Get commit type fmt.Println("Select commit type:") fmt.Println("1. feat: A new feature") fmt.Println("2. fix: A bug fix") fmt.Println("3. docs: Documentation only changes") fmt.Println("4. style: Changes that do not affect the meaning of the code") fmt.Println("5. refactor: A code change that neither fixes a bug nor adds a feature") fmt.Println("6. perf: A code change that improves performance") fmt.Println("7. test: Adding missing tests or correcting existing tests") fmt.Println("8. build: Changes that affect the build system or external dependencies") fmt.Println("9. ci: Changes to our CI configuration files and scripts") fmt.Println("10. chore: Other changes that don't modify src or test files") var choice int fmt.Print("Enter choice (1-10): ") fmt.Scanln(&choice) var commitType string switch choice { case 1: commitType = "feat" case 2: commitType = "fix" case 3: commitType = "docs" case 4: commitType = "style" case 5: commitType = "refactor" case 6: commitType = "perf" case 7: commitType = "test" case 8: commitType = "build" case 9: commitType = "ci" case 10: commitType = "chore" default: return fmt.Errorf("invalid choice") } // Get scope fmt.Print("Enter scope (optional, press Enter to skip): ") reader := bufio.NewReader(os.Stdin) scope, _ := reader.ReadString('\n') scope = strings.TrimSpace(scope) // Get description fmt.Print("Enter description: ") description, _ := reader.ReadString('\n') description = strings.TrimSpace(description) if description == "" { return fmt.Errorf("description is required") } // Get body (optional) fmt.Print("Enter detailed description (optional, press Enter to skip): ") body, _ := reader.ReadString('\n') body = strings.TrimSpace(body) // Build commit message var message string if scope != "" { message = fmt.Sprintf("%s(%s): %s", commitType, scope, description) } else { message = fmt.Sprintf("%s: %s", commitType, description) } if body != "" { message += "\n\n" + body } // Validate Git repository if validationResult := validation.ValidateGitRepository(ctx); !validationResult.IsValid { return fmt.Errorf(validationResult.GetErrors()) } // Validate conventional commit message if validationResult := validation.ValidateConventionalCommit(message); !validationResult.IsValid { return fmt.Errorf("invalid conventional commit message: %s", validationResult.GetErrors()) } // Check if working directory is clean if validationResult := validation.ValidateWorkingDirectory(ctx); !validationResult.IsValid { return fmt.Errorf(validationResult.GetErrors()) } // Add all changes if err := git.AddAll(ctx); err != nil { return fmt.Errorf("failed to add changes: %w", err) } // Create commit if err := git.Commit(ctx, message); err != nil { return fmt.Errorf("failed to create commit: %w", err) } fmt.Printf("Created conventional commit: %s\n", message) return nil }, } var commitSignoffCmd = &cobra.Command{ Use: "signoff [message]", Short: "Create a commit with sign-off", Args: cobra.MinimumNArgs(1), RunE: func(cmd *cobra.Command, args []string) error { ctx := cmd.Context() message := strings.Join(args, " ") // Validate Git repository if validationResult := validation.ValidateGitRepository(ctx); !validationResult.IsValid { return fmt.Errorf(validationResult.GetErrors()) } // Validate commit message if validationResult := validation.ValidateCommitMessage(message); !validationResult.IsValid { return fmt.Errorf("invalid commit message: %s", validationResult.GetErrors()) } // Check if working directory is clean if validationResult := validation.ValidateWorkingDirectory(ctx); !validationResult.IsValid { return fmt.Errorf(validationResult.GetErrors()) } // Add all changes if err := git.AddAll(ctx); err != nil { return fmt.Errorf("failed to add changes: %w", err) } // Create commit with sign-off var err error _, err = git.Run(ctx, "commit", "-s", "-m", message) if err != nil { return fmt.Errorf("failed to create commit: %w", err) } fmt.Printf("Created signed-off commit: %s\n", message) return nil }, } func init() { rootCmd.AddCommand(commitCmd) commitCmd.AddCommand(commitCreateCmd) commitCmd.AddCommand(commitAmendCmd) commitCmd.AddCommand(commitFixupCmd) commitCmd.AddCommand(commitConventionalCmd) commitCmd.AddCommand(commitSignoffCmd) }