Something went wrong. Try again.
An alternative CLI for git-bug that simplifies working with agents on issues
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614//go:build integration
package main
import ( "os" "os/exec" "strings" "testing"
"github.com/git-bug/git-bug/entities/bug" "github.com/git-bug/git-bug/entity" "github.com/git-bug/git-bug/repository")
// TestAgentCommentCommand_WithFlag adds a comment as agent using the message flagfunc TestAgentCommentCommand_WithFlag(t *testing.T) { tmpDir := t.TempDir()
// Initialize a git repo initCmd := exec.Command("git", "init") initCmd.Dir = tmpDir if err := initCmd.Run(); err != nil { t.Fatalf("failed to init git repo: %v", err) }
// Initialize git-bug with both user and agent identities if err := createIdentity(tmpDir, "Test User", "test@example.com", true); err != nil { t.Fatalf("failed to create user identity: %v", err) } if err := createIdentity(tmpDir, "agent", "", false); err != nil { t.Fatalf("failed to create agent identity: %v", err) }
// Create a bug first as user title := "Test Bug for Agent Comment" message := "Initial bug description" if err := runNew(tmpDir, title, message, "", "", ""); err != nil { t.Fatalf("runNew failed: %v", err) }
// Get the bug ID repo, err := repository.OpenGoGitRepo(tmpDir, "", nil) if err != nil { t.Fatalf("failed to open repo: %v", err) }
var bugID string for streamedBug := range bug.ReadAll(repo) { if streamedBug.Err != nil { t.Fatalf("failed to read bug: %v", streamedBug.Err) } b := streamedBug.Entity snap := b.Compile() if snap.Title == title { bugID = b.Id().String() break } } repo.Close()
if bugID == "" { t.Fatal("could not find created bug") }
// Add a comment as agent using the flag commentText := "This is an automated agent comment" if err := runAgentComment(tmpDir, bugID, commentText, "", false); err != nil { t.Fatalf("runAgentComment failed: %v", err) }
// Verify comment was added with agent as author repo, err = repository.OpenGoGitRepo(tmpDir, "", nil) if err != nil { t.Fatalf("failed to open repo: %v", err) } defer repo.Close()
b, err := bug.Read(repo, entity.Id(bugID)) if err != nil { t.Fatalf("failed to read bug: %v", err) }
snap := b.Compile() if len(snap.Comments) != 2 { t.Errorf("expected 2 comments (original + new), got %d", len(snap.Comments)) }
// Check the second comment (index 1) is our agent comment if snap.Comments[1].Message != commentText { t.Errorf("comment message = %q, want %q", snap.Comments[1].Message, commentText) }
if snap.Comments[1].Author.Name() != "agent" { t.Errorf("comment author = %q, want %q", snap.Comments[1].Author.Name(), "agent") }
if snap.Comments[1].Author.Email() != "" { t.Errorf("comment author email = %q, want empty", snap.Comments[1].Author.Email()) }}
// TestAgentCommentCommand_WithShortID adds a comment as agent using short bug IDfunc TestAgentCommentCommand_WithShortID(t *testing.T) { tmpDir := t.TempDir()
// Initialize a git repo initCmd := exec.Command("git", "init") initCmd.Dir = tmpDir if err := initCmd.Run(); err != nil { t.Fatalf("failed to init git repo: %v", err) }
// Initialize identities if err := createIdentity(tmpDir, "Test User", "test@example.com", true); err != nil { t.Fatalf("failed to create user identity: %v", err) } if err := createIdentity(tmpDir, "agent", "", false); err != nil { t.Fatalf("failed to create agent identity: %v", err) }
// Create a bug title := "Test Bug for Agent Short ID" if err := runNew(tmpDir, title, "", "", "", ""); err != nil { t.Fatalf("runNew failed: %v", err) }
// Get the bug ID and short ID repo, err := repository.OpenGoGitRepo(tmpDir, "", nil) if err != nil { t.Fatalf("failed to open repo: %v", err) }
var bugID, shortID string for streamedBug := range bug.ReadAll(repo) { if streamedBug.Err != nil { t.Fatalf("failed to read bug: %v", streamedBug.Err) } b := streamedBug.Entity snap := b.Compile() if snap.Title == title { bugID = b.Id().String() if len(bugID) > 7 { shortID = bugID[:7] } else { shortID = bugID } break } } repo.Close()
if shortID == "" { t.Fatal("could not find created bug") }
// Add a comment as agent using short ID commentText := "Agent comment via short ID" if err := runAgentComment(tmpDir, shortID, commentText, "", false); err != nil { t.Fatalf("runAgentComment with short ID failed: %v", err) }
// Verify comment was added repo, err = repository.OpenGoGitRepo(tmpDir, "", nil) if err != nil { t.Fatalf("failed to open repo: %v", err) } defer repo.Close()
b, err := bug.Read(repo, entity.Id(bugID)) if err != nil { t.Fatalf("failed to read bug: %v", err) }
snap := b.Compile() if len(snap.Comments) != 2 { t.Errorf("expected 2 comments, got %d", len(snap.Comments)) }
if snap.Comments[1].Message != commentText { t.Errorf("comment message = %q, want %q", snap.Comments[1].Message, commentText) }
if snap.Comments[1].Author.Name() != "agent" { t.Errorf("comment author = %q, want %q", snap.Comments[1].Author.Name(), "agent") }}
// TestAgentCommentCommand_MissingAgentIdentity tests error when agent not initializedfunc TestAgentCommentCommand_MissingAgentIdentity(t *testing.T) { tmpDir := t.TempDir()
// Initialize a git repo initCmd := exec.Command("git", "init") initCmd.Dir = tmpDir if err := initCmd.Run(); err != nil { t.Fatalf("failed to init git repo: %v", err) }
// Only create user identity, NOT agent if err := createIdentity(tmpDir, "Test User", "test@example.com", true); err != nil { t.Fatalf("failed to create user identity: %v", err) }
// Create a bug as user title := "Test Bug" if err := runNew(tmpDir, title, "", "", "", ""); err != nil { t.Fatalf("runNew failed: %v", err) }
// Get the bug ID repo, err := repository.OpenGoGitRepo(tmpDir, "", nil) if err != nil { t.Fatalf("failed to open repo: %v", err) }
var bugID string for streamedBug := range bug.ReadAll(repo) { if streamedBug.Err != nil { t.Fatalf("failed to read bug: %v", streamedBug.Err) } b := streamedBug.Entity snap := b.Compile() if snap.Title == title { bugID = b.Id().String() break } } repo.Close()
// Try to add a comment as agent (should fail) err = runAgentComment(tmpDir, bugID, "Test comment", "", false) if err == nil { t.Error("expected error when agent identity not found, got nil") }
if !strings.Contains(err.Error(), "agent identity not found") { t.Errorf("expected 'agent identity not found' error, got: %v", err) }}
// TestAgentCommentCommand_EmptyMessageError tests error for empty messagefunc TestAgentCommentCommand_EmptyMessageError(t *testing.T) { tmpDir := t.TempDir()
// Initialize a git repo initCmd := exec.Command("git", "init") initCmd.Dir = tmpDir if err := initCmd.Run(); err != nil { t.Fatalf("failed to init git repo: %v", err) }
// Initialize identities if err := createIdentity(tmpDir, "Test User", "test@example.com", true); err != nil { t.Fatalf("failed to create user identity: %v", err) } if err := createIdentity(tmpDir, "agent", "", false); err != nil { t.Fatalf("failed to create agent identity: %v", err) }
// Create a bug title := "Test Bug" if err := runNew(tmpDir, title, "", "", "", ""); err != nil { t.Fatalf("runNew failed: %v", err) }
// Get the bug ID repo, err := repository.OpenGoGitRepo(tmpDir, "", nil) if err != nil { t.Fatalf("failed to open repo: %v", err) }
var bugID string for streamedBug := range bug.ReadAll(repo) { if streamedBug.Err != nil { t.Fatalf("failed to read bug: %v", streamedBug.Err) } b := streamedBug.Entity snap := b.Compile() if snap.Title == title { bugID = b.Id().String() break } } repo.Close()
// Try with empty message err = runAgentComment(tmpDir, bugID, " ", "", false) if err == nil { t.Error("expected error for empty message, got nil") }
if !strings.Contains(err.Error(), "message cannot be empty") { t.Errorf("expected 'message cannot be empty' error, got: %v", err) }}
// TestAgentCommentCommand_InvalidBugID tests error for invalid bug IDfunc TestAgentCommentCommand_InvalidBugID(t *testing.T) { tmpDir := t.TempDir()
// Initialize a git repo initCmd := exec.Command("git", "init") initCmd.Dir = tmpDir if err := initCmd.Run(); err != nil { t.Fatalf("failed to init git repo: %v", err) }
// Initialize identities if err := createIdentity(tmpDir, "Test User", "test@example.com", true); err != nil { t.Fatalf("failed to create user identity: %v", err) } if err := createIdentity(tmpDir, "agent", "", false); err != nil { t.Fatalf("failed to create agent identity: %v", err) }
// Try to add a comment to non-existent bug err := runAgentComment(tmpDir, "nonexistent", "Test comment", "", false) if err == nil { t.Error("expected error for invalid bug ID, got nil") }
if !strings.Contains(err.Error(), "failed to resolve bug ID") { t.Errorf("expected 'failed to resolve bug ID' error, got: %v", err) }}
// TestAgentCommentCommand_MultipleComments tests adding multiple agent commentsfunc TestAgentCommentCommand_MultipleComments(t *testing.T) { tmpDir := t.TempDir()
// Initialize a git repo initCmd := exec.Command("git", "init") initCmd.Dir = tmpDir if err := initCmd.Run(); err != nil { t.Fatalf("failed to init git repo: %v", err) }
// Initialize identities if err := createIdentity(tmpDir, "Test User", "test@example.com", true); err != nil { t.Fatalf("failed to create user identity: %v", err) } if err := createIdentity(tmpDir, "agent", "", false); err != nil { t.Fatalf("failed to create agent identity: %v", err) }
// Create a bug as user title := "Test Bug for Multiple Agent Comments" if err := runNew(tmpDir, title, "", "", "", ""); err != nil { t.Fatalf("runNew failed: %v", err) }
// Get the bug ID repo, err := repository.OpenGoGitRepo(tmpDir, "", nil) if err != nil { t.Fatalf("failed to open repo: %v", err) }
var bugID string for streamedBug := range bug.ReadAll(repo) { if streamedBug.Err != nil { t.Fatalf("failed to read bug: %v", streamedBug.Err) } b := streamedBug.Entity snap := b.Compile() if snap.Title == title { bugID = b.Id().String() break } } repo.Close()
// Add multiple comments as agent comments := []string{ "First agent comment", "Second agent comment", "Third agent comment with **markdown**", }
for _, comment := range comments { if err := runAgentComment(tmpDir, bugID, comment, "", false); err != nil { t.Fatalf("runAgentComment failed: %v", err) } }
// Verify all comments were added repo, err = repository.OpenGoGitRepo(tmpDir, "", nil) if err != nil { t.Fatalf("failed to open repo: %v", err) } defer repo.Close()
b, err := bug.Read(repo, entity.Id(bugID)) if err != nil { t.Fatalf("failed to read bug: %v", err) }
snap := b.Compile() // Original + 3 comments = 4 total if len(snap.Comments) != 4 { t.Errorf("expected 4 comments, got %d", len(snap.Comments)) }
// Verify each comment (index 1-3 are our added comments) for i, expected := range comments { if snap.Comments[i+1].Message != expected { t.Errorf("comment %d message = %q, want %q", i+1, snap.Comments[i+1].Message, expected) } if snap.Comments[i+1].Author.Name() != "agent" { t.Errorf("comment %d author = %q, want %q", i+1, snap.Comments[i+1].Author.Name(), "agent") } }}
// TestAgentCommentCommand_WithMarkdown tests that markdown is preservedfunc TestAgentCommentCommand_WithMarkdown(t *testing.T) { tmpDir := t.TempDir()
// Initialize a git repo initCmd := exec.Command("git", "init") initCmd.Dir = tmpDir if err := initCmd.Run(); err != nil { t.Fatalf("failed to init git repo: %v", err) }
// Initialize identities if err := createIdentity(tmpDir, "Test User", "test@example.com", true); err != nil { t.Fatalf("failed to create user identity: %v", err) } if err := createIdentity(tmpDir, "agent", "", false); err != nil { t.Fatalf("failed to create agent identity: %v", err) }
// Create a bug title := "Test Bug for Markdown" if err := runNew(tmpDir, title, "", "", "", ""); err != nil { t.Fatalf("runNew failed: %v", err) }
// Get the bug ID repo, err := repository.OpenGoGitRepo(tmpDir, "", nil) if err != nil { t.Fatalf("failed to open repo: %v", err) }
var bugID string for streamedBug := range bug.ReadAll(repo) { if streamedBug.Err != nil { t.Fatalf("failed to read bug: %v", streamedBug.Err) } b := streamedBug.Entity snap := b.Compile() if snap.Title == title { bugID = b.Id().String() break } } repo.Close()
// Add a comment with markdown markdownComment := `# Analysis Report
## Summary- **Status**: PASSED- **Duration**: 5m 32s
## DetailsAll tests passed successfully.`
if err := runAgentComment(tmpDir, bugID, markdownComment, "", false); err != nil { t.Fatalf("runAgentComment failed: %v", err) }
// Verify comment was added with markdown preserved repo, err = repository.OpenGoGitRepo(tmpDir, "", nil) if err != nil { t.Fatalf("failed to open repo: %v", err) } defer repo.Close()
b, err := bug.Read(repo, entity.Id(bugID)) if err != nil { t.Fatalf("failed to read bug: %v", err) }
snap := b.Compile() if len(snap.Comments) != 2 { t.Errorf("expected 2 comments, got %d", len(snap.Comments)) }
if snap.Comments[1].Message != markdownComment { t.Errorf("comment message does not match expected markdown:\ngot:\n%s\nwant:\n%s", snap.Comments[1].Message, markdownComment) }}
// TestAgentCommentCommand_WithStdin tests adding a comment using --stdin flagfunc TestAgentCommentCommand_WithStdin(t *testing.T) { tmpDir := t.TempDir()
// Initialize a git repo initCmd := exec.Command("git", "init") initCmd.Dir = tmpDir if err := initCmd.Run(); err != nil { t.Fatalf("failed to init git repo: %v", err) }
// Initialize identities if err := createIdentity(tmpDir, "Test User", "test@example.com", true); err != nil { t.Fatalf("failed to create user identity: %v", err) } if err := createIdentity(tmpDir, "agent", "", false); err != nil { t.Fatalf("failed to create agent identity: %v", err) }
// Create a bug title := "Test Bug for Stdin Comment" if err := runNew(tmpDir, title, "", "", "", ""); err != nil { t.Fatalf("runNew failed: %v", err) }
// Get the bug ID repo, err := repository.OpenGoGitRepo(tmpDir, "", nil) if err != nil { t.Fatalf("failed to open repo: %v", err) }
var bugID string for streamedBug := range bug.ReadAll(repo) { if streamedBug.Err != nil { t.Fatalf("failed to read bug: %v", streamedBug.Err) } b := streamedBug.Entity snap := b.Compile() if snap.Title == title { bugID = b.Id().String() break } } repo.Close()
// Multi-line content with markdown to test via stdin stdinContent := `# Implementation Plan
## Task 1: Setup**Files:**- Create: path/to/file.go- Test: path/to/file_test.go
**Step 1: Initialize**Initialize the configuration:
` + "```go" + `func Initialize() error { return nil}` + "```" + `
## Next Steps1. Run tests2. Verify results3. Document changes`
// Create a pipe to simulate stdin r, w, err := os.Pipe() if err != nil { t.Fatalf("failed to create pipe: %v", err) }
// Write content to the pipe in a goroutine go func() { defer w.Close() w.WriteString(stdinContent) }()
// Save original stdin and replace with our pipe oldStdin := os.Stdin os.Stdin = r defer func() { os.Stdin = oldStdin }()
// Add a comment as agent using stdin flag // We pass empty message and true for useStdin if err := runAgentComment(tmpDir, bugID, "", "", true); err != nil { t.Fatalf("runAgentComment with stdin failed: %v", err) }
// Verify comment was added with stdin content repo, err = repository.OpenGoGitRepo(tmpDir, "", nil) if err != nil { t.Fatalf("failed to open repo: %v", err) } defer repo.Close()
b, err := bug.Read(repo, entity.Id(bugID)) if err != nil { t.Fatalf("failed to read bug: %v", err) }
snap := b.Compile() if len(snap.Comments) != 2 { t.Errorf("expected 2 comments, got %d", len(snap.Comments)) }
// Content should be trimmed but preserve markdown expectedContent := strings.TrimSpace(stdinContent) if snap.Comments[1].Message != expectedContent { t.Errorf("comment message does not match expected stdin content:\ngot:\n%s\nwant:\n%s", snap.Comments[1].Message, expectedContent) }
// Verify agent is the author if snap.Comments[1].Author.Name() != "agent" { t.Errorf("comment author = %q, want %q", snap.Comments[1].Author.Name(), "agent") }}