{-# LANGUAGE QuasiQuotes #-}
module Main
where
import Control.Monad (unless, when)
import Data.Aeson (encode)
import qualified Data.ByteString.Lazy as BSL
import Data.List (find)
import Data.Maybe (isJust)
import Control.Concurrent (threadDelay)
import System.Console.Docopt
import System.Environment (getArgs, getEnv, getEnvironment)
import System.Exit (exitFailure)
import SHC.Api
import SHC.Coverage
import SHC.Stack
import SHC.Types
import SHC.Utils
urlApiV1 :: String
urlApiV1 = "https://coveralls.io/api/v1/jobs"
getServiceAndJobId :: IO (String, String)
getServiceAndJobId = do
env <- getEnvironment
case snd <$> find (isJust . flip lookup env . fst) ciEnvVars of
Just (ciName, jobIdVarName) -> do
jId <- getEnv jobIdVarName
return (ciName, jId)
_ -> error "Unsupported CI service."
where ciEnvVars = [
("GITHUB_ACTIONS", ("github-actions", "GITHUB_RUN_NUMBER")),
("TRAVIS", ("travis-ci", "TRAVIS_JOB_ID")),
("CIRCLECI", ("circleci", "CIRCLE_BUILD_NUM")),
("SEMAPHORE", ("semaphore", "REVISION")),
("JENKINS_URL", ("jenkins", "BUILD_ID")),
("CI_NAME", ("codeship", "CI_BUILD_NUMBER")),
("BUILDKITE", ("buildkite", "BUILDKITE_BUILD_NUMBER"))]
patterns :: Docopt
patterns = [docoptFile|USAGE.txt|]
getArgOrExit :: Arguments -> Option -> IO String
getArgOrExit = getArgOrExitWith patterns
defaultOr :: Arguments -> Option -> IO String -> IO String
defaultOr args opt action = maybe action return $ args `getArg` opt
getConfig :: Arguments -> IO Config
getConfig args = do
pn <- args `getArgOrExit` argument "package-name"
let suites = args `getAllArgs` argument "suite-name"
when (null suites) $
putStrLn "Error: provide at least one test-suite name" >> exitFailure
(sn, jId) <- getServiceAndJobId
Config pn suites sn jId (args `getArg` longOption "repo-token")
<$> getGitInfo
<*> defaultOr args (longOption "hpc-dir") (getHpcDir pn)
<*> pure (args `getArg` longOption "mix-dir")
<*> pure (if args `isPresent` longOption "partial-coverage"
then PartialLines
else FullLines)
<*> getStackProjects
<*> pure (args `isPresent` longOption "fetch-coverage")
main :: IO ()
main = do
args <- parseArgsOrExit patterns =<< getArgs
stackGood <- checkStackVersion
unless stackGood $ do
putStrLn "Error: at least Stack 0.1.7 is required"
exitFailure
conf <- getConfig args
coverallsJson <- generateCoverallsFromTix conf
if args `isPresent` longOption "dont-send"
then BSL.putStr $ encode coverallsJson
else do
response <- sendData conf urlApiV1 coverallsJson
case response of
PostSuccess u -> do
let apiUrl = u ++ ".json"
putStrLn $ "Job URL: " ++ apiUrl
when (fetchCoverage conf) $ do
-- wait 5 seconds until the page is available
threadDelay $ 5 * 1000 * 1000
coverageResult <- readCoverageResult apiUrl
case coverageResult of
Just totalCov -> putStrLn $ "Coverage: " ++ show totalCov
Nothing -> putStrLn "Failed to read total coverage"
PostFailure msg -> do
putStrLn $ "Error: " ++ msg
exitFailure