Files
converge/test/GitPullSpec.hs
T
jbrechtel 2f2cc16551 Log all git write operations with command, args, and exit code
- Add loggedGit helper that logs 'RUN: git -C <path> <args>' before
  execution and 'EXIT <code>' after (with stderr on failure)
- Refactor gitCommitAll, gitPull, and gitPush to use loggedGit
- Add Logger parameter to gitPull and gitPush
- Update test call sites and syncRepo to pass Logger
2026-05-13 22:19:44 -04:00

87 lines
4.0 KiB
Haskell

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)