Something went wrong. Try again.
An alternative CLI for git-bug that simplifies working with agents on issues
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391//go:build integration
package main
import ( "os" "os/exec" "path/filepath" "strings" "testing"
"github.com/git-bug/git-bug/entities/identity" "github.com/git-bug/git-bug/repository")
// setupGitRepo creates a git repo with an origin remote for testingfunc setupGitRepo(t *testing.T) string { 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) } // Add origin remote for bug init remoteCmd := exec.Command("git", "remote", "add", "origin", localBareRemote(t)) remoteCmd.Dir = tmpDir if err := remoteCmd.Run(); err != nil { t.Fatalf("failed to add origin remote: %v", err) }
// Configure git user for the repo (needed for git operations) exec.Command("git", "-C", tmpDir, "config", "user.email", "test@example.com").Run() exec.Command("git", "-C", tmpDir, "config", "user.name", "Test User").Run()
return tmpDir}
// setupGitRepoWithInit creates a git repo with origin remote and runs bug initfunc setupGitRepoWithInit(t *testing.T) string { tmpDir := setupGitRepo(t)
// Initialize git-bug if err := runInitWithReader(tmpDir, strings.NewReader("Test User\ntest@example.com\n")); err != nil { t.Fatalf("runInit failed: %v", err) }
return tmpDir}
// TestInitCommand_WithJJ tests init when jj config is availablefunc TestInitCommand_WithJJ(t *testing.T) { tmpDir := setupGitRepo(t)
// Create .jj directory and config file directly jjDir := filepath.Join(tmpDir, ".jj") if err := os.MkdirAll(jjDir, 0755); err != nil { t.Fatalf("failed to create .jj directory: %v", err) }
// Write jj config file directly configContent := `[user]name = "JJ Test User"email = "jj-test@example.com"` configPath := filepath.Join(jjDir, "config.toml") if err := os.WriteFile(configPath, []byte(configContent), 0644); err != nil { t.Fatalf("failed to write jj config: %v", err) }
// Run init err := runInit(tmpDir) if err != nil { t.Fatalf("runInit failed: %v", err) }
// Verify identities were created repo, err := repository.OpenGoGitRepo(tmpDir, "", nil) if err != nil { t.Fatalf("failed to open repo: %v", err) } defer repo.Close()
ids, err := identity.ListLocalIds(repo) if err != nil { t.Fatalf("ListLocalIds failed: %v", err) }
// Should have at least 2 identities (user + agent) if len(ids) < 2 { t.Errorf("expected at least 2 identities, got %d", len(ids)) }
// Check if user identity is set isSet, err := identity.IsUserIdentitySet(repo) if err != nil { t.Fatalf("IsUserIdentitySet failed: %v", err) } if !isSet { t.Error("expected user identity to be set") }
// Verify refspecs were configured config, err := parseGitConfig(tmpDir) if err != nil { t.Fatalf("failed to parse git config: %v", err) }
originSection := `remote "origin"` if _, exists := config[originSection]; !exists { t.Fatal("origin remote not found in config") }
// Check fetch refspecs hasBugsFetch := false hasIdentitiesFetch := false for _, refspec := range config[originSection]["fetch"] { if refspec == "+refs/bugs/*:refs/remotes/origin/bugs/*" { hasBugsFetch = true } if refspec == "+refs/identities/*:refs/remotes/origin/identities/*" { hasIdentitiesFetch = true } } if !hasBugsFetch { t.Error("bugs fetch refspec not configured") } if !hasIdentitiesFetch { t.Error("identities fetch refspec not configured") }
// Check push refspecs hasBugsPush := false hasIdentitiesPush := false for _, refspec := range config[originSection]["push"] { if refspec == "+refs/bugs/*:refs/bugs/*" { hasBugsPush = true } if refspec == "+refs/identities/*:refs/identities/*" { hasIdentitiesPush = true } } if !hasBugsPush { t.Error("bugs push refspec not configured") } if !hasIdentitiesPush { t.Error("identities push refspec not configured") }}
// TestInitCommand_WithoutJJ tests init without jj config (interactive mode)func TestInitCommand_WithoutJJ(t *testing.T) { tmpDir := setupGitRepo(t)
// Simulate user input for interactive mode input := "Interactive User\ninteractive@example.com\n"
// Run init with simulated input err := runInitWithReader(tmpDir, strings.NewReader(input)) if err != nil { t.Fatalf("runInitWithReader failed: %v", err) }
// Verify identities were created repo, err := repository.OpenGoGitRepo(tmpDir, "", nil) if err != nil { t.Fatalf("failed to open repo: %v", err) } defer repo.Close()
ids, err := identity.ListLocalIds(repo) if err != nil { t.Fatalf("ListLocalIds failed: %v", err) }
// Should have at least 2 identities (user + agent) if len(ids) < 2 { t.Errorf("expected at least 2 identities, got %d", len(ids)) }
// Verify the user identity has the correct info isSet, err := identity.IsUserIdentitySet(repo) if err != nil { t.Fatalf("IsUserIdentitySet failed: %v", err) } if !isSet { t.Error("expected user identity to be set") }
userIdentity, err := identity.GetUserIdentity(repo) if err != nil { t.Fatalf("GetUserIdentity failed: %v", err) }
if userIdentity.Name() != "Interactive User" { t.Errorf("expected name 'Interactive User', got %q", userIdentity.Name()) }
if userIdentity.Email() != "interactive@example.com" { t.Errorf("expected email 'interactive@example.com', got %q", userIdentity.Email()) }}
// TestInitCommand_EmptyNameError tests that empty name is rejectedfunc TestInitCommand_EmptyNameError(t *testing.T) { tmpDir := setupGitRepo(t)
// Simulate empty name input input := "\n"
err := runInitWithReader(tmpDir, strings.NewReader(input)) if err == nil { t.Error("expected error for empty name, got nil") }
if !strings.Contains(err.Error(), "name cannot be empty") { t.Errorf("expected 'name cannot be empty' error, got: %v", err) }}
// TestInitCommand_NoOriginRemote tests that init fails without origin remotefunc TestInitCommand_NoOriginRemote(t *testing.T) { tmpDir := t.TempDir()
// Initialize a git repo WITHOUT origin remote initCmd := exec.Command("git", "init") initCmd.Dir = tmpDir if err := initCmd.Run(); err != nil { t.Fatalf("failed to init git repo: %v", err) }
// Configure git user exec.Command("git", "-C", tmpDir, "config", "user.email", "test@example.com").Run() exec.Command("git", "-C", tmpDir, "config", "user.name", "Test User").Run()
// Create jj config to avoid interactive mode jjDir := filepath.Join(tmpDir, ".jj") if err := os.MkdirAll(jjDir, 0755); err != nil { t.Fatalf("failed to create .jj directory: %v", err) } configContent := `[user]name = "JJ Test User"email = "jj-test@example.com"` configPath := filepath.Join(jjDir, "config.toml") if err := os.WriteFile(configPath, []byte(configContent), 0644); err != nil { t.Fatalf("failed to write jj config: %v", err) }
// Run init - should fail with ErrNoOriginRemote err := runInit(tmpDir) if err == nil { t.Fatal("expected error when no origin remote, got nil") }
// Check that it's the specific ErrNoOriginRemote type if _, ok := err.(ErrNoOriginRemote); !ok { t.Errorf("expected ErrNoOriginRemote, got: %T - %v", err, err) }}
// TestInitCommand_IdempotentIdentities tests that running init twice doesn't duplicate identitiesfunc TestInitCommand_IdempotentIdentities(t *testing.T) { tmpDir := setupGitRepo(t)
// Create jj config jjDir := filepath.Join(tmpDir, ".jj") if err := os.MkdirAll(jjDir, 0755); err != nil { t.Fatalf("failed to create .jj directory: %v", err) } configContent := `[user]name = "JJ Test User"email = "jj-test@example.com"` configPath := filepath.Join(jjDir, "config.toml") if err := os.WriteFile(configPath, []byte(configContent), 0644); err != nil { t.Fatalf("failed to write jj config: %v", err) }
// Run init first time err := runInit(tmpDir) if err != nil { t.Fatalf("first runInit failed: %v", err) }
// Count identities after first run repo, err := repository.OpenGoGitRepo(tmpDir, "", nil) if err != nil { t.Fatalf("failed to open repo: %v", err) }
ids1, err := identity.ListLocalIds(repo) if err != nil { t.Fatalf("ListLocalIds failed: %v", err) } repo.Close()
// Run init second time err = runInit(tmpDir) if err != nil { t.Fatalf("second runInit failed: %v", err) }
// Count identities after second run repo, err = repository.OpenGoGitRepo(tmpDir, "", nil) if err != nil { t.Fatalf("failed to open repo: %v", err) } defer repo.Close()
ids2, err := identity.ListLocalIds(repo) if err != nil { t.Fatalf("ListLocalIds failed: %v", err) }
// Should have same number of identities if len(ids1) != len(ids2) { t.Errorf("identities count changed after second init: first=%d, second=%d", len(ids1), len(ids2)) }
// Verify identities are the same idMap := make(map[string]bool) for _, id := range ids1 { idMap[id.String()] = true } for _, id := range ids2 { if !idMap[id.String()] { t.Errorf("new identity found after second init: %s", id.String()) } }}
// TestInitCommand_IdempotentRefspecs tests that running init twice doesn't duplicate refspecsfunc TestInitCommand_IdempotentRefspecs(t *testing.T) { tmpDir := setupGitRepo(t)
// Create jj config jjDir := filepath.Join(tmpDir, ".jj") if err := os.MkdirAll(jjDir, 0755); err != nil { t.Fatalf("failed to create .jj directory: %v", err) } configContent := `[user]name = "JJ Test User"email = "jj-test@example.com"` configPath := filepath.Join(jjDir, "config.toml") if err := os.WriteFile(configPath, []byte(configContent), 0644); err != nil { t.Fatalf("failed to write jj config: %v", err) }
// Run init first time err := runInit(tmpDir) if err != nil { t.Fatalf("first runInit failed: %v", err) }
// Get refspec count after first run config1, err := parseGitConfig(tmpDir) if err != nil { t.Fatalf("failed to parse git config: %v", err) }
originSection := `remote "origin"` fetchCount1 := len(config1[originSection]["fetch"]) pushCount1 := len(config1[originSection]["push"])
// Run init second time err = runInit(tmpDir) if err != nil { t.Fatalf("second runInit failed: %v", err) }
// Get refspec count after second run config2, err := parseGitConfig(tmpDir) if err != nil { t.Fatalf("failed to parse git config: %v", err) }
fetchCount2 := len(config2[originSection]["fetch"]) pushCount2 := len(config2[originSection]["push"])
// Should have same number of refspecs if fetchCount1 != fetchCount2 { t.Errorf("fetch refspecs count changed: first=%d, second=%d", fetchCount1, fetchCount2) } if pushCount1 != pushCount2 { t.Errorf("push refspecs count changed: first=%d, second=%d", pushCount1, pushCount2) }}