@@ -106,6 +106,87 @@ esac
106106 t .Setenv ("PATH" , binDir + string (os .PathListSeparator )+ os .Getenv ("PATH" ))
107107}
108108
109+ func setupCanonicalBranchManagerTest (t * testing.T ) (* Manager , string ) {
110+ t .Helper ()
111+ installMockBd (t )
112+
113+ root := t .TempDir ()
114+ mayorRig := filepath .Join (root , "mayor" , "rig" )
115+ if err := os .MkdirAll (mayorRig , 0755 ); err != nil {
116+ t .Fatalf ("mkdir mayor/rig: %v" , err )
117+ }
118+
119+ rigBeads := filepath .Join (root , ".beads" )
120+ if err := os .MkdirAll (rigBeads , 0755 ); err != nil {
121+ t .Fatalf ("mkdir rig .beads: %v" , err )
122+ }
123+ mayorBeads := filepath .Join (mayorRig , ".beads" )
124+ if err := os .MkdirAll (mayorBeads , 0755 ); err != nil {
125+ t .Fatalf ("mkdir mayor/rig/.beads: %v" , err )
126+ }
127+ if err := os .WriteFile (filepath .Join (rigBeads , "redirect" ), []byte ("mayor/rig/.beads\n " ), 0644 ); err != nil {
128+ t .Fatalf ("write rig redirect: %v" , err )
129+ }
130+
131+ cmd := exec .Command ("git" , "init" , "-b" , "main" )
132+ cmd .Dir = mayorRig
133+ if out , err := cmd .CombinedOutput (); err != nil {
134+ t .Fatalf ("git init: %v\n %s" , err , out )
135+ }
136+
137+ readmePath := filepath .Join (mayorRig , "README.md" )
138+ if err := os .WriteFile (readmePath , []byte ("# Test\n " ), 0644 ); err != nil {
139+ t .Fatalf ("write README.md: %v" , err )
140+ }
141+ mayorGit := git .NewGit (mayorRig )
142+ if err := mayorGit .Add ("README.md" ); err != nil {
143+ t .Fatalf ("git add: %v" , err )
144+ }
145+ if err := mayorGit .Commit ("Initial commit" ); err != nil {
146+ t .Fatalf ("git commit: %v" , err )
147+ }
148+
149+ cmd = exec .Command ("git" , "remote" , "add" , "origin" , mayorRig )
150+ cmd .Dir = mayorRig
151+ if out , err := cmd .CombinedOutput (); err != nil {
152+ t .Fatalf ("git remote add: %v\n %s" , err , out )
153+ }
154+ cmd = exec .Command ("git" , "update-ref" , "refs/remotes/origin/main" , "HEAD" )
155+ cmd .Dir = mayorRig
156+ if out , err := cmd .CombinedOutput (); err != nil {
157+ t .Fatalf ("git update-ref: %v\n %s" , err , out )
158+ }
159+
160+ r := & rig.Rig {Name : "rig" , Path : root }
161+ return NewManager (r , git .NewGit (root ), nil ), mayorRig
162+ }
163+
164+ func createStalePolecatCommit (t * testing.T , repoPath , startPoint , branchName string ) string {
165+ t .Helper ()
166+
167+ repoGit := git .NewGit (repoPath )
168+ if err := repoGit .CheckoutNewBranch (branchName , startPoint ); err != nil {
169+ t .Fatalf ("checkout stale branch %s from %s: %v" , branchName , startPoint , err )
170+ }
171+
172+ fileName := strings .NewReplacer ("/" , "-" , "@" , "-" ).Replace (branchName ) + ".txt"
173+ if err := os .WriteFile (filepath .Join (repoPath , fileName ), []byte (branchName + "\n " ), 0644 ); err != nil {
174+ t .Fatalf ("write stale branch marker: %v" , err )
175+ }
176+ if err := repoGit .Add (fileName ); err != nil {
177+ t .Fatalf ("git add stale branch marker: %v" , err )
178+ }
179+ if err := repoGit .Commit ("Create stale polecat branch" ); err != nil {
180+ t .Fatalf ("git commit stale branch marker: %v" , err )
181+ }
182+
183+ sha , err := repoGit .Rev ("HEAD" )
184+ if err != nil {
185+ t .Fatalf ("resolve stale branch commit: %v" , err )
186+ }
187+ return sha
188+ }
189+
109190func TestStateIsWorking (t * testing.T ) {
110191 tests := []struct {
111192 state State
@@ -1071,6 +1152,78 @@ func TestAddWithOptions_NoPrimeMDCreatedLocally(t *testing.T) {
10711152 }
10721153}
10731154
1155+ func TestAddWithOptions_UsesCanonicalOriginDefaultBranch (t * testing.T ) {
1156+ mgr , mayorRig := setupCanonicalBranchManagerTest (t )
1157+
1158+ mayorGit := git .NewGit (mayorRig )
1159+ baseSHA , err := mayorGit .Rev ("origin/main" )
1160+ if err != nil {
1161+ t .Fatalf ("resolve origin/main: %v" , err )
1162+ }
1163+ staleSHA := createStalePolecatCommit (t , mayorRig , "main" , "polecat/stale-source" )
1164+
1165+ polecat , err := mgr .AddWithOptions ("toast" , AddOptions {})
1166+ if err != nil {
1167+ t .Fatalf ("AddWithOptions: %v" , err )
1168+ }
1169+
1170+ worktreeGit := git .NewGit (polecat .ClonePath )
1171+ staleAncestor , err := worktreeGit .IsAncestor (staleSHA , polecat .Branch )
1172+ if err != nil {
1173+ t .Fatalf ("check stale ancestry: %v" , err )
1174+ }
1175+ if staleAncestor {
1176+ t .Fatalf ("new polecat branch %q unexpectedly includes stale local commit %s" , polecat .Branch , staleSHA )
1177+ }
1178+
1179+ baseAncestor , err := worktreeGit .IsAncestor (baseSHA , polecat .Branch )
1180+ if err != nil {
1181+ t .Fatalf ("check canonical ancestry: %v" , err )
1182+ }
1183+ if ! baseAncestor {
1184+ t .Fatalf ("new polecat branch %q should descend from origin/main commit %s" , polecat .Branch , baseSHA )
1185+ }
1186+ }
1187+
1188+ func TestReuseIdlePolecat_UsesCanonicalOriginDefaultBranch (t * testing.T ) {
1189+ mgr , mayorRig := setupCanonicalBranchManagerTest (t )
1190+
1191+ mayorGit := git .NewGit (mayorRig )
1192+ baseSHA , err := mayorGit .Rev ("origin/main" )
1193+ if err != nil {
1194+ t .Fatalf ("resolve origin/main: %v" , err )
1195+ }
1196+
1197+ polecat , err := mgr .AddWithOptions ("toast" , AddOptions {})
1198+ if err != nil {
1199+ t .Fatalf ("AddWithOptions: %v" , err )
1200+ }
1201+
1202+ staleSHA := createStalePolecatCommit (t , polecat .ClonePath , "HEAD" , "polecat/toast-stale" )
1203+
1204+ reused , err := mgr .ReuseIdlePolecat ("toast" , AddOptions {HookBead : "gt-next" })
1205+ if err != nil {
1206+ t .Fatalf ("ReuseIdlePolecat: %v" , err )
1207+ }
1208+
1209+ worktreeGit := git .NewGit (reused .ClonePath )
1210+ staleAncestor , err := worktreeGit .IsAncestor (staleSHA , reused .Branch )
1211+ if err != nil {
1212+ t .Fatalf ("check stale ancestry: %v" , err )
1213+ }
1214+ if staleAncestor {
1215+ t .Fatalf ("reused polecat branch %q unexpectedly includes stale local commit %s" , reused .Branch , staleSHA )
1216+ }
1217+
1218+ baseAncestor , err := worktreeGit .IsAncestor (baseSHA , reused .Branch )
1219+ if err != nil {
1220+ t .Fatalf ("check canonical ancestry: %v" , err )
1221+ }
1222+ if ! baseAncestor {
1223+ t .Fatalf ("reused polecat branch %q should descend from origin/main commit %s" , reused .Branch , baseSHA )
1224+ }
1225+ }
1226+
10741227func TestAddWithOptions_NoFilesAddedToRepo (t * testing.T ) {
10751228 // This test verifies the invariant that polecat creation does NOT add any
10761229 // TRACKED files to the repo's directory structure. The user's code should stay pure.
0 commit comments