3172 - Allow passing env vars with set for docker compose cases

- Related: #3172, #1135
- Example: --set=env.key=value
This commit is contained in:
jwiltse 2025-05-23 13:49:07 -04:00
parent e3c6618db2
commit 2af52e84ea
6 changed files with 88 additions and 29 deletions

View File

@ -181,7 +181,7 @@ func readWithProgress(r io.Reader, setStatus func(st *client.VertexStatus)) (dt
}
func ListTargets(files []File) ([]string, error) {
c, _, err := ParseFiles(files, nil)
c, _, err := ParseFiles(files, nil, nil)
if err != nil {
return nil, err
}
@ -196,7 +196,7 @@ func ListTargets(files []File) ([]string, error) {
}
func ReadTargets(ctx context.Context, files []File, targets, overrides []string, defaults map[string]string, ent *EntitlementConf) (map[string]*Target, map[string]*Group, error) {
c, _, err := ParseFiles(files, defaults)
c, _, err := ParseFiles(files, overrides, defaults)
if err != nil {
return nil, nil, err
}
@ -304,7 +304,7 @@ func sliceToMap(env []string) (res map[string]string) {
return
}
func ParseFiles(files []File, defaults map[string]string) (_ *Config, _ *hclparser.ParseMeta, err error) {
func ParseFiles(files []File, overrides []string, defaults map[string]string) (_ *Config, _ *hclparser.ParseMeta, err error) {
defer func() {
err = formatHCLError(err, files)
}()
@ -312,8 +312,12 @@ func ParseFiles(files []File, defaults map[string]string) (_ *Config, _ *hclpars
var c Config
var composeFiles []File
var hclFiles []*hcl.File
envOverrides, err := parseEnvOverrides(overrides)
if err != nil {
return nil, nil, err
}
for _, f := range files {
isCompose, composeErr := validateComposeFile(f.Data, f.Name)
isCompose, composeErr := validateComposeFile(f.Data, f.Name, envOverrides)
if isCompose {
if composeErr != nil {
return nil, nil, composeErr
@ -336,7 +340,7 @@ func ParseFiles(files []File, defaults map[string]string) (_ *Config, _ *hclpars
}
if len(composeFiles) > 0 {
cfg, cmperr := ParseComposeFiles(composeFiles)
cfg, cmperr := ParseComposeFiles(composeFiles, envOverrides)
if cmperr != nil {
return nil, nil, errors.Wrap(cmperr, "failed to parse compose file")
}
@ -374,6 +378,28 @@ func ParseFiles(files []File, defaults map[string]string) (_ *Config, _ *hclpars
return &c, &pm, nil
}
// Considering overrides are "targetpattern.key=value"
// Parse env overrides like example "env.key=value"
func parseEnvOverrides(overrides []string) (map[string]string, error) {
envs := make(map[string]string)
for _, o := range overrides {
parts := strings.SplitN(o, "=", 2)
if len(parts) != 2 {
return nil, errors.Errorf("invalid env override %q", o)
}
key := strings.TrimSpace(parts[0])
value := strings.TrimSpace(parts[1])
if strings.HasPrefix(key, "env.") {
strippedKey := strings.TrimPrefix(key, "env.")
if strippedKey == "" || value == "" {
return nil, errors.Errorf("invalid env override %q", o)
}
envs[strippedKey] = value
}
}
return envs, nil
}
func dedupeConfig(c Config) Config {
c2 := c
c2.Groups = make([]*Group, 0, len(c2.Groups))
@ -396,7 +422,7 @@ func dedupeConfig(c Config) Config {
}
func ParseFile(dt []byte, fn string) (*Config, error) {
c, _, err := ParseFiles([]File{{Data: dt, Name: fn}}, nil)
c, _, err := ParseFiles([]File{{Data: dt, Name: fn}}, nil, nil)
return c, err
}

View File

@ -1641,7 +1641,7 @@ services:
c, _, err := ParseFiles([]File{
{Data: dt, Name: "c1.foo"},
{Data: dt2, Name: "c2.bar"},
}, nil)
}, nil, nil)
require.NoError(t, err)
require.Equal(t, 1, len(c.Targets))

View File

@ -19,8 +19,8 @@ import (
"gopkg.in/yaml.v3"
)
func ParseComposeFiles(fs []File) (*Config, error) {
envs, err := composeEnv()
func ParseComposeFiles(fs []File, envOverrides map[string]string) (*Config, error) {
envs, err := composeEnv(envOverrides)
if err != nil {
return nil, err
}
@ -199,8 +199,8 @@ func ParseCompose(cfgs []composetypes.ConfigFile, envs map[string]string) (*Conf
return &c, nil
}
func validateComposeFile(dt []byte, fn string) (bool, error) {
envs, err := composeEnv()
func validateComposeFile(dt []byte, fn string, envOverrides map[string]string) (bool, error) {
envs, err := composeEnv(envOverrides)
if err != nil {
return true, err
}
@ -233,7 +233,7 @@ func validateCompose(dt []byte, envs map[string]string) error {
return err
}
func composeEnv() (map[string]string, error) {
func composeEnv(envOverrides map[string]string) (map[string]string, error) {
envs := sliceToMap(os.Environ())
if wd, err := os.Getwd(); err == nil {
envs, err = loadDotEnv(envs, wd)
@ -241,6 +241,12 @@ func composeEnv() (map[string]string, error) {
return nil, err
}
}
if envOverrides != nil {
// Apply envOverrides on envs
for key, value := range envOverrides {
envs[key] = value
}
}
return envs, nil
}

View File

@ -437,7 +437,33 @@ services:
c, err := ParseComposeFiles([]File{{
Name: "docker-compose.yml",
Data: dt,
}})
}}, nil)
require.NoError(t, err)
require.Equal(t, map[string]*string{"FOO": ptrstr("bar")}, c.Targets[0].Args)
}
func TestEnvOverrides(t *testing.T) {
tmpdir := t.TempDir()
overrides := []string{"env.FOO=bar"}
envOverrides, err := parseEnvOverrides(overrides)
require.NoError(t, err)
dt := []byte(`
services:
scratch:
build:
context: .
args:
FOO:
`)
chdir(t, tmpdir)
c, err := ParseComposeFiles([]File{{
Name: "docker-compose.yml",
Data: dt,
}}, envOverrides)
require.NoError(t, err)
require.Equal(t, map[string]*string{"FOO": ptrstr("bar")}, c.Targets[0].Args)
}
@ -664,7 +690,7 @@ target "default" {
}
for _, tt := range cases {
t.Run(tt.name, func(t *testing.T) {
isCompose, err := validateComposeFile(tt.dt, tt.fn)
isCompose, err := validateComposeFile(tt.dt, tt.fn, nil)
assert.Equal(t, tt.isCompose, isCompose)
if tt.wantErr {
require.Error(t, err)
@ -738,7 +764,7 @@ services:
c, err := ParseComposeFiles([]File{{
Name: "composetypes.yml",
Data: dt,
}})
}}, nil)
require.NoError(t, err)
require.Equal(t, 2, len(c.Targets))

View File

@ -284,7 +284,7 @@ func TestHCLMultiFileSharedVariables(t *testing.T) {
c, _, err := ParseFiles([]File{
{Data: dt, Name: "c1.hcl"},
{Data: dt2, Name: "c2.hcl"},
}, nil)
}, nil, nil)
require.NoError(t, err)
require.Equal(t, 1, len(c.Targets))
require.Equal(t, "app", c.Targets[0].Name)
@ -296,7 +296,7 @@ func TestHCLMultiFileSharedVariables(t *testing.T) {
c, _, err = ParseFiles([]File{
{Data: dt, Name: "c1.hcl"},
{Data: dt2, Name: "c2.hcl"},
}, nil)
}, nil, nil)
require.NoError(t, err)
require.Equal(t, 1, len(c.Targets))
@ -333,7 +333,7 @@ func TestHCLVarsWithVars(t *testing.T) {
c, _, err := ParseFiles([]File{
{Data: dt, Name: "c1.hcl"},
{Data: dt2, Name: "c2.hcl"},
}, nil)
}, nil, nil)
require.NoError(t, err)
require.Equal(t, 1, len(c.Targets))
require.Equal(t, "app", c.Targets[0].Name)
@ -345,7 +345,7 @@ func TestHCLVarsWithVars(t *testing.T) {
c, _, err = ParseFiles([]File{
{Data: dt, Name: "c1.hcl"},
{Data: dt2, Name: "c2.hcl"},
}, nil)
}, nil, nil)
require.NoError(t, err)
require.Equal(t, 1, len(c.Targets))
@ -841,7 +841,7 @@ func TestHCLMultiFileAttrs(t *testing.T) {
c, _, err := ParseFiles([]File{
{Data: dt, Name: "c1.hcl"},
{Data: dt2, Name: "c2.hcl"},
}, nil)
}, nil, nil)
require.NoError(t, err)
require.Equal(t, 1, len(c.Targets))
require.Equal(t, "app", c.Targets[0].Name)
@ -852,7 +852,7 @@ func TestHCLMultiFileAttrs(t *testing.T) {
c, _, err = ParseFiles([]File{
{Data: dt, Name: "c1.hcl"},
{Data: dt2, Name: "c2.hcl"},
}, nil)
}, nil, nil)
require.NoError(t, err)
require.Equal(t, 1, len(c.Targets))
@ -876,7 +876,7 @@ func TestHCLMultiFileGlobalAttrs(t *testing.T) {
c, _, err := ParseFiles([]File{
{Data: dt, Name: "c1.hcl"},
{Data: dt2, Name: "c2.hcl"},
}, nil)
}, nil, nil)
require.NoError(t, err)
require.Equal(t, 1, len(c.Targets))
require.Equal(t, "app", c.Targets[0].Name)
@ -1060,7 +1060,7 @@ func TestHCLRenameMultiFile(t *testing.T) {
{Data: dt, Name: "c1.hcl"},
{Data: dt2, Name: "c2.hcl"},
{Data: dt3, Name: "c3.hcl"},
}, nil)
}, nil, nil)
require.NoError(t, err)
require.Equal(t, 2, len(c.Targets))
@ -1278,7 +1278,7 @@ func TestHCLMatrixArgsOverride(t *testing.T) {
c, _, err := ParseFiles([]File{
{Data: dt, Name: "docker-bake.hcl"},
}, map[string]string{"ABC": "11,22,33"})
}, nil, map[string]string{"ABC": "11,22,33"})
require.NoError(t, err)
require.Equal(t, 3, len(c.Targets))
@ -1465,7 +1465,7 @@ services:
c, _, err := ParseFiles([]File{
{Data: dt, Name: "c1.hcl"},
{Data: dt2, Name: "c2.yml"},
}, nil)
}, nil, nil)
require.NoError(t, err)
require.Equal(t, 1, len(c.Targets))
@ -1486,7 +1486,7 @@ func TestHCLBuiltinVars(t *testing.T) {
c, _, err := ParseFiles([]File{
{Data: dt, Name: "c1.hcl"},
}, map[string]string{
}, nil, map[string]string{
"BAKE_CMD_CONTEXT": "foo",
})
require.NoError(t, err)
@ -1549,7 +1549,7 @@ target "b" {
}]
}`),
},
}, nil)
}, nil, nil)
require.NoError(t, err)
require.Equal(t, 1, len(c.Groups))
@ -1606,7 +1606,7 @@ target "two" {
Name: "bar.json",
Data: []byte(`{"ABC": "ghi", "DEF": "jkl"}`),
},
}, nil)
}, nil, nil)
require.NoError(t, err)
require.Equal(t, 1, len(c.Groups))
@ -2267,6 +2267,7 @@ func TestJSONOverridePriority(t *testing.T) {
t.Setenv("FOO_JSON", "[3,4,5]")
c, _, err := ParseFiles(
[]File{{Name: "docker-bake.hcl", Data: dt}},
nil,
map[string]string{"FOO_JSON": "whatever"},
)
require.NoError(t, err)

View File

@ -198,7 +198,7 @@ func runBake(ctx context.Context, dockerCli command.Cli, targets []string, in ba
}
if in.list != "" {
cfg, pm, err := bake.ParseFiles(files, defaults)
cfg, pm, err := bake.ParseFiles(files, overrides, defaults)
if err != nil {
return err
}