rollbar-client-0.1.0: src/Rollbar/Client/Settings.hs
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE OverloadedStrings #-}
module Rollbar.Client.Settings
( HasSettings(..)
, Settings(..)
, readSettings
, Token(..)
, Environment(..)
, Revision(..)
, getRevision
, getRevisionMaybe
, RequestModifiers(..)
, defaultRequestModifiers
) where
import qualified Data.Text as T
import qualified Data.Text.Encoding as T
import Control.Exception (Exception, throwIO)
import Control.Monad (forM)
import Control.Monad.IO.Class (MonadIO(..))
import Data.Aeson
import Data.ByteString (ByteString)
import Data.List.NonEmpty
import Data.Text (Text)
import Data.Yaml.Config (loadYamlSettings, requireEnv)
import System.Directory (findExecutable)
import System.Process
-- | Typeclass used to pull Rollbar 'Settings' out of a given 'Monad'.
class HasSettings m where
getSettings :: m Settings
-- | General settings required to interact with Rollbar API.
data Settings = Settings
{ settingsToken :: Token
-- ^ Rollbar API authentication token.
, settingsEnvironment :: Environment
-- ^ Environment to which the revision was deployed.
, settingsRevision :: Maybe Revision
-- ^ Git SHA of revision being deployed.
, settingsRequestModifiers :: RequestModifiers
} deriving (Eq, Show)
instance FromJSON Settings where
parseJSON = withObject "Settings" $ \o ->
Settings <$> o .: "token"
<*> o .: "environment"
<*> o .:? "revision" .!= Nothing
<*> o .:? "request_modifiers" .!= defaultRequestModifiers
-- | Reads 'Settings' from a YAML file.
readSettings :: MonadIO m => FilePath -> m Settings
readSettings path = liftIO $ loadYamlSettings [path] [] requireEnv
newtype Token = Token ByteString
deriving (Eq, Show)
instance FromJSON Token where
parseJSON = withText "Token" $ pure . Token . T.encodeUtf8
-- | Environment to which the revision was deployed.
newtype Environment = Environment Text
deriving (Eq, FromJSON, Show, ToJSON)
-- | Git SHA of revision being deployed.
newtype Revision = Revision Text
deriving (Eq, FromJSON, Show, ToJSON)
-- | Similar to 'getRevisionMaybe', but it throws a 'RevisionNotFound' if the
-- 'Revision' is not found.
getRevision
:: (HasSettings m, MonadIO m)
=> m Revision
getRevision = do
mrevision <- getRevisionMaybe
case mrevision of
Nothing -> liftIO $ throwIO RevisionNotFound
Just revision -> return revision
-- | Gets the 'Revision' from 'Settings' (if the value is present), otherwise
-- gets the 'Revision' from @git@ (if the executable is present) directly
-- by running the following command @git rev-parse HEAD@, if none of them are
-- present (neither the value nor the executable) returns 'Nothing'.
getRevisionMaybe
:: (HasSettings m, MonadIO m)
=> m (Maybe Revision)
getRevisionMaybe = do
mrevision <- settingsRevision <$> getSettings
case mrevision of
Nothing -> do
mgitPath <- liftIO $ findExecutable "git"
forM mgitPath $ \gitPath ->
mkRevision <$> liftIO (readProcess gitPath ["rev-parse", "HEAD"] "")
Just revision -> return $ Just revision
where
mkRevision = Revision . T.stripEnd . T.pack
-- | Represents a list of 'Request' modifiers that are combined by
-- 'getRequestModifier' into a single function.
data RequestModifiers = RequestModifiers
{ requestModifiersExcludeHeaders :: Maybe (NonEmpty Text)
-- ^ A list of 'Request' header names to be excluded.
, requestModifiersExcludeParams :: Maybe (NonEmpty Text)
-- ^ A list of 'Request' param names to be excluded.
, requestModifiersIncludeHeaders :: Maybe (NonEmpty Text)
-- ^ A list of 'Request' header names to be included.
, requestModifiersIncludeParams :: Maybe (NonEmpty Text)
-- ^ A list of 'Request' params names to be included.
} deriving (Eq, Show)
instance FromJSON RequestModifiers where
parseJSON = withObject "RequestModifiers" $ \o ->
RequestModifiers <$> o .:? "exclude_headers" .!= Nothing
<*> o .:? "exclude_params" .!= Nothing
<*> o .:? "include_headers" .!= Nothing
<*> o .:? "include_params" .!= Nothing
-- | Returns an empty 'RequestModifiers', the function produced by
-- 'getRequestModifier' given this values is equivalent to 'id'.
defaultRequestModifiers :: RequestModifiers
defaultRequestModifiers = RequestModifiers
{ requestModifiersExcludeHeaders = Nothing
, requestModifiersExcludeParams = Nothing
, requestModifiersIncludeHeaders = Nothing
, requestModifiersIncludeParams = Nothing
}
data RollbarError = RevisionNotFound
deriving (Eq, Show)
instance Exception RollbarError