Skip to content

Commit

Permalink
Support newlines in env files (#6)
Browse files Browse the repository at this point in the history
Also did some housekeeping:
- Now using github.com/maragudk/is for assertions
- Upgraded the CI workflow
- Upgraded to Go 1.18
  • Loading branch information
markuswustenberg authored May 15, 2024
1 parent c2c7c06 commit 0b6812e
Show file tree
Hide file tree
Showing 11 changed files with 121 additions and 105 deletions.
53 changes: 53 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
name: CI

on:
push:
branches:
- main
pull_request:
branches:
- main

concurrency:
group: ${{ github.workflow }}-${{ github.ref_name }}
cancel-in-progress: true

jobs:
test:
name: Test
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Go
uses: actions/setup-go@v5
with:
go-version-file: go.mod
check-latest: true

- name: Build
run: go build -v ./...

- name: Test
run: go test -v -coverprofile=cover.out -shuffle on ./...

lint:
name: Lint
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Go
uses: actions/setup-go@v5
with:
go-version-file: go.mod
check-latest: true

- name: Lint
uses: golangci/golangci-lint-action@v4
with:
version: latest
44 changes: 0 additions & 44 deletions .github/workflows/go.yml

This file was deleted.

2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Made in 🇩🇰 by [maragu](https://www.maragu.dk), maker of [online Go courses
## Usage

```shell
go get -u github.com/maragudk/env
go get github.com/maragudk/env
```

```go
Expand Down
15 changes: 9 additions & 6 deletions env.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,6 @@ import (
"time"
)

const (
charComment = '#'
// TODO: handle `prefix`, i.e. single and double quote
)

// GetStringOrDefault value.
func GetStringOrDefault(name, defaultV string) string {
v, ok := os.LookupEnv(name)
Expand Down Expand Up @@ -78,9 +73,17 @@ func Load(paths ...string) error {
for s.Scan() {
i++
line := s.Text()
if line[0] == charComment {

// Blank lines
if line == "" {
continue
}

// Comments
if strings.HasPrefix(line, "#") {
continue
}

parts := strings.SplitN(line, "=", 2)
if len(parts) < 2 {
return fmt.Errorf("missing equal sign on line %v in %v", i, path)
Expand Down
92 changes: 47 additions & 45 deletions env_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,148 +5,150 @@ import (
"testing"
"time"

"github.com/maragudk/is"

"github.com/maragudk/env"
"github.com/matryer/is"
)

func TestGetStringOrDefault(t *testing.T) {
t.Run("gets the string value from the environment", func(t *testing.T) {
is := is.New(t)
defer setenv("hat", "party")()
v := env.GetStringOrDefault("hat", "regular")
is.Equal("party", v)
is.Equal(t, "party", v)
})

t.Run("gets the default value if not set", func(t *testing.T) {
is := is.New(t)
v := env.GetStringOrDefault("hat", "regular")
is.Equal("regular", v)
is.Equal(t, "regular", v)
})
}

func TestGetIntOrDefault(t *testing.T) {
t.Run("gets the int value from the environment", func(t *testing.T) {
is := is.New(t)
defer setenv("hats", "2")()
v := env.GetIntOrDefault("hats", 1)
is.Equal(2, v)
is.Equal(t, 2, v)
})

t.Run("gets the default value if not set", func(t *testing.T) {
is := is.New(t)
v := env.GetIntOrDefault("hats", 1)
is.Equal(1, v)
is.Equal(t, 1, v)
})

t.Run("gets the default value if not an int", func(t *testing.T) {
is := is.New(t)
defer setenv("hats", "notanumber")()
v := env.GetIntOrDefault("hats", 1)
is.Equal(1, v)
is.Equal(t, 1, v)
})
}

func TestGetBoolOrDefault(t *testing.T) {
t.Run("gets the bool value from the environment", func(t *testing.T) {
is := is.New(t)
defer setenv("hats", "true")()
v := env.GetBoolOrDefault("hats", true)
is.Equal(true, v)
is.Equal(t, true, v)
})

t.Run("gets the default value if not set", func(t *testing.T) {
is := is.New(t)
v := env.GetBoolOrDefault("hats", false)
is.Equal(false, v)
is.Equal(t, false, v)
})

t.Run("gets the default value if not a bool", func(t *testing.T) {
is := is.New(t)
defer setenv("hats", "notabool")()
v := env.GetBoolOrDefault("hats", false)
is.Equal(false, v)
is.Equal(t, false, v)
})
}

func TestGetDurationOrDefault(t *testing.T) {
t.Run("gets the duration value from the environment", func(t *testing.T) {
is := is.New(t)
defer setenv("wearhatfor", "1m")()
v := env.GetDurationOrDefault("wearhatfor", time.Second)
is.Equal(time.Minute, v)
is.Equal(t, time.Minute, v)
})

t.Run("gets the default value if not set", func(t *testing.T) {
is := is.New(t)
v := env.GetDurationOrDefault("wearhatfor", time.Second)
is.Equal(time.Second, v)
is.Equal(t, time.Second, v)
})

t.Run("gets the default value if not a bool", func(t *testing.T) {
is := is.New(t)
defer setenv("wearhatfor", "notaduration")()
v := env.GetDurationOrDefault("wearhatfor", time.Second)
is.Equal(time.Second, v)
is.Equal(t, time.Second, v)
})
}

func TestLoad(t *testing.T) {
t.Run("loads an environment file", func(t *testing.T) {
is := is.New(t)
defer unsetenv("hat", "hats", "equals")
err := env.Load("testdata/env")
is.NoErr(err)
is.NotError(t, err)
hat := env.GetStringOrDefault("hat", "regular")
is.Equal(t, "party", hat)
hats := env.GetIntOrDefault("hats", 1)
is.Equal(t, 2, hats)
})

t.Run("loads multiple environment files, and later files take precedence", func(t *testing.T) {
defer unsetenv("hat", "hats", "equals")
err := env.Load("testdata/env", "testdata/env2")
is.NotError(t, err)
hat := env.GetStringOrDefault("hat", "regular")
is.Equal("party", hat)
is.Equal(t, "party", hat)
hats := env.GetIntOrDefault("hats", 1)
is.Equal(2, hats)
is.Equal(t, 3, hats)
})

t.Run("ignores blank lines", func(t *testing.T) {
defer unsetenv("hat", "hats")
err := env.Load("testdata/blank")
is.NotError(t, err)
hat := env.GetStringOrDefault("hat", "regular")
is.Equal(t, "party", hat)
})

t.Run("errors on bad file", func(t *testing.T) {
is := is.New(t)
err := env.Load("testdata/invalid")
is.True(err != nil)
is.Equal("missing equal sign on line 1 in testdata/invalid", err.Error())
is.True(t, err != nil)
is.Equal(t, "missing equal sign on line 1 in testdata/invalid", err.Error())
})

t.Run("ignore comments in environment file", func(t *testing.T) {
is := is.New(t)
defer unsetenv("hat", "hats", "equals")
err := env.Load("testdata/with_comment")
is.NoErr(err)
equals := env.GetStringOrDefault("equals", "")
is.Equal("somethingwithequalsafter=", equals)
t.Run("ignores comments in environment file", func(t *testing.T) {
defer unsetenv("hat")
err := env.Load("testdata/comments")
is.NotError(t, err)
hat := env.GetStringOrDefault("hat", "regular")
is.Equal(t, "party", hat)
})

t.Run("gets the string value including equal signs", func(t *testing.T) {
is := is.New(t)
defer unsetenv("hat", "hats", "equals")
err := env.Load("testdata/env")
is.NoErr(err)
is.NotError(t, err)
equals := env.GetStringOrDefault("equals", "")
is.Equal("somethingwithequalsafter=", equals)
is.Equal(t, "somethingwithequalsafter=", equals)
})
}

func TestMustLoad(t *testing.T) {
t.Run("loads an environment file", func(t *testing.T) {
is := is.New(t)
defer unsetenv("hat", "hats", "equals")
env.MustLoad("testdata/env")
hat := env.GetStringOrDefault("hat", "regular")
is.Equal("party", hat)
is.Equal(t, "party", hat)
hats := env.GetIntOrDefault("hats", 1)
is.Equal(2, hats)
is.Equal(t, 2, hats)
})

t.Run("panics on no such file", func(t *testing.T) {
is := is.New(t)
recovered := false
defer func() {
if err := recover(); err != nil {
recovered = true
}
is.True(recovered)
is.True(t, recovered)
}()
env.MustLoad()
})
Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
module github.com/maragudk/env

go 1.16
go 1.18

require github.com/matryer/is v1.4.0
require github.com/maragudk/is v0.1.0
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE=
github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
github.com/maragudk/is v0.1.0 h1:obq9anZNmOYcaNbeT0LMyjIexdNeYTw/TLAPD/BnZHA=
github.com/maragudk/is v0.1.0/go.mod h1:W/r6+TpnISu+a88OLXQy5JQGCOhXQXXLD2e5b4xMn5c=
3 changes: 3 additions & 0 deletions testdata/blank
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
hat=party

hats=3
3 changes: 3 additions & 0 deletions testdata/comments
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# this a comment
hat=party
# this another comment
1 change: 1 addition & 0 deletions testdata/env2
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
hats=3
5 changes: 0 additions & 5 deletions testdata/with_comment

This file was deleted.

0 comments on commit 0b6812e

Please sign in to comment.