module GitPullSpec (spec) where import Converge (RepoConfig (..), defaultRepoConfig, gitPull) import qualified Data.Text as T import System.Directory (createDirectory) import System.Exit (ExitCode (..)) import System.FilePath (()) import System.IO.Temp (withSystemTempDirectory) import Test.Hspec import TestHelper spec :: Spec spec = do describe "gitPull" $ do it "pulls changes from remote 'origin'" $ do logger <- testLogger withTempGitRepoWithRemote $ \local -> do -- Make a second commit on local and push to remote writeFile (local "upstream.txt") "pushed to remote" _ <- runGitIn local ["add", "upstream.txt"] _ <- runGitIn local ["commit", "-m", "second commit"] _ <- runGitIn local ["push", "origin", "main"] -- Rewind local to the initial commit (simulate being behind) _ <- runGitIn local ["reset", "--hard", "HEAD~1"] countBefore <- commitCount local countBefore `shouldBe` 1 let cfg = defaultRepoConfig{rcPath = local} (code, _, _) <- gitPull logger cfg code `shouldBe` ExitSuccess countAfter <- commitCount local countAfter `shouldBe` 2 it "rebases local commits on top of pulled changes" $ do logger <- testLogger withSystemTempDirectory "converge-test-rebase" $ \tmp -> do let remoteDir = tmp "remote.git" let localDir = tmp "local" -- Create directories before git init createDirectory remoteDir createDirectory localDir -- Create bare remote _ <- runGitIn remoteDir ["init", "--bare", "-b", "main"] -- Create local repo, push initial commit _ <- runGitIn localDir ["init", "-b", "main"] _ <- runGitIn localDir ["config", "user.name", "test"] _ <- runGitIn localDir ["config", "user.email", "test@test"] _ <- runGitIn localDir ["remote", "add", "origin", remoteDir] writeFile (localDir "initial.txt") "initial" _ <- runGitIn localDir ["add", "initial.txt"] _ <- runGitIn localDir ["commit", "-m", "initial commit"] _ <- runGitIn localDir ["push", "-u", "origin", "main"] -- Make a local-only commit (divergent from remote) writeFile (localDir "local.txt") "local-only change" _ <- runGitIn localDir ["add", "local.txt"] _ <- runGitIn localDir ["commit", "-m", "local commit"] -- Push a *different* commit to remote (from another clone) let otherDir = tmp "other" _ <- rawGit ["clone", remoteDir, otherDir] _ <- runGitIn otherDir ["config", "user.name", "test"] _ <- runGitIn otherDir ["config", "user.email", "test@test"] writeFile (otherDir "remote.txt") "remote-only change" _ <- runGitIn otherDir ["add", "remote.txt"] _ <- runGitIn otherDir ["commit", "-m", "remote commit"] _ <- runGitIn otherDir ["push", "origin", "main"] -- Pull with --rebase: local commits are rebased on top -- of the fetched remote commit, yielding a linear history. let cfg = defaultRepoConfig{rcPath = localDir} (code, _, _) <- gitPull logger cfg code `shouldBe` ExitSuccess -- Rebase produces linear history: 3 commits, no merge commit c <- commitCount localDir c `shouldBe` 3 -- Verify no merge commits exist (each commit has exactly 1 parent) (_, logOut, _) <- runGitIn localDir ["log", "--format=%P", "--all"] let parentCounts = map (length . words) (lines (T.unpack logOut)) parentCounts `shouldSatisfy` all (<= 1)