packages feed

mudbath-0.0.3: Notifications.hs

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards   #-}


module Notifications
    ( notifyDeploymentStatusChange
    ) where


import           Control.Monad
import           Control.Monad.Trans.Except
import qualified Control.Exception.Base      as CE

import           Data.Aeson
import           Data.Monoid
import           Data.Text (Text)
import qualified Data.Text                   as T

import           System.Environment (getEnv)

import           Network.HTTP.Conduit (RequestBody(..), Request(requestBody,requestHeaders,method), httpLbs, parseUrl, withManager)
import           Network.HTTP.Types.Method (methodPost)

import           GitHub.Types



-- | Send notification about the deployment status change to all configured
-- targets.
--
-- Configuration is done through environment variables. Currently supported
-- are:
--
--  * slack: SLACK_TEAM, SLACK_TOKEN

notifyDeploymentStatusChange :: DeploymentStatusEvent -> IO ()
notifyDeploymentStatusChange ev = do
    notifySlack ev



getEnvVar :: String -> IO (Either IOError String)
getEnvVar = CE.try . getEnv



------------------------------------------------------------------------------
-- Slack

data SlackMessage = SlackMessage { smText :: Text }

instance ToJSON SlackMessage where
    toJSON SlackMessage{..} = object [ "text" .= smText ]


notifySlack :: DeploymentStatusEvent -> IO ()
notifySlack ev = do
    mbConfig <- runExceptT $ do
        team  <- ExceptT $ getEnvVar "SLACK_TEAM"
        token <- ExceptT $ getEnvVar "SLACK_TOKEN"
        ExceptT $ return $ Right (team, token)

    case mbConfig of
        Left  _             -> return ()
        Right (team, token) -> sendRequest team token

  where
    ds         = deploymentStatusEventDeploymentStatus ev
    state      = deploymentStatusState           ds
    deployment = deploymentStatusEventDeployment ev
    repo       = deploymentStatusEventRepository ev

    repoOwner  = repositoryOwner repo
    repoName   = repositoryFullName repo

    userName   = ownerLogin repoOwner

    env        = deploymentEnvironment deployment

    sendRequest team token = do
        req <- parseUrl $ "https://" <> team <> ".slack.com/services/hooks/incoming-webhook?token=" <> token

        let msg = userName <> " is deploying " <> repoName <> " to " <> env
        let text = msg <> ": " <> T.pack (show state)

        let body = RequestBodyLBS $ encode $ SlackMessage text
        let contentType = ("Content-Type","application/json")
        let req' = req { Network.HTTP.Conduit.method = methodPost, requestBody = body, requestHeaders = contentType : requestHeaders req }

        void $ withManager $ httpLbs req'