effectful-config-file 0.1.1.1 → 0.1.2.0
raw patch · 8 files changed
+59/−4 lines, 8 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ Data.Error.Config: ConfigNotFound :: Text -> ConfigNotFound
+ Data.Error.Config: instance GHC.Classes.Eq Data.Error.Config.ConfigNotFound
+ Data.Error.Config: instance GHC.Internal.Show.Show Data.Error.Config.ConfigNotFound
+ Data.Error.Config: newtype ConfigNotFound
+ Effectful.Config: requireConfigValue :: forall (es :: [Effect]) c a. (IOE :> es, Config c :> es, Log :> es, Secrets :> es, Error ConfigNotFound :> es, ConfigParse a, Show a) => Text -> ALens' c (ConfigValue a) -> Eff es a
Files
- CHANGELOG.md +6/−0
- effectful-config-file.cabal +1/−1
- src/Data/Config.hs +2/−0
- src/Data/Error/Config.hs +9/−0
- src/Effectful/Config.hs +23/−1
- src/Effectful/Config/Log.hs +1/−0
- src/Effectful/Config/Secrets.hs +1/−0
- test/Effectful/ConfigSpec.hs +16/−2
CHANGELOG.md view
@@ -1,3 +1,9 @@+## [1.2.0](https://github.com/haskell-github-trust/effectful-config-file/compare/1.1.1...1.2.0) (2026-10-26)++### Features++* add `requireConfigValue` helper ([8ba0c9e](https://github.com/haskell-github-trust/effectful-config-file/commit/8ba0c9e9e09ac829f3e64f44ae519d81c137312b))+ ## [1.1.1](https://github.com/haskell-github-trust/effectful-config-file/compare/1.1.0...1.1.1) (2026-10-25) ## [1.1.0](https://github.com/haskell-github-trust/effectful-config-file/compare/1.0.2...1.1.0) (2026-10-25)
effectful-config-file.cabal view
@@ -5,7 +5,7 @@ -- see: https://github.com/sol/hpack name: effectful-config-file-version: 0.1.1.1+version: 0.1.2.0 synopsis: Config-file effect for effectful description: Config-file parser and utilities to use in conjunction with effectful category: Configuration
src/Data/Config.hs view
@@ -7,6 +7,8 @@ {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeOperators #-} +-- | Configuration values that can be literals or references to+-- environment variables, files or secrets, and their TOML decoding. module Data.Config ( ConfigParse (..), ConfigFetch (..),
src/Data/Error/Config.hs view
@@ -1,8 +1,11 @@+-- | Configuration decoding errors. module Data.Error.Config ( ConfigError (..),+ ConfigNotFound (..), ) where import Data.List (intercalate)+import Data.Text (Text) import Toml (DecodeError, prettyDecodeError) -- | Errors raised while decoding a TOML configuration.@@ -18,3 +21,9 @@ instance Show ConfigError where show (ConfigError es) = "config error: " <> intercalate "; " (map prettyDecodeError es)++-- | A configuration value whose @env://@ or @file://@ source is absent.+--+-- @since 0.1.2.0+newtype ConfigNotFound = ConfigNotFound Text+ deriving (Eq, Show)
src/Effectful/Config.hs view
@@ -5,18 +5,21 @@ {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeOperators #-} +-- | Effect to read a TOML configuration and lazily resolve its values. module Effectful.Config ( Config, getConfig, getConfigValue, readConfig, readConfig',+ requireConfigValue, ) where import Control.Concurrent.MVar (MVar, modifyMVar, readMVar)+import Control.Exception (IOException) import Control.Lens (ALens', cloneLens, (&), (.~), (^.)) import Data.Config (ConfigFetch (fetch), ConfigParse, ConfigValue (..))-import Data.Error.Config (ConfigError (..))+import Data.Error.Config (ConfigError (..), ConfigNotFound (..)) import Data.Text (Text) import qualified Data.Text as T (pack) import qualified Data.Text.IO as T (readFile)@@ -24,6 +27,7 @@ import Effectful.Config.Log (Log, logWarn) import Effectful.Config.Secrets (Secrets) import Effectful.Error.Static (Error, throwError)+import Effectful.Exception (catch) import Effectful.Reader.Static (Reader, ask) import OpenTelemetry.Trace.Core ( addAttribute,@@ -78,6 +82,24 @@ [ printf "tried to get raw config value from (%s)" (show v) , "this should be impossible and is most likely a bug in your ConfigFetch instance" ]++-- | 'getConfigValue', raising t'ConfigNotFound' when an @env://@ or @file://@+-- source is absent instead of letting the 'IOException' escape.+--+-- @since 0.1.2.0+requireConfigValue+ :: IOE :> es+ => Config c :> es+ => Log :> es+ => Secrets :> es+ => Error ConfigNotFound :> es+ => ConfigParse a+ => Show a+ => Text+ -> ALens' c (ConfigValue a)+ -> Eff es a+requireConfigValue name lens =+ getConfigValue lens `catch` \(_ :: IOException) -> throwError (ConfigNotFound name) -- | Decode a configuration from TOML text. Warnings are ignored. --
src/Effectful/Config/Log.hs view
@@ -4,6 +4,7 @@ {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} +-- | Minimal logging effect used by the configuration library. module Effectful.Config.Log ( Log, runLog,
src/Effectful/Config/Secrets.hs view
@@ -4,6 +4,7 @@ {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} +-- | Effect to resolve secrets referenced by configuration values. module Effectful.Config.Secrets ( Secrets (..), getSecret,
test/Effectful/ConfigSpec.hs view
@@ -13,11 +13,11 @@ import Control.Lens (makeLenses, (^.)) import Data.Bifunctor (Bifunctor (..), first) import Data.Config (ConfigValue (..), withSection)-import Data.Error.Config (ConfigError (..))+import Data.Error.Config (ConfigError (..), ConfigNotFound (..)) import Data.Text (Text) import qualified Data.Text as T (isInfixOf, pack, unlines, unpack) import Effectful (runEff)-import Effectful.Config (getConfigValue, readConfig, readConfig')+import Effectful.Config (getConfigValue, readConfig, readConfig', requireConfigValue) import Effectful.Config.Log (runLog) import Effectful.Config.Secrets (SecretsError, runSecretsError) import Effectful.Error.Static (runErrorNoCallStack)@@ -216,6 +216,20 @@ cfg <- timeout 1000000 (readMVar p) cfg `shouldBe` Just (FileConfig (File "/nonexistent"))++ describe "requireConfigValue" $ do+ it "throws ConfigNotFound on a missing file" $ do+ p <- newMVar (FileConfig (File "/nonexistent"))+ result <-+ runEff+ . runErrorNoCallStack @ConfigNotFound+ . runErrorNoCallStack @SecretsError+ . runSecretsError+ . runLog silentLog+ . runReader p+ $ requireConfigValue "file_val" file_val++ result `shouldBe` Left (ConfigNotFound "file_val") describe "readConfig' OTel logging" $ do it "emits parse warnings as OTel log records" $ withSystemTempFile "effectful-config" $ \path h -> do