Allow bake files to be specified via environment variable
The environment variable `BUILDX_BAKE_FILE` (and optional variable `BUILDX_BAKE_FILE_SEPARATOR`) can be used to specify one or more bake files (similar to `compose`). This is mutually exclusive with`--file` (which takes precedence). This is done very early to ensure the values are treated just like `--file`, e.g., participate in telemetry. This includes leaving relative paths as-is, which deviates from `compose` (which makes them absolute). Signed-off-by: Roberto Villarreal <rrjjvv@yahoo.com>
This commit is contained in:
@@ -40,6 +40,11 @@ import (
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
)
|
||||
|
||||
const (
|
||||
bakeEnvFileSeparator = "BUILDX_BAKE_PATH_SEPARATOR"
|
||||
bakeEnvFilePath = "BUILDX_BAKE_FILE"
|
||||
)
|
||||
|
||||
type bakeOptions struct {
|
||||
files []string
|
||||
overrides []string
|
||||
@@ -452,6 +457,13 @@ func bakeCmd(dockerCli command.Cli, rootOpts *rootOptions) *cobra.Command {
|
||||
Aliases: []string{"f"},
|
||||
Short: "Build from a file",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if len(options.files) == 0 {
|
||||
envFiles, err := bakeEnvFiles(os.LookupEnv)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
options.files = envFiles
|
||||
}
|
||||
// reset to nil to avoid override is unset
|
||||
if !cmd.Flags().Lookup("no-cache").Changed {
|
||||
cFlags.noCache = nil
|
||||
@@ -504,6 +516,37 @@ func bakeCmd(dockerCli command.Cli, rootOpts *rootOptions) *cobra.Command {
|
||||
return cmd
|
||||
}
|
||||
|
||||
func bakeEnvFiles(lookup func(string string) (string, bool)) ([]string, error) {
|
||||
sep, _ := lookup(bakeEnvFileSeparator)
|
||||
if sep == "" {
|
||||
sep = string(os.PathListSeparator)
|
||||
}
|
||||
f, ok := lookup(bakeEnvFilePath)
|
||||
if ok {
|
||||
return cleanPaths(strings.Split(f, sep))
|
||||
}
|
||||
return []string{}, nil
|
||||
}
|
||||
|
||||
func cleanPaths(p []string) ([]string, error) {
|
||||
var paths []string
|
||||
for _, f := range p {
|
||||
f = strings.TrimSpace(f)
|
||||
if f == "" {
|
||||
continue
|
||||
}
|
||||
if f == "-" {
|
||||
paths = append(paths, f)
|
||||
continue
|
||||
}
|
||||
if _, err := os.Stat(f); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
paths = append(paths, f)
|
||||
}
|
||||
return paths, nil
|
||||
}
|
||||
|
||||
func saveLocalStateGroup(dockerCli command.Cli, in bakeOptions, targets []string, bo map[string]build.Options) error {
|
||||
l, err := localstate.New(confutil.NewConfig(dockerCli))
|
||||
if err != nil {
|
||||
|
||||
@@ -143,6 +143,11 @@ Use the `-f` / `--file` option to specify the build definition file to use.
|
||||
The file can be an HCL, JSON or Compose file. If multiple files are specified,
|
||||
all are read and the build configurations are combined.
|
||||
|
||||
Alternatively, the environment variable `BUILDX_BAKE_FILE` can be used to specify the build definition to use.
|
||||
This is mutually exclusive with `-f` / `--file`; if both are specified, the environment variable is ignored.
|
||||
Multiple definitions can be specified by separating them with the system's path separator
|
||||
(typically `;` on Windows and `:` elsewhere), but can be changed with `BUILDX_BAKE_PATH_SEPARATOR`.
|
||||
|
||||
You can pass the names of the targets to build, to build only specific target(s).
|
||||
The following example builds the `db` and `webapp-release` targets that are
|
||||
defined in the `docker-bake.dev.hcl` file:
|
||||
|
||||
+160
@@ -81,6 +81,7 @@ var bakeTests = []func(t *testing.T, sb integration.Sandbox){
|
||||
testBakeMultiPlatform,
|
||||
testBakeCheckCallOutput,
|
||||
testBakeExtraHosts,
|
||||
testBakeFileFromEnvironment,
|
||||
}
|
||||
|
||||
func testBakePrint(t *testing.T, sb integration.Sandbox) {
|
||||
@@ -2188,6 +2189,165 @@ target "default" {
|
||||
require.NoError(t, err, out)
|
||||
}
|
||||
|
||||
func testBakeFileFromEnvironment(t *testing.T, sb integration.Sandbox) {
|
||||
bakeFileFirst := []byte(`
|
||||
target "first" {
|
||||
dockerfile-inline = "FROM scratch\nCOPY first /"
|
||||
}
|
||||
`)
|
||||
bakeFileSecond := []byte(`
|
||||
target "second" {
|
||||
dockerfile-inline = "FROM scratch\nCOPY second /"
|
||||
}
|
||||
`)
|
||||
|
||||
t.Run("single file", func(t *testing.T) {
|
||||
dir := tmpdir(t,
|
||||
fstest.CreateFile("first.hcl", bakeFileFirst, 0600),
|
||||
fstest.CreateFile("first", []byte("first"), 0600),
|
||||
)
|
||||
cmd := buildxCmd(sb,
|
||||
withDir(dir),
|
||||
withArgs("bake", "--progress=plain", "first"),
|
||||
withEnv("BUILDX_BAKE_FILE=first.hcl"))
|
||||
|
||||
dt, err := cmd.CombinedOutput()
|
||||
require.NoError(t, err, string(dt))
|
||||
require.Contains(t, string(dt), `#1 [internal] load local bake definitions`)
|
||||
require.Contains(t, string(dt), `#1 reading first.hcl`)
|
||||
})
|
||||
|
||||
t.Run("single file, default ignored if present", func(t *testing.T) {
|
||||
dir := tmpdir(t,
|
||||
fstest.CreateFile("first.hcl", bakeFileFirst, 0600),
|
||||
fstest.CreateFile("first", []byte("first"), 0600),
|
||||
fstest.CreateFile("docker-bake.hcl", []byte("invalid bake file"), 0600),
|
||||
)
|
||||
cmd := buildxCmd(sb,
|
||||
withDir(dir),
|
||||
withArgs("bake", "--progress=plain", "first"),
|
||||
withEnv("BUILDX_BAKE_FILE=first.hcl"))
|
||||
|
||||
dt, err := cmd.CombinedOutput()
|
||||
require.NoError(t, err, string(dt))
|
||||
require.Contains(t, string(dt), `#1 [internal] load local bake definitions`)
|
||||
require.Contains(t, string(dt), `#1 reading first.hcl`)
|
||||
require.NotContains(t, string(dt), "docker-bake.hcl")
|
||||
})
|
||||
|
||||
t.Run("multiple files", func(t *testing.T) {
|
||||
dir := tmpdir(t,
|
||||
fstest.CreateFile("first.hcl", bakeFileFirst, 0600),
|
||||
fstest.CreateFile("first", []byte("first"), 0600),
|
||||
fstest.CreateFile("second.hcl", bakeFileSecond, 0600),
|
||||
fstest.CreateFile("second", []byte("second"), 0600),
|
||||
)
|
||||
|
||||
cmd := buildxCmd(sb,
|
||||
withDir(dir),
|
||||
withArgs("bake", "--progress=plain", "second", "first"),
|
||||
withEnv("BUILDX_BAKE_FILE=first.hcl"+string(os.PathListSeparator)+"second.hcl"))
|
||||
dt, err := cmd.CombinedOutput()
|
||||
require.NoError(t, err, string(dt))
|
||||
require.Contains(t, string(dt), `#1 [internal] load local bake definitions`)
|
||||
require.Contains(t, string(dt), `#1 reading first.hcl`)
|
||||
require.Contains(t, string(dt), `#1 reading second.hcl`)
|
||||
})
|
||||
|
||||
t.Run("multiple files, custom separator", func(t *testing.T) {
|
||||
dir := tmpdir(t,
|
||||
fstest.CreateFile("first.hcl", bakeFileFirst, 0600),
|
||||
fstest.CreateFile("first", []byte("first"), 0600),
|
||||
fstest.CreateFile("second.hcl", bakeFileSecond, 0600),
|
||||
fstest.CreateFile("second", []byte("second"), 0600),
|
||||
)
|
||||
|
||||
cmd := buildxCmd(sb,
|
||||
withDir(dir),
|
||||
withArgs("bake", "--progress=plain", "second", "first"),
|
||||
withEnv("BUILDX_BAKE_PATH_SEPARATOR=@", "BUILDX_BAKE_FILE=first.hcl@second.hcl"))
|
||||
|
||||
dt, err := cmd.CombinedOutput()
|
||||
require.NoError(t, err, string(dt))
|
||||
require.Contains(t, string(dt), `#1 [internal] load local bake definitions`)
|
||||
require.Contains(t, string(dt), `#1 reading first.hcl`)
|
||||
require.Contains(t, string(dt), `#1 reading second.hcl`)
|
||||
})
|
||||
|
||||
t.Run("multiple files, one STDIN", func(t *testing.T) {
|
||||
dir := tmpdir(t,
|
||||
fstest.CreateFile("first.hcl", bakeFileFirst, 0600),
|
||||
fstest.CreateFile("first", []byte("first"), 0600),
|
||||
fstest.CreateFile("second", []byte("second"), 0600),
|
||||
)
|
||||
|
||||
cmd := buildxCmd(sb,
|
||||
withDir(dir),
|
||||
withArgs("bake", "--progress=plain", "second", "first"),
|
||||
withEnv("BUILDX_BAKE_FILE=first.hcl"+string(os.PathListSeparator)+"-"))
|
||||
w, err := cmd.StdinPipe()
|
||||
require.NoError(t, err)
|
||||
go func() {
|
||||
defer w.Close()
|
||||
w.Write(bakeFileSecond)
|
||||
}()
|
||||
|
||||
dt, err := cmd.CombinedOutput()
|
||||
require.NoError(t, err, string(dt))
|
||||
require.Contains(t, string(dt), `#1 [internal] load local bake definitions`)
|
||||
require.Contains(t, string(dt), `#1 reading first.hcl`)
|
||||
require.Contains(t, string(dt), `#1 reading from stdin`)
|
||||
})
|
||||
|
||||
t.Run("env ignored if file arg passed", func(t *testing.T) {
|
||||
dir := tmpdir(t,
|
||||
fstest.CreateFile("first.hcl", bakeFileFirst, 0600),
|
||||
fstest.CreateFile("first", []byte("first"), 0600),
|
||||
fstest.CreateFile("second.hcl", bakeFileSecond, 0600),
|
||||
)
|
||||
cmd := buildxCmd(sb,
|
||||
withDir(dir),
|
||||
withArgs("bake", "--progress=plain", "-f", "first.hcl", "first", "second"),
|
||||
withEnv("BUILDX_BAKE_FILE=second.hcl"))
|
||||
|
||||
dt, err := cmd.CombinedOutput()
|
||||
require.Error(t, err, string(dt))
|
||||
require.Contains(t, string(dt), "failed to find target second")
|
||||
})
|
||||
|
||||
t.Run("file does not exist", func(t *testing.T) {
|
||||
dir := tmpdir(t,
|
||||
fstest.CreateFile("first.hcl", bakeFileFirst, 0600),
|
||||
fstest.CreateFile("first", []byte("first"), 0600),
|
||||
)
|
||||
cmd := buildxCmd(sb,
|
||||
withDir(dir),
|
||||
withArgs("bake", "--progress=plain", "first"),
|
||||
withEnv("BUILDX_BAKE_FILE=wrong.hcl"))
|
||||
|
||||
dt, err := cmd.CombinedOutput()
|
||||
require.Error(t, err, string(dt))
|
||||
require.Contains(t, string(dt), "wrong.hcl: no such file or directory")
|
||||
})
|
||||
|
||||
for kind, val := range map[string]string{"missing": "", "whitespace": " "} {
|
||||
t.Run(kind+" value ignored", func(t *testing.T) {
|
||||
dir := tmpdir(t,
|
||||
fstest.CreateFile("first.hcl", bakeFileFirst, 0600),
|
||||
fstest.CreateFile("first", []byte("first"), 0600),
|
||||
)
|
||||
cmd := buildxCmd(sb,
|
||||
withDir(dir),
|
||||
withArgs("bake", "--progress=plain", "first"),
|
||||
withEnv(fmt.Sprintf("BUILDX_BAKE_FILE=%s", val)))
|
||||
|
||||
dt, err := cmd.CombinedOutput()
|
||||
require.Error(t, err, string(dt))
|
||||
require.Contains(t, string(dt), "couldn't find a bake definition")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func writeTempPrivateKey(fp string) error {
|
||||
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user