{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}

-- |
-- Module      : Language.Github.Actions.Concurrency
-- Description : GitHub Actions concurrency settings
-- Copyright   : (c) 2025 Bellroy Pty Ltd
-- License     : BSD-3-Clause
-- Maintainer  : Bellroy Tech Team <haskell@bellroy.com>
--
-- This module provides the 'Concurrency' type for controlling concurrent execution
-- of GitHub Actions workflows and jobs.
--
-- Concurrency settings allow you to control how many workflow runs or job executions
-- can happen simultaneously.
--
-- For more information about GitHub Actions concurrency, see:
-- <https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#concurrency>
module Language.Github.Actions.Concurrency
  ( Concurrency (..),
    gen,
  )
where

import Data.Aeson (FromJSON, ToJSON (..), (.:?), (.=))
import qualified Data.Aeson as Aeson
import Data.Text (Text)
import GHC.Generics (Generic)
import Hedgehog (MonadGen)
import qualified Hedgehog.Gen as Gen
import qualified Hedgehog.Range as Range

-- | Concurrency settings for workflows and jobs.
--
-- Concurrency allows you to control whether multiple workflow runs or job executions
-- can happen simultaneously. This is useful for preventing conflicts when deploying
-- or when you want to ensure only one workflow processes a particular resource at a time.
--
-- Example usage:
--
-- @
-- import Language.Github.Actions.Concurrency
--
-- -- Only allow one deployment per branch
-- deploymentConcurrency :: Concurrency
-- deploymentConcurrency = Concurrency
--  { group = Just "${{ github.ref }}"
--  , cancelInProgress = Just True
--  }
-- @
--
-- For more details, see: <https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#concurrency>
data Concurrency = Concurrency
  { -- | Concurrency group identifier
    Concurrency -> Maybe Text
group :: Maybe Text,
    -- | Whether to cancel in-progress runs
    Concurrency -> Maybe Bool
cancelInProgress :: Maybe Bool
  }
  deriving stock (Concurrency -> Concurrency -> Bool
(Concurrency -> Concurrency -> Bool)
-> (Concurrency -> Concurrency -> Bool) -> Eq Concurrency
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Concurrency -> Concurrency -> Bool
== :: Concurrency -> Concurrency -> Bool
$c/= :: Concurrency -> Concurrency -> Bool
/= :: Concurrency -> Concurrency -> Bool
Eq, (forall x. Concurrency -> Rep Concurrency x)
-> (forall x. Rep Concurrency x -> Concurrency)
-> Generic Concurrency
forall x. Rep Concurrency x -> Concurrency
forall x. Concurrency -> Rep Concurrency x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. Concurrency -> Rep Concurrency x
from :: forall x. Concurrency -> Rep Concurrency x
$cto :: forall x. Rep Concurrency x -> Concurrency
to :: forall x. Rep Concurrency x -> Concurrency
Generic, Eq Concurrency
Eq Concurrency =>
(Concurrency -> Concurrency -> Ordering)
-> (Concurrency -> Concurrency -> Bool)
-> (Concurrency -> Concurrency -> Bool)
-> (Concurrency -> Concurrency -> Bool)
-> (Concurrency -> Concurrency -> Bool)
-> (Concurrency -> Concurrency -> Concurrency)
-> (Concurrency -> Concurrency -> Concurrency)
-> Ord Concurrency
Concurrency -> Concurrency -> Bool
Concurrency -> Concurrency -> Ordering
Concurrency -> Concurrency -> Concurrency
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: Concurrency -> Concurrency -> Ordering
compare :: Concurrency -> Concurrency -> Ordering
$c< :: Concurrency -> Concurrency -> Bool
< :: Concurrency -> Concurrency -> Bool
$c<= :: Concurrency -> Concurrency -> Bool
<= :: Concurrency -> Concurrency -> Bool
$c> :: Concurrency -> Concurrency -> Bool
> :: Concurrency -> Concurrency -> Bool
$c>= :: Concurrency -> Concurrency -> Bool
>= :: Concurrency -> Concurrency -> Bool
$cmax :: Concurrency -> Concurrency -> Concurrency
max :: Concurrency -> Concurrency -> Concurrency
$cmin :: Concurrency -> Concurrency -> Concurrency
min :: Concurrency -> Concurrency -> Concurrency
Ord, Int -> Concurrency -> ShowS
[Concurrency] -> ShowS
Concurrency -> String
(Int -> Concurrency -> ShowS)
-> (Concurrency -> String)
-> ([Concurrency] -> ShowS)
-> Show Concurrency
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Concurrency -> ShowS
showsPrec :: Int -> Concurrency -> ShowS
$cshow :: Concurrency -> String
show :: Concurrency -> String
$cshowList :: [Concurrency] -> ShowS
showList :: [Concurrency] -> ShowS
Show)

instance FromJSON Concurrency where
  parseJSON :: Value -> Parser Concurrency
parseJSON = String
-> (Object -> Parser Concurrency) -> Value -> Parser Concurrency
forall a. String -> (Object -> Parser a) -> Value -> Parser a
Aeson.withObject String
"Concurrency" ((Object -> Parser Concurrency) -> Value -> Parser Concurrency)
-> (Object -> Parser Concurrency) -> Value -> Parser Concurrency
forall a b. (a -> b) -> a -> b
$ \Object
o -> do
    Maybe Text
group <- Object
o Object -> Key -> Parser (Maybe Text)
forall a. FromJSON a => Object -> Key -> Parser (Maybe a)
.:? Key
"group"
    Maybe Bool
cancelInProgress <- Object
o Object -> Key -> Parser (Maybe Bool)
forall a. FromJSON a => Object -> Key -> Parser (Maybe a)
.:? Key
"cancel-in-progress"
    Concurrency -> Parser Concurrency
forall a. a -> Parser a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Concurrency {Maybe Bool
Maybe Text
group :: Maybe Text
cancelInProgress :: Maybe Bool
group :: Maybe Text
cancelInProgress :: Maybe Bool
..}

instance ToJSON Concurrency where
  toJSON :: Concurrency -> Value
toJSON Concurrency {Maybe Bool
Maybe Text
group :: Concurrency -> Maybe Text
cancelInProgress :: Concurrency -> Maybe Bool
group :: Maybe Text
cancelInProgress :: Maybe Bool
..} =
    [Pair] -> Value
Aeson.object
      [ Key
"group" Key -> Maybe Text -> Pair
forall v. ToJSON v => Key -> v -> Pair
forall e kv v. (KeyValue e kv, ToJSON v) => Key -> v -> kv
.= Maybe Text
group,
        Key
"cancel-in-progress" Key -> Maybe Bool -> Pair
forall v. ToJSON v => Key -> v -> Pair
forall e kv v. (KeyValue e kv, ToJSON v) => Key -> v -> kv
.= Maybe Bool
cancelInProgress
      ]

gen :: (MonadGen m) => m Concurrency
gen :: forall (m :: * -> *). MonadGen m => m Concurrency
gen = do
  Maybe Text
group <- m Text -> m (Maybe Text)
forall (m :: * -> *) a. MonadGen m => m a -> m (Maybe a)
Gen.maybe (Range Int -> m Char -> m Text
forall (m :: * -> *). MonadGen m => Range Int -> m Char -> m Text
Gen.text (Int -> Int -> Range Int
forall a. Integral a => a -> a -> Range a
Range.linear Int
1 Int
5) m Char
forall (m :: * -> *). MonadGen m => m Char
Gen.alphaNum)
  Maybe Bool
cancelInProgress <- m Bool -> m (Maybe Bool)
forall (m :: * -> *) a. MonadGen m => m a -> m (Maybe a)
Gen.maybe m Bool
forall (m :: * -> *). MonadGen m => m Bool
Gen.bool
  Concurrency -> m Concurrency
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Concurrency {Maybe Bool
Maybe Text
group :: Maybe Text
cancelInProgress :: Maybe Bool
group :: Maybe Text
cancelInProgress :: Maybe Bool
..}