feat: initial commit of Git Automation CLI

- Add comprehensive Git workflow automation tools
- Include branch management utilities
- Add commit helpers with conventional commit support
- Implement GitHub integration for PR management
- Add configuration management system
- Include comprehensive test coverage
- Add professional documentation and examples
This commit is contained in:
Dev
2025-09-11 17:02:12 +03:00
commit 15bbfdcda2
27 changed files with 5727 additions and 0 deletions

134
internal/cmd/commands.go Normal file
View File

@@ -0,0 +1,134 @@
package cmd
import (
"context"
"fmt"
"strings"
"github.com/spf13/cobra"
"github.com/iwasforcedtobehere/git-automation-cli/internal/git"
"github.com/iwasforcedtobehere/git-automation-cli/internal/config"
)
func init() {
rootCmd.AddCommand(syncCmd)
rootCmd.AddCommand(cleanCmd)
}
var syncCmd = &cobra.Command{
Use: "sync",
Short: "Sync with remote",
Long: `Fetch the latest changes from remote, rebase the current branch onto
its upstream tracking branch, and push the changes back to remote.`,
RunE: func(cmd *cobra.Command, args []string) error {
ctx := context.Background()
// Check if we're in a Git repository
if _, err := git.CurrentBranch(ctx); err != nil {
return fmt.Errorf("not a git repository or no branch found")
}
// Fetch latest changes
if config.GlobalConfig.Verbose {
fmt.Println("Fetching latest changes from remote...")
}
if err := git.Fetch(ctx); err != nil {
return fmt.Errorf("failed to fetch from remote: %w", err)
}
// Rebase onto tracking branch
if config.GlobalConfig.Verbose {
fmt.Println("Rebasing current branch onto tracking branch...")
}
if err := git.RebaseOntoTracking(ctx); err != nil {
return fmt.Errorf("failed to rebase: %w", err)
}
// Push changes
if config.GlobalConfig.Verbose {
fmt.Println("Pushing changes to remote...")
}
if err := git.PushCurrent(ctx, false); err != nil {
return fmt.Errorf("failed to push: %w", err)
}
fmt.Println("Successfully synced with remote")
return nil
},
}
var cleanCmd = &cobra.Command{
Use: "clean",
Short: "Clean local feature branches",
Long: `Delete local feature branches that have been merged or are no longer needed.
By default, only deletes branches with the 'feature/' prefix.`,
RunE: func(cmd *cobra.Command, args []string) error {
ctx := context.Background()
// Check if we're in a Git repository
if _, err := git.CurrentBranch(ctx); err != nil {
return fmt.Errorf("not a git repository or no branch found")
}
// Get all local branches
branches, err := git.LocalBranches(ctx)
if err != nil {
return fmt.Errorf("failed to list branches: %w", err)
}
// Get current branch to avoid deleting it
currentBranch, err := git.CurrentBranch(ctx)
if err != nil {
return fmt.Errorf("failed to get current branch: %w", err)
}
var removed []string
var prefix string
// Determine which prefix to use for cleaning
if config.GlobalConfig.FeaturePrefix != "" {
prefix = config.GlobalConfig.FeaturePrefix
} else {
prefix = "feature/"
}
for _, b := range branches {
// Skip current branch and main/master branches
if b == currentBranch || b == "main" || b == "master" {
continue
}
// Check if branch matches the prefix
if strings.HasPrefix(b, prefix) {
// Confirm deletion if configured
if config.GlobalConfig.ConfirmDestructive {
fmt.Printf("Delete branch '%s'? [y/N]: ", b)
var response string
fmt.Scanln(&response)
if strings.ToLower(response) != "y" && strings.ToLower(response) != "yes" {
continue
}
}
if err := git.DeleteBranch(ctx, b); err == nil {
removed = append(removed, b)
if config.GlobalConfig.Verbose {
fmt.Printf("Deleted branch: %s\n", b)
}
} else if config.GlobalConfig.Verbose {
fmt.Printf("Failed to delete branch %s: %v\n", b, err)
}
}
}
if len(removed) > 0 {
fmt.Printf("Deleted %d branches:\n", len(removed))
for _, branch := range removed {
fmt.Printf(" - %s\n", branch)
}
} else {
fmt.Println("No branches to clean")
}
return nil
},
}