Skip to content
Snippets Groups Projects
Commit 89e5d59e authored by Eduardo Trujillo's avatar Eduardo Trujillo
Browse files

feat(Rendering): Render to an cmark tree before printing

parent ffdb6152
No related branches found
No related tags found
No related merge requests found
...@@ -47,6 +47,7 @@ library ...@@ -47,6 +47,7 @@ library
, vector , vector
, exceptions , exceptions
, semigroups , semigroups
, cmark-gfm
default-language: Haskell2010 default-language: Haskell2010
executable shift executable shift
......
...@@ -14,8 +14,15 @@ import qualified Data.ByteString.Char8 as BS ...@@ -14,8 +14,15 @@ import qualified Data.ByteString.Char8 as BS
import Data.Default (def) import Data.Default (def)
import Data.Either (rights) import Data.Either (rights)
import Data.Git import Data.Git
( tagList,
getObject,
withRepo,
RefName(refNameRaw),
Ref,
Git,
Commit(commitMessage) )
import Data.Git.Ref (HashAlgorithm, fromHex, isHex) import Data.Git.Ref (HashAlgorithm, fromHex, isHex)
import Data.Git.Storage.Object import Data.Git.Storage.Object ( Object(ObjCommit) )
import Data.List (sortBy) import Data.List (sortBy)
import Data.Maybe (catMaybes) import Data.Maybe (catMaybes)
import Data.Set as S (toList) import Data.Set as S (toList)
...@@ -30,13 +37,14 @@ import GitHub.Auth (Auth (OAuth)) ...@@ -30,13 +37,14 @@ import GitHub.Auth (Auth (OAuth))
import Network.HTTP.Client (newManager) import Network.HTTP.Client (newManager)
import Network.HTTP.Client.TLS (tlsManagerSettings) import Network.HTTP.Client.TLS (tlsManagerSettings)
import Shift.CLI import Shift.CLI
import Shift.Processing import Shift.Processing ( generateReport, parseCommit )
import Shift.Rendering import Shift.Rendering ( printReport )
import Shift.Types import Shift.Types
import Shift.Utilities (orError, pairs) import Shift.Utilities (orError, pairs)
import System.Process import System.Process ( readCreateProcess, shell )
import Text.Megaparsec (ParseError) import Text.Megaparsec (ParseError)
import Text.Megaparsec.Error (ParseErrorBundle) import Text.Megaparsec.Error (ParseErrorBundle)
import CMarkGFM (NodeType(DOCUMENT), NodeType(DOCUMENT), nodeToCommonmark, nodeToCommonmark, Node(Node))
parseTag :: RefName -> Either (ParseErrorBundle Text Void) TagRef parseTag :: RefName -> Either (ParseErrorBundle Text Void) TagRef
parseTag ref = case versioning . cs . refNameRaw $ ref of parseTag ref = case versioning . cs . refNameRaw $ ref of
...@@ -44,23 +52,31 @@ parseTag ref = case versioning . cs . refNameRaw $ ref of ...@@ -44,23 +52,31 @@ parseTag ref = case versioning . cs . refNameRaw $ ref of
Right v -> Right (TagRef ref v) Right v -> Right (TagRef ref v)
tempMain :: ShiftOptions -> IO () tempMain :: ShiftOptions -> IO ()
tempMain opts = withRepo ".git" $ \repo -> do tempMain opts = do
node <- renderToNode opts
liftIO $ TIO.putStr $ nodeToCommonmark [] Nothing node
renderToNode :: ShiftOptions -> IO Node
renderToNode opts = withRepo ".git" $ \repo -> do
tags <- tagList repo tags <- tagList repo
let sortedVersions = sortBy (flip compare) . rights $ parseTag <$> toList tags let sortedVersions = sortBy (flip compare) . rights $ parseTag <$> toList tags
pairedTags = swap <$> pairs sortedVersions pairedTags = swap <$> pairs sortedVersions
case opts ^. soHostingType of nodes <- case opts ^. soHostingType of
GitHubType -> do GitHubType -> do
state <- initGitHubState state <- initGitHubState
runReaderT fst <$> runReaderT
(void $ runStateT (mapM_ (renderDiff repo) pairedTags) state) (runStateT (mapM (renderDiff repo) pairedTags) state)
opts opts
GitType -> GitType ->
runReaderT fst <$> runReaderT
(void $ runStateT (mapM_ (renderDiff repo) pairedTags) GitClientState) (runStateT (mapM (renderDiff repo) pairedTags) GitClientState)
opts opts
pure (Node Nothing DOCUMENT (concat nodes))
where where
initGitHubState = do initGitHubState = do
manager <- newManager tlsManagerSettings manager <- newManager tlsManagerSettings
...@@ -80,15 +96,13 @@ tempMain opts = withRepo ".git" $ \repo -> do ...@@ -80,15 +96,13 @@ tempMain opts = withRepo ".git" $ \repo -> do
_gcsRepository = cs repositoryName _gcsRepository = cs repositoryName
} }
renderDiff :: (ClientState s, HashAlgorithm hash) => Git hash -> (TagRef, TagRef) -> GitM s () renderDiff :: (ClientState s, HashAlgorithm hash) => Git hash -> (TagRef, TagRef) -> GitM s [Node]
renderDiff repo (tx, ty) = do renderDiff repo (tx, ty) = do
liftIO . TIO.putStrLn . headerOne $ renderRange tx ty
diff <- lookupCommitsDiff repo tx ty diff <- lookupCommitsDiff repo tx ty
case diff of case diff of
[] -> throwM SEUnableToComputeDiff [] -> throwM SEUnableToComputeDiff
diff_ -> printReport (generateReport . rights $ parseCommit <$> diff_) diff_ -> printReport (tx, ty) (generateReport . rights $ parseCommit <$> diff_)
lookupCommitsDiff :: (HashAlgorithm hash) => Git hash -> TagRef -> TagRef -> GitM s [(Ref hash, Commit hash)] lookupCommitsDiff :: (HashAlgorithm hash) => Git hash -> TagRef -> TagRef -> GitM s [(Ref hash, Commit hash)]
lookupCommitsDiff repo x y = do lookupCommitsDiff repo x y = do
......
{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE OverloadedStrings #-}
module Shift.Rendering where module Shift.Rendering where
import CMarkGFM as M
import Control.Lens ((^.))
import Control.Monad.Catch (MonadThrow)
import Control.Monad.IO.Class (MonadIO, liftIO)
import Control.Monad.State (MonadState)
import Control.Monad.Trans.Writer (WriterT (runWriterT), execWriterT, runWriter)
import Control.Monad.Trans.Writer.Lazy (tell)
import Data.Git (Commit, Ref, commitAuthor)
import Data.List (sortOn) import Data.List (sortOn)
import Data.Maybe (catMaybes)
import Control.Lens ((^.)) import Data.Monoid ((<>))
import Control.Monad.Catch (MonadThrow) import Data.String.Conversions (cs)
import Control.Monad.IO.Class (MonadIO, liftIO) import Data.Text (Text)
import Control.Monad.State (MonadState) import qualified Data.Text as T (take)
import Data.Git (Commit, Ref, commitAuthor) import qualified Data.Text.IO as TIO (putStr, putStrLn)
import Data.Monoid ((<>)) import Data.Versions (prettyV)
import Data.String.Conversions (cs)
import Data.Text (Text)
import qualified Data.Text as T (take)
import qualified Data.Text.IO as TIO (putStrLn)
import Data.Versions (prettyV)
import Shift.Types import Shift.Types
renderRef renderRef ::
:: (MonadIO m, MonadState s m, ClientState s, MonadThrow m) (MonadIO m, MonadState s m, ClientState s, MonadThrow m) =>
=> Ref hash Ref hash ->
-> m Text m [Node]
renderRef ref = do renderRef ref = do
url <- getRefURL ref url <- getRefURL ref
let shortRef = T.take 7 . cs . show $ ref let shortRef = T.take 7 . cs . show $ ref
let shortRefNode = leafNode (CODE shortRef)
pure $ case url of pure $ case url of
Just url_ -> "[[`" <> shortRef <> "`](" <> url_ <> ")]" Just url_ -> [textNode "[", parentNode (LINK url_ shortRef) [shortRefNode], textNode "]"]
Nothing -> "[`" <> shortRef <> "`]" Nothing -> [textNode "[", shortRefNode, textNode "]"]
renderConventionalCommit renderConventionalCommit ::
:: (MonadIO m, MonadState s m, ClientState s, MonadThrow m) (MonadIO m, MonadState s m, ClientState s, MonadThrow m) =>
=> ConventionalGroup hash ConventionalGroup hash ->
-> m Text m Node
renderConventionalCommit (ref, commit, pc) = do renderConventionalCommit (ref, commit, pc) = do
renderedRef <- renderRef ref renderedRef <- renderRef ref
authorText <- renderAuthor commit ref authorText <- renderAuthor commit ref
pure . mconcat $ pure $
[ "- " listItemNode
, renderedRef [ paragraphNode $
, " " renderedRef
, bold $ pc ^. ccScope <> ":" <> catMaybes
, " " [ Just $ textNode " ",
, pc ^. ccSubject Just . bold $ pc ^. ccScope <> ":",
, authorText Just $ textNode " ",
] Just . textNode $ pc ^. ccSubject,
Just $ textNode " ",
renderAuthor authorText
:: (MonadIO m, MonadState s m, ClientState s, MonadThrow m) ]
=> Commit hash ]
-> Ref hash
-> m Text renderAuthor ::
(MonadIO m, MonadState s m, ClientState s, MonadThrow m) =>
Commit hash ->
Ref hash ->
m (Maybe Node)
renderAuthor commit ref = do renderAuthor commit ref = do
authorInfo <- getAuthorInfo (commitAuthor commit) ref authorInfo <- getAuthorInfo (commitAuthor commit) ref
pure $ case authorInfo of pure $ case authorInfo of
Just (username, authorUrl) -> " [(" <> username <> ")](" <> authorUrl <> ")" Just (username, authorUrl) -> Just $ parentNode (LINK authorUrl username) [textNode username]
Nothing -> "" Nothing -> Nothing
renderMiscCommit renderMiscCommit ::
:: (MonadIO m, MonadState s m, ClientState s, MonadThrow m) (MonadIO m, MonadState s m, ClientState s, MonadThrow m) =>
=> MiscGroup hash MiscGroup hash ->
-> m Text m Node
renderMiscCommit (ref, commit, MiscCommit subject) = do renderMiscCommit (ref, commit, MiscCommit subject) = do
renderedRef <- renderRef ref renderedRef <- renderRef ref
authorText <- renderAuthor commit ref authorText <- renderAuthor commit ref
pure $ "- " <> renderedRef <> " " <> subject <> authorText pure $
listItemNode
renderMergeCommit [ paragraphNode $
:: (MonadIO m, MonadState s m, ClientState s, MonadThrow m) renderedRef
=> MergeGroup hash <> catMaybes
-> m Text [ Just $ textNode subject,
Just $ textNode " ",
authorText
]
]
renderMergeCommit ::
(MonadIO m, MonadState s m, ClientState s, MonadThrow m) =>
MergeGroup hash ->
m Node
renderMergeCommit (ref, commit, MergeCommit subject) = do renderMergeCommit (ref, commit, MergeCommit subject) = do
renderedRef <- renderRef ref renderedRef <- renderRef ref
authorText <- renderAuthor commit ref authorText <- renderAuthor commit ref
pure $ "- " <> renderedRef <> " Merge " <> subject <> authorText pure $
listItemNode
[ paragraphNode $
renderedRef
<> catMaybes
[ Just $ textNode $ "Merge " <> subject,
authorText
]
]
renderRange :: TagRef -> TagRef -> Text renderRange :: TagRef -> TagRef -> Text
renderRange tx ty = mconcat renderRange tx ty =
[prettyV . _tVersioning $ tx, " to ", prettyV . _tVersioning $ ty] mconcat
[prettyV . _tVersioning $ tx, " to ", prettyV . _tVersioning $ ty]
bold :: Text -> Text bold :: Text -> Node
bold x = "**" <> x <> "**" bold x = parentNode STRONG [textNode x]
indented :: Int -> Text -> Text indented :: Int -> Text -> Text
indented levels x = foldl (\acc _ -> acc <> " ") "" [1..levels] <> x indented levels x = foldl (\acc _ -> acc <> " ") "" [1 .. levels] <> x
indentedL :: Int -> Text -> Text indentedL :: Int -> Text -> Text
indentedL levels x = "\\" <> foldl (\acc _ -> acc <> "-") "" [1..levels] <> x indentedL levels x = "\\" <> foldl (\acc _ -> acc <> "-") "" [1 .. levels] <> x
headerOne :: Text -> Node
headerOne t = parentNode (HEADING 1) [textNode t]
headerTwo :: Text -> Node
headerTwo t = parentNode (HEADING 2) [textNode t]
linePadded :: Text -> Text headerThree :: Text -> Node
linePadded x = "\n" <> x <> "\n" headerThree t = parentNode (HEADING 3) [textNode t]
headerOne :: Text -> Text textNode :: Text -> Node
headerOne = linePadded . (<>) "# " textNode t = Node Nothing (TEXT t) []
headerTwo :: Text -> Text leafNode :: NodeType -> Node
headerTwo = linePadded . (<>) "## " leafNode n = Node Nothing n []
headerThree :: Text -> Text parentNode :: NodeType -> [Node] -> Node
headerThree = linePadded . (<>) "### " parentNode = Node Nothing
listItemNode :: [Node] -> Node
listItemNode = parentNode ITEM
paragraphNode :: [Node] -> Node
paragraphNode = parentNode PARAGRAPH
printReport ::
(MonadIO m, MonadState s m, ClientState s, MonadThrow m) =>
(TagRef, TagRef) ->
ChangeReport hash ->
m [Node]
printReport (rangeStart, rangeEnd) report = execWriterT $ do
tell [headerOne $ renderRange rangeStart rangeEnd]
printReport
:: (MonadIO m, MonadState s m, ClientState s, MonadThrow m)
=> ChangeReport hash
-> m ()
printReport report = do
-- Print conventional commits -- Print conventional commits
conventionalSection "New features:" crFeatures conventionalSection "New features:" crFeatures
conventionalSection "Fixes:" crFixes conventionalSection "Fixes:" crFixes
...@@ -129,7 +169,7 @@ printReport report = do ...@@ -129,7 +169,7 @@ printReport report = do
textSection "Merge commits:" mergeCommits textSection "Merge commits:" mergeCommits
where where
conventionalSection label sectionLens = do conventionalSection label sectionLens = do
let rawCommits = sortOn (\(_,_,pc) -> pc ^. ccScope) (report ^. sectionLens) let rawCommits = sortOn (\(_, _, pc) -> pc ^. ccScope) (report ^. sectionLens)
commits <- mapM renderConventionalCommit rawCommits commits <- mapM renderConventionalCommit rawCommits
textSection label commits textSection label commits
...@@ -137,7 +177,6 @@ printReport report = do ...@@ -137,7 +177,6 @@ printReport report = do
textSection label commits = case commits of textSection label commits = case commits of
[] -> pure () [] -> pure ()
_ -> do _ -> do
liftIO . TIO.putStrLn . headerTwo $ label tell [headerTwo label]
liftIO $ mapM_ (TIO.putStrLn . indented 1) commits
tell [parentNode (LIST (ListAttributes BULLET_LIST False 0 PAREN_DELIM)) commits]
...@@ -43,7 +43,6 @@ import GitHub (URL(URL)) ...@@ -43,7 +43,6 @@ import GitHub (URL(URL))
import GitHub (getUrl) import GitHub (getUrl)
import GitHub (getUrl) import GitHub (getUrl)
import Data.Aeson (FromJSON) import Data.Aeson (FromJSON)
import Data.Aeson (FromJSON)
class ClientState s where class ClientState s where
getRefURL getRefURL
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment