module GitHub.Workflow.Command.Stopping
  ( -- * Basic usage
    suspendCommands

    -- * Stop and resume
  , stopCommands
  , resumeCommands
  , SuspendToken (..)

    -- * Manual token management
  , randomSuspendToken
  , suspendCommandsWithToken
  , stopCommandsWithToken

    -- * Command types
  , StopCommands (..)
  , ResumeCommands (..)
  ) where

import Control.Applicative ((*>), (<*))
import Control.Lens ((.~))
import Control.Monad.Random.Class (MonadRandom, getRandomRs)
import Data.Function ((.))
import Data.Functor (Functor ((<$)), (<$>))
import Data.List qualified as List
import Data.Text (Text)
import Data.Text qualified as T
import GitHub.Workflow.Command.Execution
import GitHub.Workflow.Command.Syntax

-- | Run an action with processing of workflow commands suspended
--
-- GitHub documentation:
-- <https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/workflow-commands-for-github-actions#stopping-and-starting-workflow-commands Stopping and starting workflow commands>
suspendCommands
  :: (MonadCommand m, MonadRandom m)
  => m a
  -- ^ Commands issued by this action will have no effect
  -> m a
suspendCommands :: forall (m :: * -> *) a.
(MonadCommand m, MonadRandom m) =>
m a -> m a
suspendCommands m a
x = do
  SuspendToken
token <- m SuspendToken
forall (m :: * -> *). MonadRandom m => m SuspendToken
randomSuspendToken
  SuspendToken -> m a -> m a
forall (m :: * -> *) a.
MonadCommand m =>
SuspendToken -> m a -> m a
suspendCommandsWithToken SuspendToken
token m a
x

suspendCommandsWithToken :: MonadCommand m => SuspendToken -> m a -> m a
suspendCommandsWithToken :: forall (m :: * -> *) a.
MonadCommand m =>
SuspendToken -> m a -> m a
suspendCommandsWithToken SuspendToken
token m a
x =
  SuspendToken -> m ()
forall (m :: * -> *). MonadCommand m => SuspendToken -> m ()
stopCommandsWithToken SuspendToken
token m () -> m a -> m a
forall a b. m a -> m b -> m b
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> m a
x m a -> m () -> m a
forall a b. m a -> m b -> m a
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* SuspendToken -> m ()
forall (m :: * -> *). MonadCommand m => SuspendToken -> m ()
resumeCommands SuspendToken
token

-- | Stops processing any workflow commands
--
-- This special command allows you to log anything without accidentally running a workflow command.
stopCommands :: (MonadCommand m, MonadRandom m) => m SuspendToken
stopCommands :: forall (m :: * -> *).
(MonadCommand m, MonadRandom m) =>
m SuspendToken
stopCommands = do
  SuspendToken
token <- m SuspendToken
forall (m :: * -> *). MonadRandom m => m SuspendToken
randomSuspendToken
  SuspendToken
token SuspendToken -> m () -> m SuspendToken
forall a b. a -> m b -> m a
forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ SuspendToken -> m ()
forall (m :: * -> *). MonadCommand m => SuspendToken -> m ()
stopCommandsWithToken SuspendToken
token

stopCommandsWithToken :: MonadCommand m => SuspendToken -> m ()
stopCommandsWithToken :: forall (m :: * -> *). MonadCommand m => SuspendToken -> m ()
stopCommandsWithToken SuspendToken
token =
  StopCommands -> m ()
forall a. ToCommand a => a -> m ()
forall (m :: * -> *) a. (MonadCommand m, ToCommand a) => a -> m ()
executeCommand StopCommands {SuspendToken
token :: SuspendToken
$sel:token:StopCommands :: SuspendToken
token}

-- | Resume processing workflow commands
resumeCommands :: MonadCommand m => SuspendToken -> m ()
resumeCommands :: forall (m :: * -> *). MonadCommand m => SuspendToken -> m ()
resumeCommands SuspendToken
token = ResumeCommands -> m ()
forall a. ToCommand a => a -> m ()
forall (m :: * -> *) a. (MonadCommand m, ToCommand a) => a -> m ()
executeCommand ResumeCommands {SuspendToken
token :: SuspendToken
$sel:token:ResumeCommands :: SuspendToken
token}

newtype SuspendToken = SuspendToken Text

randomSuspendToken :: MonadRandom m => m SuspendToken
randomSuspendToken :: forall (m :: * -> *). MonadRandom m => m SuspendToken
randomSuspendToken = Text -> SuspendToken
SuspendToken (Text -> SuspendToken)
-> ([Char] -> Text) -> [Char] -> SuspendToken
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Char] -> Text
T.pack ([Char] -> Text) -> ([Char] -> [Char]) -> [Char] -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> [Char] -> [Char]
forall a. Int -> [a] -> [a]
List.take Int
20 ([Char] -> SuspendToken) -> m [Char] -> m SuspendToken
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Char, Char) -> m [Char]
forall a. Random a => (a, a) -> m [a]
forall (m :: * -> *) a.
(MonadRandom m, Random a) =>
(a, a) -> m [a]
getRandomRs (Char
'a', Char
'z')

newtype StopCommands = StopCommands
  { StopCommands -> SuspendToken
token :: SuspendToken
  }

instance ToCommand StopCommands where
  addToCommand :: StopCommands -> Command -> Command
addToCommand StopCommands {$sel:token:StopCommands :: StopCommands -> SuspendToken
token = SuspendToken Text
t} =
    ((Name -> Identity Name) -> Command -> Identity Command
forall a. HasName a => Lens' a Name
Lens' Command Name
name ((Name -> Identity Name) -> Command -> Identity Command)
-> Name -> Command -> Command
forall s t a b. ASetter s t a b -> b -> s -> t
.~ Name
"stop-commands") (Command -> Command) -> (Command -> Command) -> Command -> Command
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((Message -> Identity Message) -> Command -> Identity Command
forall a. HasMessage a => Lens' a Message
Lens' Command Message
message ((Message -> Identity Message) -> Command -> Identity Command)
-> Message -> Command -> Command
forall s t a b. ASetter s t a b -> b -> s -> t
.~ Text -> Message
Message Text
t)

newtype ResumeCommands = ResumeCommands
  { ResumeCommands -> SuspendToken
token :: SuspendToken
  }

instance ToCommand ResumeCommands where
  addToCommand :: ResumeCommands -> Command -> Command
addToCommand ResumeCommands {$sel:token:ResumeCommands :: ResumeCommands -> SuspendToken
token = SuspendToken Text
t} =
    (Name -> Identity Name) -> Command -> Identity Command
forall a. HasName a => Lens' a Name
Lens' Command Name
name ((Name -> Identity Name) -> Command -> Identity Command)
-> Name -> Command -> Command
forall s t a b. ASetter s t a b -> b -> s -> t
.~ Text -> Name
Name Text
t