Skip to content

Commit 92ca78c

Browse files
Changes in the safe wrapper (#74)
* Change expected schema * Add flags for dotenv CLI to run the safe mode: * Add flag to read the scheme file path * Add directory to cabal file * Add flag to omit schema * Update README * Edit CHANGELOG * Use yml syntaxsis for default values
1 parent fc2ec57 commit 92ca78c

File tree

11 files changed

+147
-162
lines changed

11 files changed

+147
-162
lines changed

CHANGELOG.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@
22
## Dotenv 0.5.2.0
33

44
* Add `loadSafeFile` to typecheck the envs.
5-
* Add `-s` flag to the `dotenv` CLI tool to enable safe mode.
5+
* Add `(--schema|-s) FILE` flag to the `dotenv` CLI tool to enable safe mode.
6+
* Add `(--no-schema)` flag to the `dotenv` CLI tool to disable safe mode.
7+
* Turn safe mode on automatically when the `.schema.yml` file is present.
8+
* Make `required` optional in the `.schema.yml`.
69

710
## Dotenv 0.5.1.1
811

README.md

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -99,22 +99,21 @@ If the type-check succeeded the application is executed, otherwise you will get
9999
error with the types that mismatch.
100100

101101
In order to use this functionality you can use the `loadSafeFile` which takes the same
102-
configuration value as the `loadFile` function. Also, you need to have a `.scheme.yml`
102+
configuration value as the `loadFile` function. Also, you need to have a `.schema.yml`
103103
in your current directory. This file must have the following structure:
104104

105105
```yaml
106-
- type: bool
107-
envs:
108-
- name: DOTENV
109-
required: true
110-
- name: OTHERENV
111-
required: false
112-
- type: integer
113-
envs:
114-
- name: PORT
115-
required: true
116-
- name: TOKEN
117-
required: true
106+
- name: DOTENV
107+
type: bool
108+
required: true
109+
- name: OTHERENV
110+
type: bool
111+
- name: PORT
112+
type: integer
113+
required: true
114+
- name: TOKEN
115+
type: text
116+
required: false
118117
```
119118
120119
It is a list of type and envs. So, in this example, `DOTENV` must have a value
@@ -126,10 +125,11 @@ like `PORT` must be any integer. Currently, we are supporting the following type
126125
- `text` - Any text
127126

128127
**require** specifies if the env var is obligatory or not. In case you set it to true
129-
but do not provide it, you wil get an exception.
128+
but do not provide it, you wil get an exception. When **required** is omited, the default
129+
value is `false`.
130130

131-
**NOTE:** All the variables which are **required** in the `scheme.yml` must be defined
132-
in dotenvs.
131+
**NOTE:** All the variables which are **required** in the `schema.yml` must be defined
132+
in the dotenvs.
133133

134134
## Configuration
135135

@@ -223,28 +223,29 @@ current environment settings. By invoking the program `env` in place
223223
of `myprogram` above you can see what the environment will look like
224224
after evaluating multiple Dotenv files.
225225

226-
Adding the `-s` flag to dotenv will enable the safe mode to type check the env
227-
variables. For instance:
226+
The `--schema FILE` will get the envs configuration from the `FILE`. For instance:
228227

229228
```shell
230229
$ cat .env
231230
PORT=123a
232-
$ cat .scheme.yml
233-
- type: integer
234-
envs:
235-
- name: PORT
236-
required: true
231+
$ cat .schema.yml
232+
- name: PORT
233+
required: true
234+
type: integer
237235
```
238236

239237
running `dotenv` will throw:
240238

241239
```shell
242-
$ dotenv -s "echo $PORT"
240+
$ dotenv -s .schema.yml "echo $PORT"
243241
dotenv: 1:4:
244242
unexpected 'a'
245243
expecting digit or end of input
246244
```
247245

246+
**NOTE:** The flag can be omited when the `.schema.yml` is in the current working
247+
directory. To disable type checking add the flag `--no-schema`.
248+
248249
## Author
249250

250251
Justin Leitgeb

app/Main.hs

Lines changed: 33 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@ import Data.Monoid ((<>))
1111
import Options.Applicative
1212
import Paths_dotenv (version)
1313

14-
import Control.Monad (when)
14+
import Control.Monad (void, unless)
1515

1616
import Configuration.Dotenv (loadFile)
1717
import Configuration.Dotenv.Types (Config(..), defaultConfig)
18-
import Configuration.Dotenv.Scheme (readScheme, checkConfig)
18+
import Configuration.Dotenv.Scheme ( runSchemaChecker )
1919

2020
import System.Process (system)
2121
import System.Exit (exitWith)
@@ -26,31 +26,36 @@ data Options = Options
2626
, override :: Bool
2727
, program :: String
2828
, args :: [String]
29-
, safeModeEnabled :: Bool
29+
, schemaFile :: FilePath
30+
, disableSchema :: Bool
3031
} deriving (Show)
3132

3233
main :: IO ()
3334
main = do
3435
Options{..} <- execParser opts
35-
envs <- loadFile Config
36-
{ configExamplePath = dotenvExampleFiles
37-
, configOverride = override
38-
, configPath =
39-
if null dotenvFiles
40-
then configPath defaultConfig
41-
else dotenvFiles
42-
}
43-
when safeModeEnabled (readScheme >>= checkConfig envs)
44-
system (program ++ concatMap (" " ++) args) >>= exitWith
45-
where
46-
opts = info (helper <*> versionOption <*> config)
47-
( fullDesc
48-
<> progDesc "Runs PROGRAM after loading options from FILE"
49-
<> header "dotenv - loads options from dotenv files" )
50-
versionOption =
51-
infoOption
52-
(showVersion version)
53-
(long "version" <> short 'v' <> help "Show version of the program")
36+
let configDotenv =
37+
Config
38+
{ configExamplePath = dotenvExampleFiles
39+
, configOverride = override
40+
, configPath =
41+
if null dotenvFiles
42+
then configPath defaultConfig
43+
else dotenvFiles
44+
}
45+
in do
46+
void $ loadFile configDotenv
47+
unless disableSchema
48+
(runSchemaChecker schemaFile configDotenv)
49+
system (program ++ concatMap (" " ++) args) >>= exitWith
50+
where
51+
opts = info (helper <*> versionOption <*> config)
52+
( fullDesc
53+
<> progDesc "Runs PROGRAM after loading options from FILE"
54+
<> header "dotenv - loads options from dotenv files" )
55+
versionOption =
56+
infoOption
57+
(showVersion version)
58+
(long "version" <> short 'v' <> help "Show version of the program")
5459

5560
config :: Parser Options
5661
config = Options
@@ -73,6 +78,9 @@ config = Options
7378

7479
<*> many (argument str (metavar "ARG"))
7580

76-
<*> switch ( long "safe"
77-
<> short 's'
78-
<> help "Reads the .scheme.yml file from the current directory to enable type checking of envs" )
81+
<*> strOption ( long "schema"
82+
<> short 's'
83+
<> help "Set the file path for the schema.yml file"
84+
<> value ".schema.yml" )
85+
86+
<*> switch ( long "no-schema" <> help "Omit type checking" )

dotenv.cabal

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ library
8888

8989
build-depends: base >=4.7 && <5.0
9090
, base-compat >= 0.4
91+
, directory
9192
, megaparsec >= 6.0 && < 7.0
9293
, process >= 1.4.3.0
9394
, text
@@ -128,6 +129,7 @@ test-suite dotenv-test
128129
build-depends: base >=4.7 && <5.0
129130
, base-compat >= 0.4
130131
, dotenv
132+
, directory
131133
, megaparsec >= 6.0 && < 7.0
132134
, hspec
133135
, process >= 1.4.3.0

spec/Configuration/Dotenv/Scheme/ParseSpec.hs

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,20 +21,13 @@ spec = do
2121
specInstance :: Spec
2222
specInstance = describe "parse a config env file" $
2323
it "parses the env config values from a file" $
24-
let expected :: Config
24+
let expected :: [Env]
2525
expected =
26-
Config [
27-
EnvConf EnvBool
28-
[ Env "DOTENV" True
29-
, Env "OTHERENV" False
30-
]
31-
, EnvConf EnvInteger
32-
[ Env "PORT" True
33-
, Env "TOKEN" False
34-
]
35-
, EnvConf EnvText
36-
[ Env "URL" True
37-
]
26+
[ Env "DOTENV" EnvBool True
27+
, Env "OTHERENV" EnvBool False
28+
, Env "PORT" EnvInteger True
29+
, Env "TOKEN" EnvInteger False
30+
, Env "URL" EnvText True
3831
]
3932
in do
4033
actual <- decodeFileEither "spec/fixtures/.scheme.yml"

spec/Configuration/Dotenv/SchemeSpec.hs

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,29 +13,26 @@ spec =
1313
context "when the required envs are defined" $
1414
it "should succeed the type check" $
1515
let schemeEnvs =
16-
Config
17-
[ EnvConf EnvBool [Env "FOO" True]
18-
, EnvConf EnvInteger [Env "BAR" False]
16+
[ Env "FOO" EnvBool True
17+
, Env "BAR" EnvInteger False
1918
]
2019
dotenvs = [("FOO","true"), ("BAR","123")]
2120
in checkConfig dotenvs schemeEnvs `shouldReturn` ()
2221

2322
context "when the not required envs are missing" $
2423
it "should succeed the type check" $
2524
let schemeEnvs =
26-
Config
27-
[ EnvConf EnvBool [Env "FOO" True]
28-
, EnvConf EnvInteger [Env "BAR" False]
25+
[ Env "FOO" EnvBool True
26+
, Env "BAR" EnvInteger False
2927
]
3028
dotenvs = [("FOO","true")]
3129
in checkConfig dotenvs schemeEnvs `shouldReturn` ()
3230

3331
context "when the required envs are missing" $
3432
it "should fail before the type check" $
3533
let schemeEnvs =
36-
Config
37-
[ EnvConf EnvBool [Env "FOO" True]
38-
, EnvConf EnvInteger [Env "BAR" False]
34+
[ Env "FOO" EnvBool True
35+
, Env "BAR" EnvInteger False
3936
]
4037
dotenvs = [("BAR","123")]
4138
msg = "The following envs: FOO must be in the dotenvs"
@@ -44,9 +41,8 @@ spec =
4441
context "when there are missing dotenvs in the scheme" $
4542
it "should fail before type checking" $
4643
let schemeEnvs =
47-
Config
48-
[ EnvConf EnvBool [Env "FOO" True]
49-
, EnvConf EnvInteger [Env "BAR" False]
44+
[ Env "FOO" EnvBool True
45+
, Env "BAR" EnvInteger False
5046
]
5147
dotenvs = [("FOO","true"), ("BAR","123"), ("BAZ","text")]
5248
msg = "The following envs: BAZ must be in your scheme.yml"
@@ -55,10 +51,9 @@ spec =
5551
context "when there are missing scheme envs in the dotenv vars" $
5652
it "should fail before type checking" $
5753
let schemeEnvs =
58-
Config
59-
[ EnvConf EnvBool [Env "FOO" True]
60-
, EnvConf EnvText [Env "BAZ" True]
61-
, EnvConf EnvInteger [Env "BAR" False]
54+
[ Env "FOO" EnvBool True
55+
, Env "BAZ" EnvText True
56+
, Env "BAR" EnvInteger False
6257
]
6358
dotenvs = [("FOO","true"), ("BAR","123")]
6459
msg = "The following envs: BAZ must be in the dotenvs"

spec/fixtures/.scheme.yml

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,14 @@
1-
- type: bool
2-
envs:
3-
- name: DOTENV
4-
required: true
5-
- name: OTHERENV
6-
required: false
7-
- type: integer
8-
envs:
9-
- name: PORT
10-
required: true
11-
- name: TOKEN
12-
required: false
13-
- type: text
14-
envs:
15-
- name: URL
16-
required: true
1+
- name: DOTENV
2+
type: bool
3+
required: true
4+
- name: OTHERENV
5+
type: bool
6+
required: false
7+
- name: PORT
8+
type: integer
9+
required: true
10+
- name: TOKEN
11+
type: integer
12+
- name: URL
13+
type: text
14+
required: true

src/Configuration/Dotenv.hs

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,13 @@
1515
module Configuration.Dotenv
1616
( load
1717
, loadFile
18-
, loadSafeFile
1918
, parseFile
2019
, onMissingFile )
2120
where
2221

2322
import Control.Monad (liftM)
2423
import Configuration.Dotenv.Parse (configParser)
2524
import Configuration.Dotenv.ParsedVariable (interpolateParsedVariables)
26-
import Configuration.Dotenv.Scheme (readScheme, checkConfig)
2725
import Configuration.Dotenv.Types (Config(..))
2826
import Control.Monad.Catch
2927
import Control.Monad.IO.Class (MonadIO(..))
@@ -47,17 +45,6 @@ load ::
4745
-> m ()
4846
load override = mapM_ (applySetting override)
4947

50-
-- | @loadSafeFile@ parses the /.scheme.yml/ file and will perform the type checking
51-
-- of the environment variables in the /.env/ file.
52-
loadSafeFile
53-
:: MonadIO m
54-
=> Config
55-
-> m [(String, String)]
56-
loadSafeFile config = do
57-
envs <- loadFile config
58-
liftIO (readScheme >>= checkConfig envs)
59-
return envs
60-
6148
-- | @loadFile@ parses the environment variables defined in the dotenv example
6249
-- file and checks if they are defined in the dotenv file or in the environment.
6350
-- It also allows to override the environment variables defined in the environment

0 commit comments

Comments
 (0)