1- module Test.Spago.Install where
1+ module Test.Spago.Install
2+ ( spec
3+ , forceResetSpec
4+ ) where
25
36import Test.Prelude
47
@@ -7,9 +10,11 @@ import Data.Map as Map
710import Effect.Now as Now
811import Registry.Version as Version
912import Spago.Command.Init as Init
13+ import Spago.Cmd as Cmd
1014import Spago.Core.Config (Dependencies (..), Config )
1115import Spago.Core.Config as Config
1216import Spago.FS as FS
17+ import Spago.Git as Git
1318import Spago.Log (LogVerbosity (..))
1419import Spago.Path as Path
1520import Spago.Paths as Paths
@@ -302,3 +307,82 @@ writeConfigWithEither root = do
302307 )
303308 }
304309 )
310+
311+ -- | Test that fetchRepo handles git history rewrites (squash) gracefully
312+ -- This verifies that git pull --rebase works even when the remote history is squashed,
313+ -- as long as the content is the same. This is important for the registry repo.
314+ forceResetSpec :: Spec Unit
315+ forceResetSpec = Spec .around withTempDir do
316+ Spec .describe " git fetchRepo" do
317+ Spec .it " handles history rewrite (squash) gracefully" \{ testCwd } -> do
318+ -- Setup logging
319+ startingTime <- liftEffect $ Now .now
320+ let logOptions = { color: false , verbosity: LogQuiet , startingTime }
321+
322+ -- Get git command
323+ gitCmd <- runSpago { logOptions } Git .getGit
324+
325+ -- Build GitEnv
326+ let gitEnv = { git: gitCmd, logOptions, offline: Online }
327+
328+ -- 1. Create a bare "origin" repo
329+ let originRepo = testCwd </> " origin"
330+ FS .mkdirp originRepo
331+ git' (Just $ Path .toGlobal originRepo) [ " init" , " --bare" ]
332+
333+ -- 2. Clone, make commits, push
334+ let workRepo = testCwd </> " work"
335+ let gitInWorkRepo = git' (Just $ Path .toGlobal workRepo)
336+ git [ " clone" , Path .toRaw originRepo, Path .toRaw workRepo ]
337+ gitInWorkRepo [ " config" , " user.name" , " test" ]
338+ gitInWorkRepo [ " config" , " user.email" , " test@test.com" ]
339+ gitInWorkRepo [ " checkout" , " -b" , " main" ]
340+ FS .writeTextFile (workRepo </> " file1.txt" ) " content1"
341+ gitInWorkRepo [ " add" , " ." ]
342+ gitInWorkRepo [ " commit" , " -m" , " first" ]
343+ FS .writeTextFile (workRepo </> " file2.txt" ) " content2"
344+ gitInWorkRepo [ " add" , " ." ]
345+ gitInWorkRepo [ " commit" , " -m" , " second" ]
346+ gitInWorkRepo [ " push" , " -u" , " origin" , " main" ]
347+
348+ -- 3. Clone again (simulating spago's cached registry)
349+ let cachedRepo = testCwd </> " cached"
350+ git [ " clone" , Path .toRaw originRepo, Path .toRaw cachedRepo ]
351+
352+ -- 4. Add another commit to origin that modifies an existing file
353+ -- Now cached is behind and has different content
354+ FS .writeTextFile (workRepo </> " file2.txt" ) " content2-updated"
355+ gitInWorkRepo [ " add" , " ." ]
356+ gitInWorkRepo [ " commit" , " -m" , " third" ]
357+ gitInWorkRepo [ " push" , " origin" , " main" ]
358+
359+ -- 5. Squash all history and force push (simulating registry squash)
360+ -- Now origin has: first -> second -> third (with updated file2), squashed to single commit
361+ -- But cached only has: first -> second (with original file2)
362+ gitInWorkRepo [ " reset" , " --soft" , " HEAD~2" ]
363+ gitInWorkRepo [ " commit" , " --amend" , " -m" , " squashed all history" ]
364+ gitInWorkRepo [ " push" , " --force" , " origin" , " main" ]
365+
366+ -- 6. fetchRepo should succeed despite the history rewrite and different content
367+ -- because git pull --rebase can handle rebasing onto a squashed history
368+ result <- runSpago gitEnv $ Git .fetchRepo
369+ { git: Path .toRaw originRepo, ref: " main" }
370+ cachedRepo
371+ case result of
372+ Left err -> Assert .fail $ " Expected fetchRepo to succeed after history squash, but got: " <> show err
373+ Right _ -> pure unit
374+
375+ -- 7. Verify the content is updated correctly
376+ content1 <- FS .readTextFile (cachedRepo </> " file1.txt" )
377+ content1 `shouldEqualStr` " content1"
378+ content2 <- FS .readTextFile (cachedRepo </> " file2.txt" )
379+ content2 `shouldEqualStr` " content2-updated"
380+
381+ git :: Array String -> Aff Unit
382+ git = git' Nothing
383+
384+ git' :: Maybe GlobalPath -> Array String -> Aff Unit
385+ git' cwd args =
386+ Cmd .exec (Path .global " git" ) args
387+ (Cmd .defaultExecOptions { pipeStdout = false , pipeStderr = false , pipeStdin = StdinNewPipe , cwd = cwd })
388+ >>= shouldBeSuccess
0 commit comments