-- | This module contains the gerrit client library
module Gerrit
  ( -- * Client
    GerritClient,
    withClient,

    -- * Api
    getVersion,
    queryChanges,
    postReview,

    -- * Main data types
    GerritVersion (..),
    GerritQuery (..),
    GerritChange (..),
    GerritChangeStatus (..),
    ReviewResult (..),

    -- * Convenient functions
    changeUrl,
    hasLabel,
  )
where

import qualified Data.Map as M
import Data.Maybe (fromMaybe)
import Data.Text (Text)
import qualified Data.Text as T
import Gerrit.Client
import Gerrit.Data

-- | Return the url of a 'GerritChange'
changeUrl :: GerritClient -> GerritChange -> T.Text
changeUrl :: GerritClient -> GerritChange -> Text
changeUrl client :: GerritClient
client change :: GerritChange
change = GerritClient -> Text
baseUrl GerritClient
client Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> String -> Text
T.pack (Int -> String
forall a. Show a => a -> String
show (GerritChange -> Int
number GerritChange
change))

-- | Get the server version
getVersion :: GerritClient -> IO GerritVersion
getVersion :: GerritClient -> IO GerritVersion
getVersion = Text -> GerritClient -> IO GerritVersion
forall a. FromJSON a => Text -> GerritClient -> IO a
gerritGet "config/server/version"

-- | Search for changes
queryChanges :: [GerritQuery] -> GerritClient -> IO [GerritChange]
queryChanges :: [GerritQuery] -> GerritClient -> IO [GerritChange]
queryChanges queries :: [GerritQuery]
queries = Text -> GerritClient -> IO [GerritChange]
forall a. FromJSON a => Text -> GerritClient -> IO a
gerritGet ("changes/?" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
queryString)
  where
    count :: Integer
    count :: Integer
count = 2
    queryString :: Text
queryString = Text -> [Text] -> Text
T.intercalate "&" [Text
changeString, Text
countString, Text
option]
    changeString :: Text
changeString = "q=" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> [Text] -> Text
T.intercalate "+" ((GerritQuery -> Text) -> [GerritQuery] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
map GerritQuery -> Text
queryText [GerritQuery]
queries)
    countString :: Text
countString = "n=" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> String -> Text
T.pack (Integer -> String
forall a. Show a => a -> String
show Integer
count)
    option :: Text
option = "o=CURRENT_REVISION&o=DETAILED_LABELS"

-- | Post a review
postReview ::
  -- | The change to review
  GerritChange ->
  -- | A message
  Text ->
  -- | A label
  Text ->
  -- | A vote
  Int ->
  -- | The client
  GerritClient ->
  -- | Returns the ReviewResult
  IO ReviewResult
postReview :: GerritChange
-> Text -> Text -> Int -> GerritClient -> IO ReviewResult
postReview change :: GerritChange
change message :: Text
message label :: Text
label value :: Int
value client :: GerritClient
client =
  do
    ReviewResult
res <- Text -> ReviewInput -> GerritClient -> IO ReviewResult
forall a b.
(ToJSON a, FromJSON b) =>
Text -> a -> GerritClient -> IO b
gerritPost Text
urlPath ReviewInput
review GerritClient
client
    -- TODO: verify ReviewResult is correct
    ReviewResult -> IO ()
forall a. Show a => a -> IO ()
print ReviewResult
res
    ReviewResult -> IO ReviewResult
forall (f :: * -> *) a. Applicative f => a -> f a
pure ReviewResult
res
  where
    urlPath :: Text
urlPath = "changes/" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
changeId Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> "/revisions/" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
revHash Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> "/review"
    changeId :: Text
changeId = GerritChange -> Text
Gerrit.Data.id GerritChange
change
    revHash :: Text
revHash = Text -> Maybe Text -> Text
forall a. a -> Maybe a -> a
fromMaybe "" (GerritChange -> Maybe Text
Gerrit.Data.current_revision GerritChange
change)
    review :: ReviewInput
review =
      ReviewInput :: Maybe Text -> Maybe (Map Text Int) -> ReviewInput
ReviewInput
        { riMessage :: Maybe Text
riMessage = Text -> Maybe Text
forall a. a -> Maybe a
Just Text
message,
          riLabels :: Maybe (Map Text Int)
riLabels = Map Text Int -> Maybe (Map Text Int)
forall a. a -> Maybe a
Just ([(Text, Int)] -> Map Text Int
forall k a. Ord k => [(k, a)] -> Map k a
M.fromList [(Text
label, Int
value)])
        }

-- | Check if a gerrit change as a label
hasLabel :: T.Text -> Int -> GerritChange -> Bool
hasLabel :: Text -> Int -> GerritChange -> Bool
hasLabel label :: Text
label labelValue :: Int
labelValue change :: GerritChange
change = case Text -> Map Text GerritDetailedLabel -> Maybe GerritDetailedLabel
forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup Text
label (GerritChange -> Map Text GerritDetailedLabel
labels GerritChange
change) of
  Just gerritLabel :: GerritDetailedLabel
gerritLabel -> (Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> 0) (Int -> Bool) -> Int -> Bool
forall a b. (a -> b) -> a -> b
$ [GerritDetailedLabelVote] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length ([GerritDetailedLabelVote] -> Int)
-> [GerritDetailedLabelVote] -> Int
forall a b. (a -> b) -> a -> b
$ (GerritDetailedLabelVote -> Bool)
-> [GerritDetailedLabelVote] -> [GerritDetailedLabelVote]
forall a. (a -> Bool) -> [a] -> [a]
filter (\vote :: GerritDetailedLabelVote
vote -> Int -> Maybe Int -> Int
forall a. a -> Maybe a -> a
fromMaybe 0 (GerritDetailedLabelVote -> Maybe Int
value GerritDetailedLabelVote
vote) Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
labelValue) (GerritDetailedLabel -> [GerritDetailedLabelVote]
Gerrit.Data.all GerritDetailedLabel
gerritLabel)
  _ -> Bool
False