Skip to content

Commit

Permalink
bake: load .env file from working dir for compose files
Browse files Browse the repository at this point in the history
Signed-off-by: CrazyMax <[email protected]>
  • Loading branch information
crazy-max committed Aug 9, 2022
1 parent 2b630aa commit 525eeb3
Show file tree
Hide file tree
Showing 3 changed files with 132 additions and 0 deletions.
43 changes: 43 additions & 0 deletions bake/compose.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ package bake

import (
"fmt"
"os"
"path/filepath"
"strings"

"github.com/compose-spec/compose-go/dotenv"
"github.com/compose-spec/compose-go/loader"
compose "github.com/compose-spec/compose-go/types"
"github.com/pkg/errors"
Expand All @@ -14,6 +17,10 @@ import (
var errComposeInvalid = errors.New("invalid compose file")

func ParseCompose(dt []byte, envs map[string]string) (*Config, error) {
if wd, err := os.Getwd(); err == nil {
envs = loadDotEnv(envs, wd)
}

cfg, err := loader.Load(compose.ConfigDetails{
ConfigFiles: []compose.ConfigFile{
{
Expand All @@ -28,6 +35,7 @@ func ParseCompose(dt []byte, envs map[string]string) (*Config, error) {
if err != nil {
return nil, err
}

if err = composeValidate(cfg); err != nil {
return nil, err
}
Expand Down Expand Up @@ -107,6 +115,41 @@ func ParseCompose(dt []byte, envs map[string]string) (*Config, error) {
return &c, nil
}

func loadDotEnv(currentEnv map[string]string, workingDir string) map[string]string {
if currentEnv == nil {
currentEnv = make(map[string]string)
}

ef, err := filepath.Abs(filepath.Join(workingDir, ".env"))
if err != nil {
return currentEnv
}

if _, err := os.Stat(ef); err != nil {
return currentEnv
}

file, err := os.Open(ef)
if err != nil {
return currentEnv
}
defer file.Close()

envs, err := dotenv.Parse(file)
if err != nil {
return currentEnv
}

for k, v := range envs {
if _, set := currentEnv[k]; set {
continue
}
currentEnv[k] = v
}

return currentEnv
}

func flatten(in compose.MappingWithEquals) compose.Mapping {
if len(in) == 0 {
return nil
Expand Down
40 changes: 40 additions & 0 deletions bake/compose_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package bake

import (
"os"
"path/filepath"
"sort"
"testing"

Expand Down Expand Up @@ -380,6 +381,27 @@ services:
require.Equal(t, map[string]string{"CT_ECR": "foo", "FOO": "bsdf -csdf", "NODE_ENV": "test"}, c.Targets[0].Args)
}

func TestDotEnv(t *testing.T) {
tmpdir := t.TempDir()

err := os.WriteFile(filepath.Join(tmpdir, ".env"), []byte("FOO=bar"), 0644)
require.NoError(t, err)

var dt = []byte(`
services:
scratch:
build:
context: .
args:
FOO:
`)

chdir(t, tmpdir)
c, err := ParseCompose(dt, nil)
require.NoError(t, err)
require.Equal(t, map[string]string{"FOO": "bar"}, c.Targets[0].Args)
}

func TestPorts(t *testing.T) {
var dt = []byte(`
services:
Expand Down Expand Up @@ -523,3 +545,21 @@ services:
})
}
}

// chdir changes the current working directory to the named directory,
// and then restore the original working directory at the end of the test.
func chdir(t *testing.T, dir string) {
olddir, err := os.Getwd()
if err != nil {
t.Fatalf("chdir: %v", err)
}
if err := os.Chdir(dir); err != nil {
t.Fatalf("chdir %s: %v", dir, err)
}
t.Cleanup(func() {
if err := os.Chdir(olddir); err != nil {
t.Errorf("chdir to original working directory %s: %v", olddir, err)
os.Exit(1)
}
})
}
49 changes: 49 additions & 0 deletions docs/guides/bake/configuring-build.md
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,55 @@ $ TAG=v1.2.0 docker buildx bake -f docker-bake.hcl -f prod.env --print
}
```

### `.env` file

You can declare default environment variables in an environment file named
`.env`. This file will be loaded from the current working directory,
where the command is executed and applied to [compose definitions](compose-file.md).

```yaml
# docker-compose.yml
services:
webapp:
image: docker.io/username/webapp:${TAG:-v1.0.0}
build:
dockerfile: Dockerfile
```
```
# .env
TAG=v1.1.0
```

```console
$ docker buildx bake --print
```
```json
{
"group": {
"default": {
"targets": [
"webapp"
]
}
},
"target": {
"webapp": {
"context": ".",
"dockerfile": "Dockerfile",
"tags": [
"docker.io/username/webapp:v1.1.0"
]
}
}
}
```

> **Note**
>
> System environment variables and environment variables defined in `-f` take
> precedence over environment variables in `.env`.
## From command line

You can also override target configurations from the command line with the
Expand Down

0 comments on commit 525eeb3

Please sign in to comment.