packages feed

git-vogue-0.1.0.0: tests/git-setup.hs

--
-- Copyright © 2013-2015 Anchor Systems, Pty Ltd and Others
--
-- The code in this file, and the program it is a part of, is
-- made available to you by its authors as open source software:
-- you can redistribute it and/or modify it under the terms of
-- the 3-clause BSD licence.
--

{-# LANGUAGE FlexibleContexts      #-}
{-# LANGUAGE MultiParamTypeClasses #-}
-- | Description: Test git repository setup.
module Main where

import           Control.Exception
import           Control.Monad
import           Data.List
import           Data.Monoid
import           System.Directory
import           System.Exit
import           System.FilePath
import           System.Posix.Files
import           System.Posix.Temp
import           System.Process
import           Test.Hspec

import           Git.Vogue

main :: IO ()
main = hspec . describe "Git repository setup" $ do
    it "should install a new pre-commit hook" . withGitRepo $ \path -> do
            let hook = path </> ".git" </> "hooks" </> "pre-commit"

            shouldInstallWorking path hook

    it "should skip a correct pre-commit hook" . withGitRepo $ \path -> do
            let hook = path </> ".git" </> "hooks" </> "pre-commit"

            -- Create an existing hook to update.
            copyHookTemplateTo (Just "templates/pre-commit") hook

            shouldInstallWorking path hook

    it "should report a conflict pre-commit hook" . withGitRepo $ \path -> do
        let hook = path </> ".git" </> "hooks" </> "pre-commit"

        -- Create an existing hook to update.
        writeFile hook "echo YAY\n"
        setPermissions hook $ emptyPermissions
            { readable = True
            , executable = True
            }

        -- Run the setup program.
        code <- runInRepo path
        code `shouldBe` ExitFailure 1

-- | Run "git-vogue init" and check we wind up with a working pre-commit hook.
shouldInstallWorking :: FilePath -> FilePath -> IO ()
shouldInstallWorking path hook = do
    code <- runInRepo path
    code `shouldBe` ExitSuccess
    checkPreCommitHook hook

-- | Execute the setup command in a git repository.
runInRepo
    :: FilePath
    -> IO ExitCode
runInRepo path = do
    pwd <- getCurrentDirectory
    let exe = pwd </> "dist/build/git-vogue/git-vogue"
    let tpl = pwd </> "templates/pre-commit"
    ps <- spawnCommand $
        "cd " <> path <> " && " <> exe <> " init --template=" <> tpl
    waitForProcess ps

-- | Check that a pre-commit hook script is "correct".
checkPreCommitHook
    :: FilePath
    -> IO ()
checkPreCommitHook hook = do
    -- Check the hook exists.
    exists <- fileExist hook
    unless exists $ error "Commit hook missing"

    -- Check the hook is executable.
    perm <- getPermissions hook
    unless (executable perm) $ error "Commit hook is not executable"

    -- Check it has our command in it.
    content <- readFile hook
    unless ("git-vogue check" `isInfixOf` content) $
        error "Commit hook does not contain command"

-- | Create a git repository and run an action with it.
withGitRepo
    :: (FilePath -> IO ())
    -> IO ()
withGitRepo = bracket createRepo deleteRepo
  where
    createRepo = do
        path <- mkdtemp "/tmp/git-setup-test."
        callProcess "git" ["init", path]
        return path
    deleteRepo path =
        callProcess "rm" ["-rf", path]