github.com/buildtool/build-tools@v0.2.29-0.20240322150259-6a1d0a553c23/pkg/build/build_test.go (about)

     1  // MIT License
     2  //
     3  // Copyright (c) 2018 buildtool
     4  //
     5  // Permission is hereby granted, free of charge, to any person obtaining a copy
     6  // of this software and associated documentation files (the "Software"), to deal
     7  // in the Software without restriction, including without limitation the rights
     8  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     9  // copies of the Software, and to permit persons to whom the Software is
    10  // furnished to do so, subject to the following conditions:
    11  //
    12  // The above copyright notice and this permission notice shall be included in all
    13  // copies or substantial portions of the Software.
    14  //
    15  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    16  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    17  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    18  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    19  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    20  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    21  // SOFTWARE.
    22  
    23  package build
    24  
    25  import (
    26  	"bufio"
    27  	"errors"
    28  	"fmt"
    29  	"io"
    30  	"os"
    31  	"path/filepath"
    32  	"strings"
    33  	"testing"
    34  
    35  	"github.com/apex/log"
    36  	"github.com/docker/docker/api/types"
    37  	mocks "gitlab.com/unboundsoftware/apex-mocks"
    38  
    39  	"github.com/stretchr/testify/assert"
    40  
    41  	"github.com/buildtool/build-tools/pkg"
    42  	"github.com/buildtool/build-tools/pkg/args"
    43  	"github.com/buildtool/build-tools/pkg/docker"
    44  )
    45  
    46  var name string
    47  
    48  func TestMain(m *testing.M) {
    49  	buildToolsTempDir, osTempDir := setup()
    50  	setupSession = func(dir string) Session {
    51  		return &MockSession{}
    52  	}
    53  	code := m.Run()
    54  	teardown(buildToolsTempDir, osTempDir)
    55  	os.Exit(code)
    56  }
    57  
    58  func setup() (string, string) {
    59  	name, _ = os.MkdirTemp(os.TempDir(), "build-tools")
    60  	temp, _ := os.MkdirTemp(os.TempDir(), "build-tools-temp")
    61  	os.Clearenv()
    62  	_ = os.Setenv("TMPDIR", temp)
    63  	_ = os.Setenv("TEMP", temp)
    64  
    65  	return name, temp
    66  }
    67  
    68  func teardown(buildToolsTempDir, osTempDir string) {
    69  	_ = os.RemoveAll(buildToolsTempDir)
    70  	_ = os.RemoveAll(osTempDir)
    71  }
    72  
    73  func TestBuild_BrokenConfig(t *testing.T) {
    74  	yaml := `ci: [] `
    75  	file := filepath.Join(name, ".buildtools.yaml")
    76  	_ = os.WriteFile(file, []byte(yaml), 0777)
    77  	defer func() { _ = os.Remove(file) }()
    78  
    79  	logMock := mocks.New()
    80  	log.SetHandler(logMock)
    81  	log.SetLevel(log.DebugLevel)
    82  	client := &docker.MockDocker{}
    83  	defer func() { _ = os.RemoveAll(name) }()
    84  	_ = write(name, "Dockerfile", "FROM scratch")
    85  	err := build(client, name, Args{
    86  		Globals:    args.Globals{},
    87  		Dockerfile: "Dockerfile",
    88  		BuildArgs:  nil,
    89  		NoLogin:    false,
    90  		NoPull:     false,
    91  	})
    92  
    93  	absPath, _ := filepath.Abs(filepath.Join(name, ".buildtools.yaml"))
    94  	assert.EqualError(t, err, "yaml: unmarshal errors:\n  line 1: cannot unmarshal !!seq into config.CIConfig")
    95  	logMock.Check(t, []string{fmt.Sprintf("debug: Parsing config from file: <green>'%s'</green>\n", absPath)})
    96  }
    97  
    98  func TestBuild_NoRegistry(t *testing.T) {
    99  	defer func() { _ = os.RemoveAll(name) }()
   100  	_ = write(name, "Dockerfile", "FROM scratch")
   101  
   102  	defer pkg.SetEnv("CI_COMMIT_SHA", "abc123")()
   103  	defer pkg.SetEnv("CI_PROJECT_NAME", "reponame")()
   104  	defer pkg.SetEnv("CI_COMMIT_REF_NAME", "feature1")()
   105  
   106  	logMock := mocks.New()
   107  	log.SetHandler(logMock)
   108  	log.SetLevel(log.DebugLevel)
   109  	tmpDockerClient := dockerClient
   110  	dockerClient = func() (client docker.Client, e error) {
   111  		return &docker.MockDocker{}, nil
   112  	}
   113  	defer func() { dockerClient = tmpDockerClient }()
   114  
   115  	err := DoBuild(name, Args{Dockerfile: "Dockerfile"})
   116  	assert.NoError(t, err)
   117  	logMock.Check(t, []string{"debug: Using CI <green>Gitlab</green>\n",
   118  		"debug: Using registry <green>No docker registry</green>\n",
   119  		"debug: Authenticating against registry <green>No docker registry</green>\n",
   120  		"debug: Authentication <yellow>not supported</yellow> for registry <green>No docker registry</green>\n",
   121  		"debug: Using build variables commit <green>abc123</green> on branch <green>feature1</green>\n",
   122  		"debug: performing docker build with options (auths removed):\ntags:\n    - noregistry/reponame:abc123\n    - noregistry/reponame:feature1\nsuppressoutput: false\nremotecontext: client-session\nnocache: false\nremove: true\nforceremove: false\npullparent: true\nisolation: \"\"\ncpusetcpus: \"\"\ncpusetmems: \"\"\ncpushares: 0\ncpuquota: 0\ncpuperiod: 0\nmemory: 0\nmemoryswap: -1\ncgroupparent: \"\"\nnetworkmode: \"\"\nshmsize: 268435456\ndockerfile: Dockerfile\nulimits: []\nbuildargs:\n    BUILDKIT_INLINE_CACHE: \"1\"\n    CI_BRANCH: feature1\n    CI_COMMIT: abc123\nauthconfigs: {}\ncontext: null\nlabels: {}\nsquash: false\ncachefrom:\n    - noregistry/reponame:feature1\n    - noregistry/reponame:latest\nsecurityopt: []\nextrahosts: []\ntarget: \"\"\nsessionid: \"\"\nplatform: \"\"\nversion: \"2\"\nbuildid: \"\"\noutputs: []\n\n",
   123  		"info: Build successful"})
   124  }
   125  
   126  func TestBuild_LoginError(t *testing.T) {
   127  	defer pkg.SetEnv("CI_COMMIT_SHA", "abc123")()
   128  	defer pkg.SetEnv("CI_PROJECT_NAME", "reponame")()
   129  	defer pkg.SetEnv("CI_COMMIT_REF_NAME", "feature1")()
   130  	defer pkg.SetEnv("DOCKERHUB_NAMESPACE", "repo")()
   131  	defer pkg.SetEnv("DOCKERHUB_USERNAME", "user")()
   132  	defer pkg.SetEnv("DOCKERHUB_PASSWORD", "pass")()
   133  
   134  	logMock := mocks.New()
   135  	log.SetHandler(logMock)
   136  	log.SetLevel(log.DebugLevel)
   137  	client := &docker.MockDocker{LoginError: fmt.Errorf("invalid username/password")}
   138  	defer func() { _ = os.RemoveAll(name) }()
   139  	_ = write(name, "Dockerfile", "FROM scratch")
   140  	err := build(client, name, Args{
   141  		Globals:    args.Globals{},
   142  		Dockerfile: "Dockerfile",
   143  		BuildArgs:  nil,
   144  		NoLogin:    false,
   145  		NoPull:     false,
   146  	})
   147  
   148  	assert.EqualError(t, err, "invalid username/password")
   149  	logMock.Check(t, []string{
   150  		"debug: Using CI <green>Gitlab</green>\n",
   151  		"debug: Using registry <green>Dockerhub</green>\n",
   152  		"debug: Authenticating against registry <green>Dockerhub</green>\n",
   153  		"error: Unable to login\n"})
   154  }
   155  
   156  func TestBuild_NoCI(t *testing.T) {
   157  	defer pkg.SetEnv("DOCKERHUB_NAMESPACE", "repo")()
   158  	defer pkg.SetEnv("DOCKERHUB_USERNAME", "user")()
   159  	defer pkg.SetEnv("DOCKERHUB_PASSWORD", "pass")()
   160  
   161  	logMock := mocks.New()
   162  	log.SetHandler(logMock)
   163  	log.SetLevel(log.DebugLevel)
   164  	client := &docker.MockDocker{BuildError: []error{fmt.Errorf("build error")}}
   165  
   166  	_ = write(name, "Dockerfile", "FROM scratch")
   167  	err := build(client, name, Args{
   168  		Globals:    args.Globals{},
   169  		Dockerfile: "Dockerfile",
   170  		BuildArgs:  nil,
   171  		NoLogin:    false,
   172  		NoPull:     false,
   173  	})
   174  
   175  	assert.EqualError(t, err, "commit and/or branch information is <red>missing</red> (perhaps you're not in a Git repository or forgot to set environment variables?)")
   176  	logMock.Check(t, []string{
   177  		"debug: Using CI <green>none</green>\n",
   178  		"debug: Using registry <green>Dockerhub</green>\n",
   179  		"debug: Authenticating against registry <green>Dockerhub</green>\n",
   180  		"debug: Logged in\n",
   181  	})
   182  }
   183  
   184  func TestBuild_BuildError(t *testing.T) {
   185  	defer pkg.SetEnv("CI_COMMIT_SHA", "abc123")()
   186  	defer pkg.SetEnv("CI_PROJECT_NAME", "reponame")()
   187  	defer pkg.SetEnv("CI_COMMIT_REF_NAME", "feature1")()
   188  	defer pkg.SetEnv("DOCKERHUB_NAMESPACE", "repo")()
   189  	defer pkg.SetEnv("DOCKERHUB_USERNAME", "user")()
   190  	defer pkg.SetEnv("DOCKERHUB_PASSWORD", "pass")()
   191  
   192  	logMock := mocks.New()
   193  	log.SetHandler(logMock)
   194  	log.SetLevel(log.DebugLevel)
   195  	client := &docker.MockDocker{BuildError: []error{fmt.Errorf("build error")}}
   196  	defer func() { _ = os.RemoveAll(name) }()
   197  	_ = write(name, "Dockerfile", "FROM scratch")
   198  	err := build(client, name, Args{
   199  		Globals:    args.Globals{},
   200  		Dockerfile: "Dockerfile",
   201  		BuildArgs:  nil,
   202  		NoLogin:    false,
   203  		NoPull:     false,
   204  	})
   205  
   206  	assert.EqualError(t, err, "build error")
   207  	logMock.Check(t, []string{
   208  		"debug: Using CI <green>Gitlab</green>\n",
   209  		"debug: Using registry <green>Dockerhub</green>\n",
   210  		"debug: Authenticating against registry <green>Dockerhub</green>\n",
   211  		"debug: Logged in\n",
   212  		"debug: Using build variables commit <green>abc123</green> on branch <green>feature1</green>\n",
   213  		"debug: performing docker build with options (auths removed):\ntags:\n    - repo/reponame:abc123\n    - repo/reponame:feature1\nsuppressoutput: false\nremotecontext: client-session\nnocache: false\nremove: true\nforceremove: false\npullparent: true\nisolation: \"\"\ncpusetcpus: \"\"\ncpusetmems: \"\"\ncpushares: 0\ncpuquota: 0\ncpuperiod: 0\nmemory: 0\nmemoryswap: -1\ncgroupparent: \"\"\nnetworkmode: \"\"\nshmsize: 268435456\ndockerfile: Dockerfile\nulimits: []\nbuildargs:\n    BUILDKIT_INLINE_CACHE: \"1\"\n    CI_BRANCH: feature1\n    CI_COMMIT: abc123\nauthconfigs: {}\ncontext: null\nlabels: {}\nsquash: false\ncachefrom:\n    - repo/reponame:feature1\n    - repo/reponame:latest\nsecurityopt: []\nextrahosts: []\ntarget: \"\"\nsessionid: \"\"\nplatform: \"\"\nversion: \"2\"\nbuildid: \"\"\noutputs: []\n\n",
   214  	})
   215  }
   216  
   217  func TestBuild_BuildResponseError(t *testing.T) {
   218  	defer pkg.SetEnv("CI_COMMIT_SHA", "abc123")()
   219  	defer pkg.SetEnv("CI_PROJECT_NAME", "reponame")()
   220  	defer pkg.SetEnv("CI_COMMIT_REF_NAME", "feature1")()
   221  	defer pkg.SetEnv("DOCKERHUB_NAMESPACE", "repo")()
   222  	defer pkg.SetEnv("DOCKERHUB_USERNAME", "user")()
   223  	defer pkg.SetEnv("DOCKERHUB_PASSWORD", "pass")()
   224  
   225  	logMock := mocks.New()
   226  	log.SetHandler(logMock)
   227  	log.SetLevel(log.DebugLevel)
   228  	client := &docker.MockDocker{ResponseError: fmt.Errorf("build error")}
   229  	defer func() { _ = os.RemoveAll(name) }()
   230  	_ = write(name, "Dockerfile", "FROM scratch")
   231  	err := build(client, name, Args{
   232  		Globals:    args.Globals{},
   233  		Dockerfile: "Dockerfile",
   234  		BuildArgs:  nil,
   235  		NoLogin:    false,
   236  		NoPull:     false,
   237  	})
   238  
   239  	assert.EqualError(t, err, "code: 123, status: build error")
   240  	logMock.Check(t, []string{
   241  		"debug: Using CI <green>Gitlab</green>\n",
   242  		"debug: Using registry <green>Dockerhub</green>\n",
   243  		"debug: Authenticating against registry <green>Dockerhub</green>\n",
   244  		"debug: Logged in\n",
   245  		"debug: Using build variables commit <green>abc123</green> on branch <green>feature1</green>\n",
   246  		"debug: performing docker build with options (auths removed):\ntags:\n    - repo/reponame:abc123\n    - repo/reponame:feature1\nsuppressoutput: false\nremotecontext: client-session\nnocache: false\nremove: true\nforceremove: false\npullparent: true\nisolation: \"\"\ncpusetcpus: \"\"\ncpusetmems: \"\"\ncpushares: 0\ncpuquota: 0\ncpuperiod: 0\nmemory: 0\nmemoryswap: -1\ncgroupparent: \"\"\nnetworkmode: \"\"\nshmsize: 268435456\ndockerfile: Dockerfile\nulimits: []\nbuildargs:\n    BUILDKIT_INLINE_CACHE: \"1\"\n    CI_BRANCH: feature1\n    CI_COMMIT: abc123\nauthconfigs: {}\ncontext: null\nlabels: {}\nsquash: false\ncachefrom:\n    - repo/reponame:feature1\n    - repo/reponame:latest\nsecurityopt: []\nextrahosts: []\ntarget: \"\"\nsessionid: \"\"\nplatform: \"\"\nversion: \"2\"\nbuildid: \"\"\noutputs: []\n\n",
   247  	})
   248  }
   249  
   250  func TestBuild_ErrorOutput(t *testing.T) {
   251  	defer pkg.SetEnv("CI_COMMIT_SHA", "abc123")()
   252  	defer pkg.SetEnv("CI_PROJECT_NAME", "reponame")()
   253  	defer pkg.SetEnv("CI_COMMIT_REF_NAME", "feature1")()
   254  	defer pkg.SetEnv("DOCKERHUB_NAMESPACE", "repo")()
   255  	defer pkg.SetEnv("DOCKERHUB_USERNAME", "user")()
   256  	defer pkg.SetEnv("DOCKERHUB_PASSWORD", "pass")()
   257  
   258  	logMock := mocks.New()
   259  	log.SetHandler(logMock)
   260  	log.SetLevel(log.DebugLevel)
   261  	client := &docker.MockDocker{BrokenOutput: true}
   262  	defer func() { _ = os.RemoveAll(name) }()
   263  	_ = write(name, "Dockerfile", "FROM scratch")
   264  	err := build(client, name, Args{
   265  		Globals:    args.Globals{},
   266  		Dockerfile: "Dockerfile",
   267  		BuildArgs:  nil,
   268  		NoLogin:    false,
   269  		NoPull:     false,
   270  	})
   271  
   272  	assert.EqualError(t, err, "code: 1, status: some message")
   273  	logMock.Check(t, []string{
   274  		"debug: Using CI <green>Gitlab</green>\n",
   275  		"debug: Using registry <green>Dockerhub</green>\n",
   276  		"debug: Authenticating against registry <green>Dockerhub</green>\n",
   277  		"debug: Logged in\n",
   278  		"debug: Using build variables commit <green>abc123</green> on branch <green>feature1</green>\n",
   279  		"debug: performing docker build with options (auths removed):\ntags:\n    - repo/reponame:abc123\n    - repo/reponame:feature1\nsuppressoutput: false\nremotecontext: client-session\nnocache: false\nremove: true\nforceremove: false\npullparent: true\nisolation: \"\"\ncpusetcpus: \"\"\ncpusetmems: \"\"\ncpushares: 0\ncpuquota: 0\ncpuperiod: 0\nmemory: 0\nmemoryswap: -1\ncgroupparent: \"\"\nnetworkmode: \"\"\nshmsize: 268435456\ndockerfile: Dockerfile\nulimits: []\nbuildargs:\n    BUILDKIT_INLINE_CACHE: \"1\"\n    CI_BRANCH: feature1\n    CI_COMMIT: abc123\nauthconfigs: {}\ncontext: null\nlabels: {}\nsquash: false\ncachefrom:\n    - repo/reponame:feature1\n    - repo/reponame:latest\nsecurityopt: []\nextrahosts: []\ntarget: \"\"\nsessionid: \"\"\nplatform: \"\"\nversion: \"2\"\nbuildid: \"\"\noutputs: []\n\n",
   280  	})
   281  }
   282  
   283  func TestBuild_ValidOutput(t *testing.T) {
   284  	defer pkg.SetEnv("CI_COMMIT_SHA", "abc123")()
   285  	defer pkg.SetEnv("CI_PROJECT_NAME", "reponame")()
   286  	defer pkg.SetEnv("CI_COMMIT_REF_NAME", "feature1")()
   287  	defer pkg.SetEnv("DOCKERHUB_NAMESPACE", "repo")()
   288  	defer pkg.SetEnv("DOCKERHUB_USERNAME", "user")()
   289  	defer pkg.SetEnv("DOCKERHUB_PASSWORD", "pass")()
   290  
   291  	f, err := os.Open("testdata/build_body.txt")
   292  	assert.NoError(t, err)
   293  	logMock := mocks.New()
   294  	log.SetHandler(logMock)
   295  	log.SetLevel(log.DebugLevel)
   296  	client := &docker.MockDocker{ResponseBody: bufio.NewReader(f)}
   297  	defer func() { _ = os.RemoveAll(name) }()
   298  	_ = write(name, "Dockerfile", "FROM scratch")
   299  	err = build(client, name, Args{
   300  		Globals:    args.Globals{},
   301  		Dockerfile: "Dockerfile",
   302  		BuildArgs:  nil,
   303  		NoLogin:    false,
   304  		NoPull:     false,
   305  	})
   306  
   307  	assert.NoError(t, err)
   308  	logMock.Check(t, []string{
   309  		"debug: Using CI <green>Gitlab</green>\n",
   310  		"debug: Using registry <green>Dockerhub</green>\n",
   311  		"debug: Authenticating against registry <green>Dockerhub</green>\n",
   312  		"debug: Logged in\n",
   313  		"debug: Using build variables commit <green>abc123</green> on branch <green>feature1</green>\n",
   314  		"debug: performing docker build with options (auths removed):\ntags:\n    - repo/reponame:abc123\n    - repo/reponame:feature1\nsuppressoutput: false\nremotecontext: client-session\nnocache: false\nremove: true\nforceremove: false\npullparent: true\nisolation: \"\"\ncpusetcpus: \"\"\ncpusetmems: \"\"\ncpushares: 0\ncpuquota: 0\ncpuperiod: 0\nmemory: 0\nmemoryswap: -1\ncgroupparent: \"\"\nnetworkmode: \"\"\nshmsize: 268435456\ndockerfile: Dockerfile\nulimits: []\nbuildargs:\n    BUILDKIT_INLINE_CACHE: \"1\"\n    CI_BRANCH: feature1\n    CI_COMMIT: abc123\nauthconfigs: {}\ncontext: null\nlabels: {}\nsquash: false\ncachefrom:\n    - repo/reponame:feature1\n    - repo/reponame:latest\nsecurityopt: []\nextrahosts: []\ntarget: \"\"\nsessionid: \"\"\nplatform: \"\"\nversion: \"2\"\nbuildid: \"\"\noutputs: []\n\n",
   315  		"info: 1: msg 1\n2: msg 2\n",
   316  	})
   317  }
   318  
   319  func TestBuild_BrokenBuildResult(t *testing.T) {
   320  	defer pkg.SetEnv("CI_COMMIT_SHA", "abc123")()
   321  	defer pkg.SetEnv("CI_PROJECT_NAME", "reponame")()
   322  	defer pkg.SetEnv("CI_COMMIT_REF_NAME", "feature1")()
   323  	defer pkg.SetEnv("DOCKERHUB_NAMESPACE", "repo")()
   324  	defer pkg.SetEnv("DOCKERHUB_USERNAME", "user")()
   325  	defer pkg.SetEnv("DOCKERHUB_PASSWORD", "pass")()
   326  
   327  	logMock := mocks.New()
   328  	log.SetHandler(logMock)
   329  	log.SetLevel(log.DebugLevel)
   330  	client := &docker.MockDocker{ResponseBody: strings.NewReader(`{"id":"moby.image.id","aux":{"id":123}}`)}
   331  	defer func() { _ = os.RemoveAll(name) }()
   332  	_ = write(name, "Dockerfile", "FROM scratch")
   333  	err := build(client, name, Args{
   334  		Globals:    args.Globals{},
   335  		Dockerfile: "Dockerfile",
   336  		BuildArgs:  nil,
   337  		NoLogin:    false,
   338  		NoPull:     false,
   339  	})
   340  
   341  	assert.NoError(t, err)
   342  	logMock.Check(t, []string{
   343  		"debug: Using CI <green>Gitlab</green>\n",
   344  		"debug: Using registry <green>Dockerhub</green>\n",
   345  		"debug: Authenticating against registry <green>Dockerhub</green>\n",
   346  		"debug: Logged in\n",
   347  		"debug: Using build variables commit <green>abc123</green> on branch <green>feature1</green>\n",
   348  		"debug: performing docker build with options (auths removed):\ntags:\n    - repo/reponame:abc123\n    - repo/reponame:feature1\nsuppressoutput: false\nremotecontext: client-session\nnocache: false\nremove: true\nforceremove: false\npullparent: true\nisolation: \"\"\ncpusetcpus: \"\"\ncpusetmems: \"\"\ncpushares: 0\ncpuquota: 0\ncpuperiod: 0\nmemory: 0\nmemoryswap: -1\ncgroupparent: \"\"\nnetworkmode: \"\"\nshmsize: 268435456\ndockerfile: Dockerfile\nulimits: []\nbuildargs:\n    BUILDKIT_INLINE_CACHE: \"1\"\n    CI_BRANCH: feature1\n    CI_COMMIT: abc123\nauthconfigs: {}\ncontext: null\nlabels: {}\nsquash: false\ncachefrom:\n    - repo/reponame:feature1\n    - repo/reponame:latest\nsecurityopt: []\nextrahosts: []\ntarget: \"\"\nsessionid: \"\"\nplatform: \"\"\nversion: \"2\"\nbuildid: \"\"\noutputs: []\n\n",
   349  		"error: failed to parse aux message: json: cannot unmarshal number into Go struct field BuildResult.ID of type string",
   350  		"info: ",
   351  	})
   352  }
   353  
   354  func TestBuild_WithBuildArgs(t *testing.T) {
   355  	defer pkg.SetEnv("CI_PROJECT_NAME", "reponame")()
   356  	defer pkg.SetEnv("CI_COMMIT_REF_NAME", "master")()
   357  	defer pkg.SetEnv("CI_COMMIT_SHA", "sha")()
   358  	defer pkg.SetEnv("DOCKERHUB_NAMESPACE", "repo")()
   359  	client := &docker.MockDocker{}
   360  	defer func() { _ = os.RemoveAll(name) }()
   361  	_ = write(name, "Dockerfile", "FROM scratch")
   362  
   363  	err := build(client, name, Args{
   364  		Globals:    args.Globals{},
   365  		Dockerfile: "Dockerfile",
   366  		BuildArgs:  []string{"buildargs1=1", "buildargs2=2"},
   367  		NoLogin:    false,
   368  		NoPull:     false,
   369  	})
   370  	assert.NoError(t, err)
   371  
   372  	assert.Equal(t, 5, len(client.BuildOptions[0].BuildArgs))
   373  	assert.Equal(t, "1", *client.BuildOptions[0].BuildArgs["buildargs1"])
   374  	assert.Equal(t, "2", *client.BuildOptions[0].BuildArgs["buildargs2"])
   375  }
   376  
   377  func TestBuild_WithStrangeBuildArg(t *testing.T) {
   378  	defer pkg.SetEnv("CI_PROJECT_NAME", "reponame")()
   379  	defer pkg.SetEnv("CI_COMMIT_REF_NAME", "master")()
   380  	defer pkg.SetEnv("CI_COMMIT_SHA", "sha")()
   381  	defer pkg.SetEnv("DOCKERHUB_NAMESPACE", "repo")()
   382  	defer pkg.SetEnv("buildargs4", "env-value")()
   383  	logMock := mocks.New()
   384  	log.SetHandler(logMock)
   385  	log.SetLevel(log.DebugLevel)
   386  	client := &docker.MockDocker{}
   387  	defer func() { _ = os.RemoveAll(name) }()
   388  	_ = write(name, "Dockerfile", "FROM scratch")
   389  
   390  	err := build(client, name, Args{
   391  		Globals:    args.Globals{},
   392  		Dockerfile: "Dockerfile",
   393  		BuildArgs:  []string{"buildargs1=1=1", "buildargs2", "buildargs3=", "buildargs4"},
   394  		NoLogin:    false,
   395  		NoPull:     false,
   396  	})
   397  	assert.NoError(t, err)
   398  
   399  	assert.Equal(t, 5, len(client.BuildOptions[0].BuildArgs))
   400  	assert.Equal(t, "1=1", *client.BuildOptions[0].BuildArgs["buildargs1"])
   401  	assert.Equal(t, "env-value", *client.BuildOptions[0].BuildArgs["buildargs4"])
   402  	logMock.Check(t, []string{
   403  		"debug: Using CI <green>Gitlab</green>\n",
   404  		"debug: Using registry <green>Dockerhub</green>\n",
   405  		"debug: Authenticating against registry <green>Dockerhub</green>\n",
   406  		"debug: Logged in\n",
   407  		"debug: Using build variables commit <green>sha</green> on branch <green>master</green>\n",
   408  		"debug: ignoring build-arg buildargs2\n",
   409  		"debug: ignoring build-arg buildargs3\n",
   410  		"debug: performing docker build with options (auths removed):\ntags:\n    - repo/reponame:sha\n    - repo/reponame:master\n    - repo/reponame:latest\nsuppressoutput: false\nremotecontext: client-session\nnocache: false\nremove: true\nforceremove: false\npullparent: true\nisolation: \"\"\ncpusetcpus: \"\"\ncpusetmems: \"\"\ncpushares: 0\ncpuquota: 0\ncpuperiod: 0\nmemory: 0\nmemoryswap: -1\ncgroupparent: \"\"\nnetworkmode: \"\"\nshmsize: 268435456\ndockerfile: Dockerfile\nulimits: []\nbuildargs:\n    BUILDKIT_INLINE_CACHE: \"1\"\n    CI_BRANCH: master\n    CI_COMMIT: sha\n    buildargs1: 1=1\n    buildargs4: env-value\nauthconfigs: {}\ncontext: null\nlabels: {}\nsquash: false\ncachefrom:\n    - repo/reponame:master\n    - repo/reponame:latest\nsecurityopt: []\nextrahosts: []\ntarget: \"\"\nsessionid: \"\"\nplatform: \"\"\nversion: \"2\"\nbuildid: \"\"\noutputs: []\n\n",
   411  		"info: Build successful"})
   412  }
   413  
   414  func TestBuild_WithPlatform(t *testing.T) {
   415  	defer pkg.SetEnv("CI_PROJECT_NAME", "reponame")()
   416  	defer pkg.SetEnv("CI_COMMIT_REF_NAME", "master")()
   417  	defer pkg.SetEnv("CI_COMMIT_SHA", "sha")()
   418  	defer pkg.SetEnv("DOCKERHUB_NAMESPACE", "repo")()
   419  	logMock := mocks.New()
   420  	log.SetHandler(logMock)
   421  	log.SetLevel(log.DebugLevel)
   422  	client := &docker.MockDocker{}
   423  	defer func() { _ = os.RemoveAll(name) }()
   424  	_ = write(name, "Dockerfile", "FROM scratch")
   425  
   426  	err := build(client, name, Args{
   427  		Globals:    args.Globals{},
   428  		Dockerfile: "Dockerfile",
   429  		NoLogin:    false,
   430  		NoPull:     false,
   431  		Platform:   "linux/amd64",
   432  	})
   433  	assert.NoError(t, err)
   434  
   435  	logMock.Check(t, []string{
   436  		"info: building for platform <green>linux/amd64</green>\n",
   437  		"debug: Using CI <green>Gitlab</green>\n",
   438  		"debug: Using registry <green>Dockerhub</green>\n",
   439  		"debug: Authenticating against registry <green>Dockerhub</green>\n",
   440  		"debug: Logged in\n",
   441  		"debug: Using build variables commit <green>sha</green> on branch <green>master</green>\n",
   442  		"debug: performing docker build with options (auths removed):\ntags:\n    - repo/reponame:sha\n    - repo/reponame:master\n    - repo/reponame:latest\nsuppressoutput: false\nremotecontext: client-session\nnocache: false\nremove: true\nforceremove: false\npullparent: true\nisolation: \"\"\ncpusetcpus: \"\"\ncpusetmems: \"\"\ncpushares: 0\ncpuquota: 0\ncpuperiod: 0\nmemory: 0\nmemoryswap: -1\ncgroupparent: \"\"\nnetworkmode: \"\"\nshmsize: 268435456\ndockerfile: Dockerfile\nulimits: []\nbuildargs:\n    BUILDKIT_INLINE_CACHE: \"1\"\n    CI_BRANCH: master\n    CI_COMMIT: sha\nauthconfigs: {}\ncontext: null\nlabels: {}\nsquash: false\ncachefrom:\n    - repo/reponame:master\n    - repo/reponame:latest\nsecurityopt: []\nextrahosts: []\ntarget: \"\"\nsessionid: \"\"\nplatform: linux/amd64\nversion: \"2\"\nbuildid: \"\"\noutputs: []\n\n",
   443  		"info: Build successful"})
   444  }
   445  
   446  func TestBuild_WithSkipLogin(t *testing.T) {
   447  	defer pkg.SetEnv("CI_PROJECT_NAME", "reponame")()
   448  	defer pkg.SetEnv("CI_COMMIT_REF_NAME", "master")()
   449  	defer pkg.SetEnv("CI_COMMIT_SHA", "sha")()
   450  	defer pkg.SetEnv("DOCKERHUB_NAMESPACE", "repo")()
   451  	logMock := mocks.New()
   452  	log.SetHandler(logMock)
   453  	log.SetLevel(log.DebugLevel)
   454  	defer func() { _ = os.RemoveAll(name) }()
   455  	_ = write(name, "Dockerfile", "FROM scratch")
   456  
   457  	client := &docker.MockDocker{}
   458  	err := build(client, name, Args{
   459  		Globals:    args.Globals{},
   460  		Dockerfile: "Dockerfile",
   461  		BuildArgs:  nil,
   462  		NoLogin:    true,
   463  		NoPull:     false,
   464  	})
   465  	assert.NoError(t, err)
   466  	logMock.Check(t, []string{
   467  		"debug: Using CI <green>Gitlab</green>\n",
   468  		"debug: Using registry <green>Dockerhub</green>\n",
   469  		"debug: Login <yellow>disabled</yellow>\n",
   470  		"debug: Using build variables commit <green>sha</green> on branch <green>master</green>\n",
   471  		"debug: performing docker build with options (auths removed):\ntags:\n    - repo/reponame:sha\n    - repo/reponame:master\n    - repo/reponame:latest\nsuppressoutput: false\nremotecontext: client-session\nnocache: false\nremove: true\nforceremove: false\npullparent: true\nisolation: \"\"\ncpusetcpus: \"\"\ncpusetmems: \"\"\ncpushares: 0\ncpuquota: 0\ncpuperiod: 0\nmemory: 0\nmemoryswap: -1\ncgroupparent: \"\"\nnetworkmode: \"\"\nshmsize: 268435456\ndockerfile: Dockerfile\nulimits: []\nbuildargs:\n    BUILDKIT_INLINE_CACHE: \"1\"\n    CI_BRANCH: master\n    CI_COMMIT: sha\nauthconfigs: {}\ncontext: null\nlabels: {}\nsquash: false\ncachefrom:\n    - repo/reponame:master\n    - repo/reponame:latest\nsecurityopt: []\nextrahosts: []\ntarget: \"\"\nsessionid: \"\"\nplatform: \"\"\nversion: \"2\"\nbuildid: \"\"\noutputs: []\n\n",
   472  		"info: Build successful"})
   473  }
   474  
   475  func TestBuild_FeatureBranch(t *testing.T) {
   476  	defer pkg.SetEnv("CI_COMMIT_SHA", "abc123")()
   477  	defer pkg.SetEnv("CI_PROJECT_NAME", "reponame")()
   478  	defer pkg.SetEnv("CI_COMMIT_REF_NAME", "feature1")()
   479  	defer pkg.SetEnv("DOCKERHUB_NAMESPACE", "repo")()
   480  	defer pkg.SetEnv("DOCKERHUB_USERNAME", "user")()
   481  	defer pkg.SetEnv("DOCKERHUB_PASSWORD", "pass")()
   482  
   483  	logMock := mocks.New()
   484  	log.SetHandler(logMock)
   485  	log.SetLevel(log.DebugLevel)
   486  	defer func() { _ = os.RemoveAll(name) }()
   487  	_ = write(name, "Dockerfile", "FROM scratch")
   488  
   489  	client := &docker.MockDocker{}
   490  	err := build(client, name, Args{
   491  		Globals:    args.Globals{},
   492  		Dockerfile: "Dockerfile",
   493  		BuildArgs:  nil,
   494  		NoLogin:    false,
   495  		NoPull:     false,
   496  	})
   497  
   498  	assert.NoError(t, err)
   499  	assert.Equal(t, "Dockerfile", client.BuildOptions[0].Dockerfile)
   500  	assert.Equal(t, 3, len(client.BuildOptions[0].BuildArgs))
   501  	assert.Equal(t, "abc123", *client.BuildOptions[0].BuildArgs["CI_COMMIT"])
   502  	assert.Equal(t, "feature1", *client.BuildOptions[0].BuildArgs["CI_BRANCH"])
   503  	assert.Equal(t, int64(-1), client.BuildOptions[0].MemorySwap)
   504  	assert.Equal(t, true, client.BuildOptions[0].Remove)
   505  	assert.Equal(t, int64(256*1024*1024), client.BuildOptions[0].ShmSize)
   506  	assert.Equal(t, []string{"repo/reponame:abc123", "repo/reponame:feature1"}, client.BuildOptions[0].Tags)
   507  	assert.Equal(t, "Dockerfile", client.BuildOptions[0].Dockerfile)
   508  	assert.Equal(t, int64(-1), client.BuildOptions[0].MemorySwap)
   509  	assert.Equal(t, true, client.BuildOptions[0].Remove)
   510  	assert.Equal(t, int64(256*1024*1024), client.BuildOptions[0].ShmSize)
   511  	assert.Equal(t, []string{"repo/reponame:abc123", "repo/reponame:feature1"}, client.BuildOptions[0].Tags)
   512  	logMock.Check(t, []string{"debug: Using CI <green>Gitlab</green>\n",
   513  		"debug: Using registry <green>Dockerhub</green>\n",
   514  		"debug: Authenticating against registry <green>Dockerhub</green>\n",
   515  		"debug: Logged in\n",
   516  		"debug: Using build variables commit <green>abc123</green> on branch <green>feature1</green>\n",
   517  		"debug: performing docker build with options (auths removed):\ntags:\n    - repo/reponame:abc123\n    - repo/reponame:feature1\nsuppressoutput: false\nremotecontext: client-session\nnocache: false\nremove: true\nforceremove: false\npullparent: true\nisolation: \"\"\ncpusetcpus: \"\"\ncpusetmems: \"\"\ncpushares: 0\ncpuquota: 0\ncpuperiod: 0\nmemory: 0\nmemoryswap: -1\ncgroupparent: \"\"\nnetworkmode: \"\"\nshmsize: 268435456\ndockerfile: Dockerfile\nulimits: []\nbuildargs:\n    BUILDKIT_INLINE_CACHE: \"1\"\n    CI_BRANCH: feature1\n    CI_COMMIT: abc123\nauthconfigs: {}\ncontext: null\nlabels: {}\nsquash: false\ncachefrom:\n    - repo/reponame:feature1\n    - repo/reponame:latest\nsecurityopt: []\nextrahosts: []\ntarget: \"\"\nsessionid: \"\"\nplatform: \"\"\nversion: \"2\"\nbuildid: \"\"\noutputs: []\n\n",
   518  		"info: Build successful"})
   519  }
   520  
   521  func TestBuild_MasterBranch(t *testing.T) {
   522  	defer pkg.SetEnv("CI_COMMIT_SHA", "abc123")()
   523  	defer pkg.SetEnv("CI_PROJECT_NAME", "reponame")()
   524  	defer pkg.SetEnv("CI_COMMIT_REF_NAME", "master")()
   525  	defer pkg.SetEnv("DOCKERHUB_NAMESPACE", "repo")()
   526  	defer pkg.SetEnv("DOCKERHUB_USERNAME", "user")()
   527  	defer pkg.SetEnv("DOCKERHUB_PASSWORD", "pass")()
   528  
   529  	logMock := mocks.New()
   530  	log.SetHandler(logMock)
   531  	log.SetLevel(log.DebugLevel)
   532  	client := &docker.MockDocker{}
   533  	defer func() { _ = os.RemoveAll(name) }()
   534  	_ = write(name, "Dockerfile", "FROM scratch")
   535  
   536  	err := build(client, name, Args{
   537  		Globals:    args.Globals{},
   538  		Dockerfile: "Dockerfile",
   539  		BuildArgs:  nil,
   540  		NoLogin:    false,
   541  		NoPull:     false,
   542  	})
   543  
   544  	assert.NoError(t, err)
   545  	assert.Equal(t, "Dockerfile", client.BuildOptions[0].Dockerfile)
   546  	assert.Equal(t, int64(-1), client.BuildOptions[0].MemorySwap)
   547  	assert.Equal(t, true, client.BuildOptions[0].Remove)
   548  	assert.Equal(t, int64(256*1024*1024), client.BuildOptions[0].ShmSize)
   549  	assert.Equal(t, []string{"repo/reponame:abc123", "repo/reponame:master", "repo/reponame:latest"}, client.BuildOptions[0].Tags)
   550  	logMock.Check(t, []string{"debug: Using CI <green>Gitlab</green>\n",
   551  		"debug: Using registry <green>Dockerhub</green>\n",
   552  		"debug: Authenticating against registry <green>Dockerhub</green>\n",
   553  		"debug: Logged in\n",
   554  		"debug: Using build variables commit <green>abc123</green> on branch <green>master</green>\n",
   555  		"debug: performing docker build with options (auths removed):\ntags:\n    - repo/reponame:abc123\n    - repo/reponame:master\n    - repo/reponame:latest\nsuppressoutput: false\nremotecontext: client-session\nnocache: false\nremove: true\nforceremove: false\npullparent: true\nisolation: \"\"\ncpusetcpus: \"\"\ncpusetmems: \"\"\ncpushares: 0\ncpuquota: 0\ncpuperiod: 0\nmemory: 0\nmemoryswap: -1\ncgroupparent: \"\"\nnetworkmode: \"\"\nshmsize: 268435456\ndockerfile: Dockerfile\nulimits: []\nbuildargs:\n    BUILDKIT_INLINE_CACHE: \"1\"\n    CI_BRANCH: master\n    CI_COMMIT: abc123\nauthconfigs: {}\ncontext: null\nlabels: {}\nsquash: false\ncachefrom:\n    - repo/reponame:master\n    - repo/reponame:latest\nsecurityopt: []\nextrahosts: []\ntarget: \"\"\nsessionid: \"\"\nplatform: \"\"\nversion: \"2\"\nbuildid: \"\"\noutputs: []\n\n",
   556  		"info: Build successful"})
   557  }
   558  
   559  func TestBuild_MainBranch(t *testing.T) {
   560  	defer pkg.SetEnv("CI_COMMIT_SHA", "abc123")()
   561  	defer pkg.SetEnv("CI_PROJECT_NAME", "reponame")()
   562  	defer pkg.SetEnv("CI_COMMIT_REF_NAME", "main")()
   563  	defer pkg.SetEnv("DOCKERHUB_NAMESPACE", "repo")()
   564  	defer pkg.SetEnv("DOCKERHUB_USERNAME", "user")()
   565  	defer pkg.SetEnv("DOCKERHUB_PASSWORD", "pass")()
   566  
   567  	logMock := mocks.New()
   568  	log.SetHandler(logMock)
   569  	log.SetLevel(log.DebugLevel)
   570  	client := &docker.MockDocker{}
   571  	defer func() { _ = os.RemoveAll(name) }()
   572  	_ = write(name, "Dockerfile", "FROM scratch")
   573  
   574  	err := build(client, name, Args{
   575  		Globals:    args.Globals{},
   576  		Dockerfile: "Dockerfile",
   577  		BuildArgs:  nil,
   578  		NoLogin:    false,
   579  		NoPull:     false,
   580  	})
   581  
   582  	assert.NoError(t, err)
   583  	assert.Equal(t, "Dockerfile", client.BuildOptions[0].Dockerfile)
   584  	assert.Equal(t, int64(-1), client.BuildOptions[0].MemorySwap)
   585  	assert.Equal(t, true, client.BuildOptions[0].Remove)
   586  	assert.Equal(t, int64(256*1024*1024), client.BuildOptions[0].ShmSize)
   587  	assert.Equal(t, []string{"repo/reponame:abc123", "repo/reponame:main", "repo/reponame:latest"}, client.BuildOptions[0].Tags)
   588  	logMock.Check(t, []string{"debug: Using CI <green>Gitlab</green>\n",
   589  		"debug: Using registry <green>Dockerhub</green>\n",
   590  		"debug: Authenticating against registry <green>Dockerhub</green>\n",
   591  		"debug: Logged in\n",
   592  		"debug: Using build variables commit <green>abc123</green> on branch <green>main</green>\n",
   593  		"debug: performing docker build with options (auths removed):\ntags:\n    - repo/reponame:abc123\n    - repo/reponame:main\n    - repo/reponame:latest\nsuppressoutput: false\nremotecontext: client-session\nnocache: false\nremove: true\nforceremove: false\npullparent: true\nisolation: \"\"\ncpusetcpus: \"\"\ncpusetmems: \"\"\ncpushares: 0\ncpuquota: 0\ncpuperiod: 0\nmemory: 0\nmemoryswap: -1\ncgroupparent: \"\"\nnetworkmode: \"\"\nshmsize: 268435456\ndockerfile: Dockerfile\nulimits: []\nbuildargs:\n    BUILDKIT_INLINE_CACHE: \"1\"\n    CI_BRANCH: main\n    CI_COMMIT: abc123\nauthconfigs: {}\ncontext: null\nlabels: {}\nsquash: false\ncachefrom:\n    - repo/reponame:main\n    - repo/reponame:latest\nsecurityopt: []\nextrahosts: []\ntarget: \"\"\nsessionid: \"\"\nplatform: \"\"\nversion: \"2\"\nbuildid: \"\"\noutputs: []\n\n",
   594  		"info: Build successful"})
   595  }
   596  
   597  func TestBuild_WithImageName(t *testing.T) {
   598  	defer pkg.SetEnv("CI_COMMIT_SHA", "abc123")()
   599  	defer pkg.SetEnv("CI_PROJECT_NAME", "reponame")()
   600  	defer pkg.SetEnv("CI_COMMIT_REF_NAME", "main")()
   601  	defer pkg.SetEnv("IMAGE_NAME", "other")()
   602  	defer pkg.SetEnv("DOCKERHUB_NAMESPACE", "repo")()
   603  	defer pkg.SetEnv("DOCKERHUB_USERNAME", "user")()
   604  	defer pkg.SetEnv("DOCKERHUB_PASSWORD", "pass")()
   605  
   606  	logMock := mocks.New()
   607  	log.SetHandler(logMock)
   608  	log.SetLevel(log.DebugLevel)
   609  	defer func() { _ = os.RemoveAll(name) }()
   610  	_ = write(name, "Dockerfile", "FROM scratch")
   611  
   612  	client := &docker.MockDocker{}
   613  	err := build(client, name, Args{
   614  		Globals:    args.Globals{},
   615  		Dockerfile: "Dockerfile",
   616  		BuildArgs:  nil,
   617  		NoLogin:    false,
   618  		NoPull:     false,
   619  	})
   620  
   621  	assert.NoError(t, err)
   622  	assert.Equal(t, "Dockerfile", client.BuildOptions[0].Dockerfile)
   623  	assert.Equal(t, int64(-1), client.BuildOptions[0].MemorySwap)
   624  	assert.Equal(t, true, client.BuildOptions[0].Remove)
   625  	assert.Equal(t, int64(256*1024*1024), client.BuildOptions[0].ShmSize)
   626  	assert.Equal(t, []string{"repo/other:abc123", "repo/other:main", "repo/other:latest"}, client.BuildOptions[0].Tags)
   627  	logMock.Check(t, []string{"debug: Using CI <green>Gitlab</green>\n",
   628  		"debug: Using registry <green>Dockerhub</green>\n",
   629  		"debug: Authenticating against registry <green>Dockerhub</green>\n",
   630  		"debug: Logged in\n",
   631  		"debug: Using build variables commit <green>abc123</green> on branch <green>main</green>\n",
   632  		"info: Using other as BuildName\n",
   633  		"info: Using other as BuildName\n",
   634  		"info: Using other as BuildName\n",
   635  		"debug: performing docker build with options (auths removed):\ntags:\n    - repo/other:abc123\n    - repo/other:main\n    - repo/other:latest\nsuppressoutput: false\nremotecontext: client-session\nnocache: false\nremove: true\nforceremove: false\npullparent: true\nisolation: \"\"\ncpusetcpus: \"\"\ncpusetmems: \"\"\ncpushares: 0\ncpuquota: 0\ncpuperiod: 0\nmemory: 0\nmemoryswap: -1\ncgroupparent: \"\"\nnetworkmode: \"\"\nshmsize: 268435456\ndockerfile: Dockerfile\nulimits: []\nbuildargs:\n    BUILDKIT_INLINE_CACHE: \"1\"\n    CI_BRANCH: main\n    CI_COMMIT: abc123\nauthconfigs: {}\ncontext: null\nlabels: {}\nsquash: false\ncachefrom:\n    - repo/other:main\n    - repo/other:latest\nsecurityopt: []\nextrahosts: []\ntarget: \"\"\nsessionid: \"\"\nplatform: \"\"\nversion: \"2\"\nbuildid: \"\"\noutputs: []\n\n",
   636  		"info: Build successful"})
   637  }
   638  
   639  func TestBuild_BadDockerHost(t *testing.T) {
   640  	defer pkg.SetEnv("DOCKER_HOST", "abc-123")()
   641  	logMock := mocks.New()
   642  	log.SetHandler(logMock)
   643  	log.SetLevel(log.DebugLevel)
   644  	err := DoBuild(name, Args{})
   645  	assert.EqualError(t, err, "unable to parse docker host `abc-123`")
   646  	logMock.Check(t, []string{})
   647  }
   648  
   649  func TestBuild_Unreadable_Dockerfile(t *testing.T) {
   650  	defer pkg.SetEnv("CI_COMMIT_SHA", "abc123")()
   651  	defer pkg.SetEnv("CI_PROJECT_NAME", "reponame")()
   652  	defer pkg.SetEnv("CI_COMMIT_REF_NAME", "master")()
   653  	defer pkg.SetEnv("DOCKERHUB_NAMESPACE", "repo")()
   654  	defer pkg.SetEnv("DOCKERHUB_USERNAME", "user")()
   655  	defer pkg.SetEnv("DOCKERHUB_PASSWORD", "pass")()
   656  
   657  	defer func() { _ = os.RemoveAll(name) }()
   658  	dockerfile := filepath.Join(name, "Dockerfile")
   659  	_ = os.MkdirAll(dockerfile, 0777)
   660  
   661  	logMock := mocks.New()
   662  	log.SetHandler(logMock)
   663  	log.SetLevel(log.DebugLevel)
   664  	client := &docker.MockDocker{}
   665  
   666  	err := build(client, name, Args{
   667  		Globals:    args.Globals{},
   668  		Dockerfile: "Dockerfile",
   669  		BuildArgs:  nil,
   670  		NoLogin:    false,
   671  		NoPull:     false,
   672  	})
   673  
   674  	assert.EqualError(t, err, fmt.Sprintf("read %s: is a directory", dockerfile))
   675  	logMock.Check(t, []string{
   676  		"debug: Using CI <green>Gitlab</green>\n",
   677  		"debug: Using registry <green>Dockerhub</green>\n",
   678  		"debug: Authenticating against registry <green>Dockerhub</green>\n",
   679  		"debug: Logged in\n",
   680  		fmt.Sprintf("error: <red>read %s: is a directory</red>", dockerfile),
   681  	})
   682  }
   683  
   684  func TestBuild_HandleCaching(t *testing.T) {
   685  	defer pkg.SetEnv("CI_COMMIT_SHA", "abc123")()
   686  	defer pkg.SetEnv("CI_PROJECT_NAME", "reponame")()
   687  	defer pkg.SetEnv("CI_COMMIT_REF_NAME", "master")()
   688  	defer pkg.SetEnv("DOCKERHUB_NAMESPACE", "repo")()
   689  	defer pkg.SetEnv("DOCKERHUB_USERNAME", "user")()
   690  	defer pkg.SetEnv("DOCKERHUB_PASSWORD", "pass")()
   691  
   692  	logMock := mocks.New()
   693  	log.SetHandler(logMock)
   694  	log.SetLevel(log.DebugLevel)
   695  	client := &docker.MockDocker{}
   696  
   697  	dockerfile := `
   698  FROM scratch as build
   699  RUN echo apa > file
   700  FROM scratch as test
   701  RUN echo cepa > file2
   702  FROM scratch
   703  COPY --from=build file .
   704  COPY --from=test file2 .
   705  `
   706  	defer func() { _ = os.RemoveAll(name) }()
   707  	_ = write(name, "Dockerfile", dockerfile)
   708  
   709  	err := build(client, name, Args{
   710  		Globals:    args.Globals{},
   711  		Dockerfile: "Dockerfile",
   712  		BuildArgs:  nil,
   713  		NoLogin:    false,
   714  		NoPull:     false,
   715  	})
   716  
   717  	assert.NoError(t, err)
   718  	assert.Equal(t, "Dockerfile", client.BuildOptions[0].Dockerfile)
   719  	assert.Equal(t, int64(-1), client.BuildOptions[0].MemorySwap)
   720  	assert.Equal(t, true, client.BuildOptions[0].Remove)
   721  	assert.Equal(t, int64(256*1024*1024), client.BuildOptions[0].ShmSize)
   722  	assert.Equal(t, 3, len(client.BuildOptions))
   723  	assert.Equal(t, []string{"repo/reponame:build"}, client.BuildOptions[0].Tags)
   724  	assert.Equal(t, []string{"repo/reponame:test"}, client.BuildOptions[1].Tags)
   725  	assert.Equal(t, []string{"repo/reponame:abc123", "repo/reponame:master", "repo/reponame:latest"}, client.BuildOptions[2].Tags)
   726  	assert.Equal(t, []string{"repo/reponame:build", "repo/reponame:master", "repo/reponame:latest"}, client.BuildOptions[0].CacheFrom)
   727  	assert.Equal(t, []string{"repo/reponame:test", "repo/reponame:build", "repo/reponame:master", "repo/reponame:latest"}, client.BuildOptions[1].CacheFrom)
   728  	assert.Equal(t, []string{"repo/reponame:test", "repo/reponame:build", "repo/reponame:master", "repo/reponame:latest"}, client.BuildOptions[2].CacheFrom)
   729  	logMock.Check(t, []string{"debug: Using CI <green>Gitlab</green>\n",
   730  		"debug: Using registry <green>Dockerhub</green>\n",
   731  		"debug: Authenticating against registry <green>Dockerhub</green>\n",
   732  		"debug: Logged in\n",
   733  		"debug: Using build variables commit <green>abc123</green> on branch <green>master</green>\n",
   734  		"debug: performing docker build with options (auths removed):\ntags:\n    - repo/reponame:build\nsuppressoutput: false\nremotecontext: client-session\nnocache: false\nremove: true\nforceremove: false\npullparent: true\nisolation: \"\"\ncpusetcpus: \"\"\ncpusetmems: \"\"\ncpushares: 0\ncpuquota: 0\ncpuperiod: 0\nmemory: 0\nmemoryswap: -1\ncgroupparent: \"\"\nnetworkmode: \"\"\nshmsize: 268435456\ndockerfile: Dockerfile\nulimits: []\nbuildargs:\n    BUILDKIT_INLINE_CACHE: \"1\"\n    CI_BRANCH: master\n    CI_COMMIT: abc123\nauthconfigs: {}\ncontext: null\nlabels: {}\nsquash: false\ncachefrom:\n    - repo/reponame:build\n    - repo/reponame:master\n    - repo/reponame:latest\nsecurityopt: []\nextrahosts: []\ntarget: build\nsessionid: \"\"\nplatform: \"\"\nversion: \"2\"\nbuildid: \"\"\noutputs: []\n\n",
   735  		"info: Build successful",
   736  		"debug: performing docker build with options (auths removed):\ntags:\n    - repo/reponame:test\nsuppressoutput: false\nremotecontext: client-session\nnocache: false\nremove: true\nforceremove: false\npullparent: true\nisolation: \"\"\ncpusetcpus: \"\"\ncpusetmems: \"\"\ncpushares: 0\ncpuquota: 0\ncpuperiod: 0\nmemory: 0\nmemoryswap: -1\ncgroupparent: \"\"\nnetworkmode: \"\"\nshmsize: 268435456\ndockerfile: Dockerfile\nulimits: []\nbuildargs:\n    BUILDKIT_INLINE_CACHE: \"1\"\n    CI_BRANCH: master\n    CI_COMMIT: abc123\nauthconfigs: {}\ncontext: null\nlabels: {}\nsquash: false\ncachefrom:\n    - repo/reponame:test\n    - repo/reponame:build\n    - repo/reponame:master\n    - repo/reponame:latest\nsecurityopt: []\nextrahosts: []\ntarget: test\nsessionid: \"\"\nplatform: \"\"\nversion: \"2\"\nbuildid: \"\"\noutputs: []\n\n",
   737  		"info: Build successful",
   738  		"debug: performing docker build with options (auths removed):\ntags:\n    - repo/reponame:abc123\n    - repo/reponame:master\n    - repo/reponame:latest\nsuppressoutput: false\nremotecontext: client-session\nnocache: false\nremove: true\nforceremove: false\npullparent: true\nisolation: \"\"\ncpusetcpus: \"\"\ncpusetmems: \"\"\ncpushares: 0\ncpuquota: 0\ncpuperiod: 0\nmemory: 0\nmemoryswap: -1\ncgroupparent: \"\"\nnetworkmode: \"\"\nshmsize: 268435456\ndockerfile: Dockerfile\nulimits: []\nbuildargs:\n    BUILDKIT_INLINE_CACHE: \"1\"\n    CI_BRANCH: master\n    CI_COMMIT: abc123\nauthconfigs: {}\ncontext: null\nlabels: {}\nsquash: false\ncachefrom:\n    - repo/reponame:test\n    - repo/reponame:build\n    - repo/reponame:master\n    - repo/reponame:latest\nsecurityopt: []\nextrahosts: []\ntarget: \"\"\nsessionid: \"\"\nplatform: \"\"\nversion: \"2\"\nbuildid: \"\"\noutputs: []\n\n",
   739  		"info: Build successful"})
   740  }
   741  
   742  func TestBuild_BrokenStage(t *testing.T) {
   743  	defer pkg.SetEnv("CI_COMMIT_SHA", "abc123")()
   744  	defer pkg.SetEnv("CI_PROJECT_NAME", "reponame")()
   745  	defer pkg.SetEnv("CI_COMMIT_REF_NAME", "master")()
   746  	defer pkg.SetEnv("DOCKERHUB_NAMESPACE", "repo")()
   747  	defer pkg.SetEnv("DOCKERHUB_USERNAME", "user")()
   748  	defer pkg.SetEnv("DOCKERHUB_PASSWORD", "pass")()
   749  
   750  	logMock := mocks.New()
   751  	log.SetHandler(logMock)
   752  	log.SetLevel(log.DebugLevel)
   753  	client := &docker.MockDocker{BuildError: []error{nil, errors.New("build error")}}
   754  	dockerfile := `
   755  FROM scratch as build
   756  RUN echo apa > file
   757  FROM scratch as test
   758  RUN echo cepa > file2
   759  FROM scratch
   760  COPY --from=build file .
   761  COPY --from=test file2 .
   762  `
   763  	defer func() { _ = os.RemoveAll(name) }()
   764  	_ = write(name, "Dockerfile", dockerfile)
   765  	err := build(client, name, Args{
   766  		Globals:    args.Globals{},
   767  		Dockerfile: "Dockerfile",
   768  		BuildArgs:  nil,
   769  		NoLogin:    false,
   770  		NoPull:     false,
   771  	})
   772  
   773  	assert.EqualError(t, err, "build error")
   774  	logMock.Check(t, []string{
   775  		"debug: Using CI <green>Gitlab</green>\n",
   776  		"debug: Using registry <green>Dockerhub</green>\n",
   777  		"debug: Authenticating against registry <green>Dockerhub</green>\n",
   778  		"debug: Logged in\n",
   779  		"debug: Using build variables commit <green>abc123</green> on branch <green>master</green>\n",
   780  		"debug: performing docker build with options (auths removed):\ntags:\n    - repo/reponame:build\nsuppressoutput: false\nremotecontext: client-session\nnocache: false\nremove: true\nforceremove: false\npullparent: true\nisolation: \"\"\ncpusetcpus: \"\"\ncpusetmems: \"\"\ncpushares: 0\ncpuquota: 0\ncpuperiod: 0\nmemory: 0\nmemoryswap: -1\ncgroupparent: \"\"\nnetworkmode: \"\"\nshmsize: 268435456\ndockerfile: Dockerfile\nulimits: []\nbuildargs:\n    BUILDKIT_INLINE_CACHE: \"1\"\n    CI_BRANCH: master\n    CI_COMMIT: abc123\nauthconfigs: {}\ncontext: null\nlabels: {}\nsquash: false\ncachefrom:\n    - repo/reponame:build\n    - repo/reponame:master\n    - repo/reponame:latest\nsecurityopt: []\nextrahosts: []\ntarget: build\nsessionid: \"\"\nplatform: \"\"\nversion: \"2\"\nbuildid: \"\"\noutputs: []\n\n",
   781  		"info: Build successful",
   782  		"debug: performing docker build with options (auths removed):\ntags:\n    - repo/reponame:test\nsuppressoutput: false\nremotecontext: client-session\nnocache: false\nremove: true\nforceremove: false\npullparent: true\nisolation: \"\"\ncpusetcpus: \"\"\ncpusetmems: \"\"\ncpushares: 0\ncpuquota: 0\ncpuperiod: 0\nmemory: 0\nmemoryswap: -1\ncgroupparent: \"\"\nnetworkmode: \"\"\nshmsize: 268435456\ndockerfile: Dockerfile\nulimits: []\nbuildargs:\n    BUILDKIT_INLINE_CACHE: \"1\"\n    CI_BRANCH: master\n    CI_COMMIT: abc123\nauthconfigs: {}\ncontext: null\nlabels: {}\nsquash: false\ncachefrom:\n    - repo/reponame:test\n    - repo/reponame:build\n    - repo/reponame:master\n    - repo/reponame:latest\nsecurityopt: []\nextrahosts: []\ntarget: test\nsessionid: \"\"\nplatform: \"\"\nversion: \"2\"\nbuildid: \"\"\noutputs: []\n\n",
   783  	})
   784  }
   785  
   786  func TestBuild_ExportStage(t *testing.T) {
   787  	defer pkg.SetEnv("CI_COMMIT_SHA", "abc123")()
   788  	defer pkg.SetEnv("CI_PROJECT_NAME", "reponame")()
   789  	defer pkg.SetEnv("CI_COMMIT_REF_NAME", "master")()
   790  	defer pkg.SetEnv("DOCKERHUB_NAMESPACE", "repo")()
   791  	defer pkg.SetEnv("DOCKERHUB_USERNAME", "user")()
   792  	defer pkg.SetEnv("DOCKERHUB_PASSWORD", "pass")()
   793  
   794  	logMock := mocks.New()
   795  	log.SetHandler(logMock)
   796  	log.SetLevel(log.DebugLevel)
   797  	client := &docker.MockDocker{}
   798  	dockerfile := `
   799  FROM scratch as build
   800  RUN echo apa > file
   801  FROM scratch as test
   802  RUN echo cepa > file2
   803  FROM scratch as export
   804  COPY --from=build file .
   805  COPY --from=test file2 .
   806  FROM scratch
   807  COPY --from=build file .
   808  COPY --from=test file2 .
   809  `
   810  	defer func() { _ = os.RemoveAll(name) }()
   811  	_ = write(name, "Dockerfile", dockerfile)
   812  	err := build(client, name, Args{
   813  		Globals:    args.Globals{},
   814  		Dockerfile: "Dockerfile",
   815  		BuildArgs:  nil,
   816  		NoLogin:    false,
   817  		NoPull:     false,
   818  	})
   819  
   820  	assert.NoError(t, err)
   821  	assert.Equal(t, "Dockerfile", client.BuildOptions[0].Dockerfile)
   822  	assert.Equal(t, int64(-1), client.BuildOptions[0].MemorySwap)
   823  	assert.Equal(t, true, client.BuildOptions[0].Remove)
   824  	assert.Equal(t, int64(256*1024*1024), client.BuildOptions[0].ShmSize)
   825  	assert.Equal(t, 4, len(client.BuildOptions))
   826  	assert.Equal(t, []string{"repo/reponame:build"}, client.BuildOptions[0].Tags)
   827  	assert.Equal(t, []string{"repo/reponame:test"}, client.BuildOptions[1].Tags)
   828  	assert.Equal(t, []string{"repo/reponame:export"}, client.BuildOptions[2].Tags)
   829  	assert.Equal(t, []types.ImageBuildOutput{
   830  		{
   831  			Type:  "local",
   832  			Attrs: map[string]string{},
   833  		},
   834  	}, client.BuildOptions[2].Outputs)
   835  	assert.Equal(t, []string{"repo/reponame:abc123", "repo/reponame:master", "repo/reponame:latest"}, client.BuildOptions[3].Tags)
   836  	assert.Equal(t, []string{"repo/reponame:build", "repo/reponame:master", "repo/reponame:latest"}, client.BuildOptions[0].CacheFrom)
   837  	assert.Equal(t, []string{"repo/reponame:test", "repo/reponame:build", "repo/reponame:master", "repo/reponame:latest"}, client.BuildOptions[1].CacheFrom)
   838  	assert.Equal(t, []string{"repo/reponame:export", "repo/reponame:test", "repo/reponame:build", "repo/reponame:master", "repo/reponame:latest"}, client.BuildOptions[2].CacheFrom)
   839  	assert.Equal(t, []string{"repo/reponame:export", "repo/reponame:test", "repo/reponame:build", "repo/reponame:master", "repo/reponame:latest"}, client.BuildOptions[3].CacheFrom)
   840  	logMock.Check(t, []string{"debug: Using CI <green>Gitlab</green>\n",
   841  		"debug: Using registry <green>Dockerhub</green>\n",
   842  		"debug: Authenticating against registry <green>Dockerhub</green>\n",
   843  		"debug: Logged in\n",
   844  		"debug: Using build variables commit <green>abc123</green> on branch <green>master</green>\n",
   845  		"debug: performing docker build with options (auths removed):\ntags:\n    - repo/reponame:build\nsuppressoutput: false\nremotecontext: client-session\nnocache: false\nremove: true\nforceremove: false\npullparent: true\nisolation: \"\"\ncpusetcpus: \"\"\ncpusetmems: \"\"\ncpushares: 0\ncpuquota: 0\ncpuperiod: 0\nmemory: 0\nmemoryswap: -1\ncgroupparent: \"\"\nnetworkmode: \"\"\nshmsize: 268435456\ndockerfile: Dockerfile\nulimits: []\nbuildargs:\n    BUILDKIT_INLINE_CACHE: \"1\"\n    CI_BRANCH: master\n    CI_COMMIT: abc123\nauthconfigs: {}\ncontext: null\nlabels: {}\nsquash: false\ncachefrom:\n    - repo/reponame:build\n    - repo/reponame:master\n    - repo/reponame:latest\nsecurityopt: []\nextrahosts: []\ntarget: build\nsessionid: \"\"\nplatform: \"\"\nversion: \"2\"\nbuildid: \"\"\noutputs: []\n\n",
   846  		"info: Build successful",
   847  		"debug: performing docker build with options (auths removed):\ntags:\n    - repo/reponame:test\nsuppressoutput: false\nremotecontext: client-session\nnocache: false\nremove: true\nforceremove: false\npullparent: true\nisolation: \"\"\ncpusetcpus: \"\"\ncpusetmems: \"\"\ncpushares: 0\ncpuquota: 0\ncpuperiod: 0\nmemory: 0\nmemoryswap: -1\ncgroupparent: \"\"\nnetworkmode: \"\"\nshmsize: 268435456\ndockerfile: Dockerfile\nulimits: []\nbuildargs:\n    BUILDKIT_INLINE_CACHE: \"1\"\n    CI_BRANCH: master\n    CI_COMMIT: abc123\nauthconfigs: {}\ncontext: null\nlabels: {}\nsquash: false\ncachefrom:\n    - repo/reponame:test\n    - repo/reponame:build\n    - repo/reponame:master\n    - repo/reponame:latest\nsecurityopt: []\nextrahosts: []\ntarget: test\nsessionid: \"\"\nplatform: \"\"\nversion: \"2\"\nbuildid: \"\"\noutputs: []\n\n",
   848  		"info: Build successful",
   849  		"debug: performing docker build with options (auths removed):\ntags:\n    - repo/reponame:export\nsuppressoutput: false\nremotecontext: client-session\nnocache: false\nremove: true\nforceremove: false\npullparent: true\nisolation: \"\"\ncpusetcpus: \"\"\ncpusetmems: \"\"\ncpushares: 0\ncpuquota: 0\ncpuperiod: 0\nmemory: 0\nmemoryswap: -1\ncgroupparent: \"\"\nnetworkmode: \"\"\nshmsize: 268435456\ndockerfile: Dockerfile\nulimits: []\nbuildargs:\n    BUILDKIT_INLINE_CACHE: \"1\"\n    CI_BRANCH: master\n    CI_COMMIT: abc123\nauthconfigs: {}\ncontext: null\nlabels: {}\nsquash: false\ncachefrom:\n    - repo/reponame:export\n    - repo/reponame:test\n    - repo/reponame:build\n    - repo/reponame:master\n    - repo/reponame:latest\nsecurityopt: []\nextrahosts: []\ntarget: export\nsessionid: \"\"\nplatform: \"\"\nversion: \"2\"\nbuildid: \"\"\noutputs:\n    - type: local\n      attrs: {}\n\n",
   850  		"info: Build successful",
   851  		"debug: performing docker build with options (auths removed):\ntags:\n    - repo/reponame:abc123\n    - repo/reponame:master\n    - repo/reponame:latest\nsuppressoutput: false\nremotecontext: client-session\nnocache: false\nremove: true\nforceremove: false\npullparent: true\nisolation: \"\"\ncpusetcpus: \"\"\ncpusetmems: \"\"\ncpushares: 0\ncpuquota: 0\ncpuperiod: 0\nmemory: 0\nmemoryswap: -1\ncgroupparent: \"\"\nnetworkmode: \"\"\nshmsize: 268435456\ndockerfile: Dockerfile\nulimits: []\nbuildargs:\n    BUILDKIT_INLINE_CACHE: \"1\"\n    CI_BRANCH: master\n    CI_COMMIT: abc123\nauthconfigs: {}\ncontext: null\nlabels: {}\nsquash: false\ncachefrom:\n    - repo/reponame:export\n    - repo/reponame:test\n    - repo/reponame:build\n    - repo/reponame:master\n    - repo/reponame:latest\nsecurityopt: []\nextrahosts: []\ntarget: \"\"\nsessionid: \"\"\nplatform: \"\"\nversion: \"2\"\nbuildid: \"\"\noutputs: []\n\n",
   852  		"info: Build successful"})
   853  }
   854  
   855  func TestBuild_ExportAsLastStage(t *testing.T) {
   856  	defer pkg.SetEnv("CI_COMMIT_SHA", "abc123")()
   857  	defer pkg.SetEnv("CI_PROJECT_NAME", "reponame")()
   858  	defer pkg.SetEnv("CI_COMMIT_REF_NAME", "master")()
   859  	defer pkg.SetEnv("DOCKERHUB_NAMESPACE", "repo")()
   860  	defer pkg.SetEnv("DOCKERHUB_USERNAME", "user")()
   861  	defer pkg.SetEnv("DOCKERHUB_PASSWORD", "pass")()
   862  
   863  	logMock := mocks.New()
   864  	log.SetHandler(logMock)
   865  	log.SetLevel(log.DebugLevel)
   866  	client := &docker.MockDocker{}
   867  	dockerfile := `
   868  FROM scratch as build
   869  RUN echo apa > file
   870  FROM scratch as test
   871  RUN echo cepa > file2
   872  FROM scratch as export
   873  COPY --from=build file .
   874  COPY --from=test file2 .
   875  `
   876  	defer func() { _ = os.RemoveAll(name) }()
   877  	_ = write(name, "Dockerfile", dockerfile)
   878  	err := build(client, name, Args{
   879  		Globals:    args.Globals{},
   880  		Dockerfile: "Dockerfile",
   881  		BuildArgs:  nil,
   882  		NoLogin:    false,
   883  		NoPull:     false,
   884  	})
   885  
   886  	assert.NoError(t, err)
   887  	assert.Equal(t, "Dockerfile", client.BuildOptions[0].Dockerfile)
   888  	assert.Equal(t, int64(-1), client.BuildOptions[0].MemorySwap)
   889  	assert.Equal(t, true, client.BuildOptions[0].Remove)
   890  	assert.Equal(t, int64(256*1024*1024), client.BuildOptions[0].ShmSize)
   891  	assert.Equal(t, 4, len(client.BuildOptions))
   892  	assert.Equal(t, []string{"repo/reponame:build"}, client.BuildOptions[0].Tags)
   893  	assert.Equal(t, []string{"repo/reponame:test"}, client.BuildOptions[1].Tags)
   894  	assert.Equal(t, []string{"repo/reponame:export"}, client.BuildOptions[2].Tags)
   895  	assert.Equal(t, []types.ImageBuildOutput{
   896  		{
   897  			Type:  "local",
   898  			Attrs: map[string]string{},
   899  		},
   900  	}, client.BuildOptions[2].Outputs)
   901  	assert.Equal(t, []string{"repo/reponame:abc123", "repo/reponame:master", "repo/reponame:latest"}, client.BuildOptions[3].Tags)
   902  	assert.Equal(t, []string{"repo/reponame:build", "repo/reponame:master", "repo/reponame:latest"}, client.BuildOptions[0].CacheFrom)
   903  	assert.Equal(t, []string{"repo/reponame:test", "repo/reponame:build", "repo/reponame:master", "repo/reponame:latest"}, client.BuildOptions[1].CacheFrom)
   904  	assert.Equal(t, []string{"repo/reponame:export", "repo/reponame:test", "repo/reponame:build", "repo/reponame:master", "repo/reponame:latest"}, client.BuildOptions[2].CacheFrom)
   905  	assert.Equal(t, []string{"repo/reponame:export", "repo/reponame:test", "repo/reponame:build", "repo/reponame:master", "repo/reponame:latest"}, client.BuildOptions[3].CacheFrom)
   906  	logMock.Check(t, []string{"debug: Using CI <green>Gitlab</green>\n",
   907  		"debug: Using registry <green>Dockerhub</green>\n",
   908  		"debug: Authenticating against registry <green>Dockerhub</green>\n",
   909  		"debug: Logged in\n",
   910  		"debug: Using build variables commit <green>abc123</green> on branch <green>master</green>\n",
   911  		"debug: performing docker build with options (auths removed):\ntags:\n    - repo/reponame:build\nsuppressoutput: false\nremotecontext: client-session\nnocache: false\nremove: true\nforceremove: false\npullparent: true\nisolation: \"\"\ncpusetcpus: \"\"\ncpusetmems: \"\"\ncpushares: 0\ncpuquota: 0\ncpuperiod: 0\nmemory: 0\nmemoryswap: -1\ncgroupparent: \"\"\nnetworkmode: \"\"\nshmsize: 268435456\ndockerfile: Dockerfile\nulimits: []\nbuildargs:\n    BUILDKIT_INLINE_CACHE: \"1\"\n    CI_BRANCH: master\n    CI_COMMIT: abc123\nauthconfigs: {}\ncontext: null\nlabels: {}\nsquash: false\ncachefrom:\n    - repo/reponame:build\n    - repo/reponame:master\n    - repo/reponame:latest\nsecurityopt: []\nextrahosts: []\ntarget: build\nsessionid: \"\"\nplatform: \"\"\nversion: \"2\"\nbuildid: \"\"\noutputs: []\n\n",
   912  		"info: Build successful",
   913  		"debug: performing docker build with options (auths removed):\ntags:\n    - repo/reponame:test\nsuppressoutput: false\nremotecontext: client-session\nnocache: false\nremove: true\nforceremove: false\npullparent: true\nisolation: \"\"\ncpusetcpus: \"\"\ncpusetmems: \"\"\ncpushares: 0\ncpuquota: 0\ncpuperiod: 0\nmemory: 0\nmemoryswap: -1\ncgroupparent: \"\"\nnetworkmode: \"\"\nshmsize: 268435456\ndockerfile: Dockerfile\nulimits: []\nbuildargs:\n    BUILDKIT_INLINE_CACHE: \"1\"\n    CI_BRANCH: master\n    CI_COMMIT: abc123\nauthconfigs: {}\ncontext: null\nlabels: {}\nsquash: false\ncachefrom:\n    - repo/reponame:test\n    - repo/reponame:build\n    - repo/reponame:master\n    - repo/reponame:latest\nsecurityopt: []\nextrahosts: []\ntarget: test\nsessionid: \"\"\nplatform: \"\"\nversion: \"2\"\nbuildid: \"\"\noutputs: []\n\n",
   914  		"info: Build successful",
   915  		"debug: performing docker build with options (auths removed):\ntags:\n    - repo/reponame:export\nsuppressoutput: false\nremotecontext: client-session\nnocache: false\nremove: true\nforceremove: false\npullparent: true\nisolation: \"\"\ncpusetcpus: \"\"\ncpusetmems: \"\"\ncpushares: 0\ncpuquota: 0\ncpuperiod: 0\nmemory: 0\nmemoryswap: -1\ncgroupparent: \"\"\nnetworkmode: \"\"\nshmsize: 268435456\ndockerfile: Dockerfile\nulimits: []\nbuildargs:\n    BUILDKIT_INLINE_CACHE: \"1\"\n    CI_BRANCH: master\n    CI_COMMIT: abc123\nauthconfigs: {}\ncontext: null\nlabels: {}\nsquash: false\ncachefrom:\n    - repo/reponame:export\n    - repo/reponame:test\n    - repo/reponame:build\n    - repo/reponame:master\n    - repo/reponame:latest\nsecurityopt: []\nextrahosts: []\ntarget: export\nsessionid: \"\"\nplatform: \"\"\nversion: \"2\"\nbuildid: \"\"\noutputs:\n    - type: local\n      attrs: {}\n\n",
   916  		"info: Build successful",
   917  		"debug: performing docker build with options (auths removed):\ntags:\n    - repo/reponame:abc123\n    - repo/reponame:master\n    - repo/reponame:latest\nsuppressoutput: false\nremotecontext: client-session\nnocache: false\nremove: true\nforceremove: false\npullparent: true\nisolation: \"\"\ncpusetcpus: \"\"\ncpusetmems: \"\"\ncpushares: 0\ncpuquota: 0\ncpuperiod: 0\nmemory: 0\nmemoryswap: -1\ncgroupparent: \"\"\nnetworkmode: \"\"\nshmsize: 268435456\ndockerfile: Dockerfile\nulimits: []\nbuildargs:\n    BUILDKIT_INLINE_CACHE: \"1\"\n    CI_BRANCH: master\n    CI_COMMIT: abc123\nauthconfigs: {}\ncontext: null\nlabels: {}\nsquash: false\ncachefrom:\n    - repo/reponame:export\n    - repo/reponame:test\n    - repo/reponame:build\n    - repo/reponame:master\n    - repo/reponame:latest\nsecurityopt: []\nextrahosts: []\ntarget: \"\"\nsessionid: \"\"\nplatform: \"\"\nversion: \"2\"\nbuildid: \"\"\noutputs: []\n\n",
   918  		"info: Build successful"})
   919  }
   920  
   921  type brokenReader struct{}
   922  
   923  func (b brokenReader) Read([]byte) (n int, err error) {
   924  	return 0, errors.New("read error")
   925  }
   926  
   927  var _ io.Reader = &brokenReader{}
   928  
   929  func write(dir, file, content string) error {
   930  	if err := os.MkdirAll(filepath.Dir(filepath.Join(dir, file)), 0777); err != nil {
   931  		return err
   932  	}
   933  	return os.WriteFile(filepath.Join(dir, file), []byte(fmt.Sprintln(strings.TrimSpace(content))), 0666)
   934  }