module MiniParser.Deploy where import Control.Monad (void) import Data.Void (Void) import Text.Megaparsec ( Parsec , choice , eof , errorBundlePretty , many , parse , sepBy1 , some , (<|>) ) import Text.Megaparsec.Char (alphaNumChar, char, space1, string) data Environment = Staging | Production deriving (Eq, Show) data DeployCommand = DeployCommand { serviceName :: String , environment :: Environment , tags :: [String] } deriving (Eq, Show) type Parser = Parsec Void String environmentParser :: Parser Environment environmentParser = choice [ Production <$ string "production" , Staging <$ string "staging" ] identifierParser :: Parser String identifierParser = some (alphaNumChar <|> char '_' <|> char '-') tagParser :: Parser [String] tagParser = string "tags=" *> (identifierParser `sepBy1` char ',') deployCommandParser :: Parser DeployCommand deployCommandParser = do void (string "deploy") space1 parsedService <- identifierParser space1 parsedEnvironment <- environmentParser parsedTags <- many (space1 *> tagParser) eof pure DeployCommand { serviceName = parsedService , environment = parsedEnvironment , tags = concat parsedTags } parseDeployCommand :: String -> Either String DeployCommand parseDeployCommand input = case parse deployCommandParser "deploy-command" input of Left parseError -> Left (errorBundlePretty parseError) Right command -> Right command renderCommand :: DeployCommand -> String renderCommand command = "deploy " ++ serviceName command ++ " to " ++ renderEnvironment (environment command) ++ renderTags (tags command) renderEnvironment :: Environment -> String renderEnvironment Staging = "staging" renderEnvironment Production = "production" renderTags :: [String] -> String renderTags [] = " with no tags" renderTags parsedTags = " with tags: " ++ commaSeparated parsedTags commaSeparated :: [String] -> String commaSeparated [] = "" commaSeparated [singleItem] = singleItem commaSeparated (firstItem : remainingItems) = firstItem ++ ", " ++ commaSeparated remainingItems