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
2 changes: 1 addition & 1 deletion cmd/commit.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ var commitCmd = &cobra.Command{
Use: "commit",
Short: "Automatically generate commit message",
RunE: func(cmd *cobra.Command, args []string) error {
if err := check(); err != nil {
if err := check(cmd.Context()); err != nil {
return err
}

Expand Down
10 changes: 9 additions & 1 deletion cmd/hepler.go
Original file line number Diff line number Diff line change
@@ -1,22 +1,30 @@
package cmd

import (
"context"
"errors"
"fmt"

"github.com/appleboy/CodeGPT/git"
"github.com/appleboy/CodeGPT/prompt"
"github.com/appleboy/CodeGPT/provider/openai"
"github.com/appleboy/CodeGPT/util"
"github.com/appleboy/com/file"
"github.com/spf13/viper"
)

func check() error {
func check(ctx context.Context) error {
// Check if the Git command is available on the system's PATH
if !util.IsCommandAvailable("git") {
return errors.New("git command not found in your system's PATH. Please install Git and try again")
}

// Check if the current directory is a git repository and can execute git diff
g := git.New()
if err := g.CanExecuteGitDiff(ctx); err != nil {
return fmt.Errorf("cannot execute git diff: %w", err)
}

// Apply configuration values from CLI flags to Viper
if diffUnified != 3 {
viper.Set("git.diff_unified", diffUnified)
Expand Down
2 changes: 1 addition & 1 deletion cmd/review.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ var reviewCmd = &cobra.Command{
Use: "review",
Short: "Auto review code changes",
RunE: func(cmd *cobra.Command, args []string) error {
if err := check(); err != nil {
if err := check(cmd.Context()); err != nil {
return err
}

Expand Down
25 changes: 25 additions & 0 deletions git/git.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,16 @@ func (c *Command) gitDir(ctx context.Context) *exec.Cmd {
)
}

// checkGitRepository generates the git command to check if the current directory is a git repository.
func (c *Command) checkGitRepository(ctx context.Context) *exec.Cmd {
return exec.CommandContext(
ctx,
"git",
"rev-parse",
"--is-inside-work-tree",
)
}

// commit generates the git command to create a commit with the provided message.
// It includes options to skip pre-commit hooks, sign off the commit, and handle amendments.
func (c *Command) commit(ctx context.Context, val string) *exec.Cmd {
Expand Down Expand Up @@ -163,6 +173,21 @@ func (c *Command) GitDir(ctx context.Context) (string, error) {
return string(output), nil
}

// CanExecuteGitDiff checks if git diff can be executed in the current directory.
// It returns an error if the current directory is not a git repository or if git diff cannot be executed.
func (c *Command) CanExecuteGitDiff(ctx context.Context) error {
output, err := c.checkGitRepository(ctx).Output()
if err != nil {
return errors.New("not a git repository (or any of the parent directories)")
}

if strings.TrimSpace(string(output)) != "true" {
return errors.New("not inside a git working tree")
}

return nil
}

// Diff compares the differences between two sets of data.
// It returns a string representing the differences and an error.
// If there are no differences, it returns an empty string and an error.
Expand Down
88 changes: 88 additions & 0 deletions git/git_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package git

import (
"context"
"os"
"path/filepath"
"testing"
)

func TestCanExecuteGitDiff(t *testing.T) {
// Test in the current directory (which is a git repository)
t.Run("in git repository", func(t *testing.T) {
cmd := New()
ctx := context.Background()

err := cmd.CanExecuteGitDiff(ctx)
if err != nil {
t.Errorf("CanExecuteGitDiff() should succeed in a git repository, got error: %v", err)
}
})

// Test in a non-git directory
t.Run("not in git repository", func(t *testing.T) {
// Create a temporary directory
tmpDir := t.TempDir()

// Change to the temporary directory
originalDir, err := os.Getwd()
if err != nil {
t.Fatalf("Failed to get current directory: %v", err)
}
defer func() {
if err := os.Chdir(originalDir); err != nil {
t.Logf("Failed to restore directory: %v", err)
}
}()

if err := os.Chdir(tmpDir); err != nil {
t.Fatalf("Failed to change directory: %v", err)
}

cmd := New()
ctx := context.Background()

err = cmd.CanExecuteGitDiff(ctx)
if err == nil {
t.Error("CanExecuteGitDiff() should fail in a non-git directory")
}

expectedMsg := "not a git repository"
if err != nil && err.Error() != expectedMsg {
t.Logf("Got expected error: %v", err)
}
})

// Test in a git repository subdirectory
t.Run("in git repository subdirectory", func(t *testing.T) {
// Create a test subdirectory in the git repository
tmpDir := filepath.Join(".", "test_subdir")
if err := os.MkdirAll(tmpDir, 0o755); err != nil {
t.Fatalf("Failed to create test directory: %v", err)
}
defer os.RemoveAll(tmpDir)

// Change to the subdirectory
originalDir, err := os.Getwd()
if err != nil {
t.Fatalf("Failed to get current directory: %v", err)
}
defer func() {
if err := os.Chdir(originalDir); err != nil {
t.Logf("Failed to restore directory: %v", err)
}
}()

if err := os.Chdir(tmpDir); err != nil {
t.Fatalf("Failed to change directory: %v", err)
}

cmd := New()
ctx := context.Background()

err = cmd.CanExecuteGitDiff(ctx)
if err != nil {
t.Errorf("CanExecuteGitDiff() should succeed in a git repository subdirectory, got error: %v", err)
}
})
}
Loading