module GitCommitSpec (spec) where import Converge (Options (..), RepoConfig (..), defaultOptions, defaultRepoConfig, gitCommitAll, syncRepo) import qualified Data.Text as T import System.Exit (ExitCode (..)) import System.FilePath (()) import Test.Hspec import TestHelper spec :: Spec spec = do describe "gitCommitAll" $ do it "creates a commit after a file is changed" $ do logger <- testLogger withTempGitRepo $ \repo -> do countBefore <- commitCount repo countBefore `shouldBe` 1 -- initial commit from helper writeFile (repo "hello.txt") "hello world" (code, _, _) <- gitCommitAll logger repo code `shouldBe` ExitSuccess countAfter <- commitCount repo countAfter `shouldBe` (countBefore + 1) it "includes the changed file in the commit" $ do logger <- testLogger withTempGitRepo $ \repo -> do writeFile (repo "data.txt") "some data" (code, _, _) <- gitCommitAll logger repo code `shouldBe` ExitSuccess (_, logOut, _) <- runGitIn repo ["log", "-1", "--name-only", "--oneline"] logOut `shouldSatisfy` ("data.txt" `T.isInfixOf`) it "does not create a new commit when there are no changes" $ do logger <- testLogger withTempGitRepo $ \repo -> do countBefore <- commitCount repo (code, _, _) <- gitCommitAll logger repo -- git commit exits non-zero when there is nothing to commit code `shouldSatisfy` (/= ExitSuccess) countAfter <- commitCount repo countAfter `shouldBe` countBefore it "creates only one commit when called multiple times with the same staged changes" $ do logger <- testLogger withTempGitRepo $ \repo -> do writeFile (repo "single.txt") "single change" (code1, _, _) <- gitCommitAll logger repo code1 `shouldBe` ExitSuccess -- Second call: nothing left to commit countBefore2 <- commitCount repo (code2, _, _) <- gitCommitAll logger repo code2 `shouldSatisfy` (/= ExitSuccess) countAfter2 <- commitCount repo countAfter2 `shouldBe` countBefore2 it "aborts commit when staging fails (e.g. index.lock exists)" $ do logger <- testLogger withTempGitRepo $ \repo -> do -- Create a lock file to make git add -A fail writeFile (repo ".git" "index.lock") "locked" writeFile (repo "new.txt") "new file" countBefore <- commitCount repo (code, _, err) <- gitCommitAll logger repo -- Staging fails, so commit should not happen code `shouldSatisfy` (/= ExitSuccess) err `shouldSatisfy` ("index.lock" `T.isInfixOf`) commitCount repo `shouldReturn` countBefore describe "startup sync" $ do it "commits and pushes uncommitted changes on startup" $ do logger <- testLogger withTempGitRepoWithRemote $ \repo -> do -- Leave a file uncommitted (simulating state before converge starts) writeFile (repo "uncommitted.txt") "pending change" countBefore <- commitCount repo countBefore `shouldBe` 1 let cfg = defaultRepoConfig{rcPath = repo} let opts = defaultOptions { optRepos = [cfg] , optNotifyCmd = "true" -- avoid firing notify-send } syncRepo opts logger cfg countAfter <- commitCount repo countAfter `shouldBe` 2 -- Verify the commit was pushed to remote (_, remoteLog, _) <- runGitIn repo ["log", "origin/main", "--oneline", "--name-only"] remoteLog `shouldSatisfy` ("uncommitted.txt" `T.isInfixOf`)