//go:build integration package main import ( "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" ) // TestCommentCommand_WithFlag adds a comment using the message flag func TestCommentCommand_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 identities if err := createIdentity(tmpDir, "Test User", "test@example.com", true); err != nil { t.Fatalf("failed to create identity: %v", err) } // Create a bug first title := "Test Bug for 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 using the flag commentText := "This is a test comment" if err := runComment(tmpDir, bugID, commentText); err != nil { t.Fatalf("runComment 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 (original + new), got %d", len(snap.Comments)) } // Check the second comment (index 1) is our new 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() != "Test User" { t.Errorf("comment author = %q, want %q", snap.Comments[1].Author.Name(), "Test User") } } // TestCommentCommand_WithShortID adds a comment using a short bug ID func TestCommentCommand_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 git-bug identities if err := createIdentity(tmpDir, "Test User", "test@example.com", true); err != nil { t.Fatalf("failed to create identity: %v", err) } // Create a bug title := "Test Bug for 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() // Use first 7 chars as short ID 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 using short ID commentText := "Comment added via short ID" if err := runComment(tmpDir, shortID, commentText); err != nil { t.Fatalf("runComment 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) } } // TestCommentCommand_NoIdentityError tests error when identity not set func TestCommentCommand_NoIdentityError(t *testing.T) { tmpDir := t.TempDir() // Initialize a git repo (but no git-bug identities) initCmd := exec.Command("git", "init") initCmd.Dir = tmpDir if err := initCmd.Run(); err != nil { t.Fatalf("failed to init git repo: %v", err) } // Don't create any identities - try to add a comment to non-existent bug // Bug ID resolution happens before identity check, so we should get ID error first err := runComment(tmpDir, "nonexistent123", "Test comment") if err == nil { t.Error("expected error, got nil") } // Since no bugs exist at all, we should get an ID resolution error if !strings.Contains(err.Error(), "failed to resolve bug ID") { t.Errorf("expected 'failed to resolve bug ID' error, got: %v", err) } } // TestCommentCommand_EmptyMessageError tests error for empty message func TestCommentCommand_EmptyMessageError(t *testing.T) { tmpDir := t.TempDir() // Blank message opens the editor; use one that exits immediately with no input t.Setenv("EDITOR", "true") // 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 identities if err := createIdentity(tmpDir, "Test User", "test@example.com", true); err != nil { t.Fatalf("failed to create identity: %v", err) } // Create a bug first 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 with empty message (whitespace only) // This triggers the editor path, which returns "no comment provided" err = runComment(tmpDir, bugID, " ") if err == nil { t.Error("expected error for empty message, got nil") } // When empty message is provided, editor opens and returns "no comment provided" if !strings.Contains(err.Error(), "no comment provided") { t.Errorf("expected 'no comment provided' error, got: %v", err) } } // TestCommentCommand_InvalidBugID tests error for invalid bug ID func TestCommentCommand_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 git-bug identities if err := createIdentity(tmpDir, "Test User", "test@example.com", true); err != nil { t.Fatalf("failed to create identity: %v", err) } // Try to add a comment to non-existent bug err := runComment(tmpDir, "nonexistent", "Test comment") 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) } } // TestCommentCommand_MultipleComments tests adding multiple comments func TestCommentCommand_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 git-bug identities if err := createIdentity(tmpDir, "Test User", "test@example.com", true); err != nil { t.Fatalf("failed to create identity: %v", err) } // Create a bug title := "Test Bug for Multiple 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 comments := []string{ "First comment", "Second comment", "Third comment with **markdown**", } for _, comment := range comments { if err := runComment(tmpDir, bugID, comment); err != nil { t.Fatalf("runComment 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) } } }