diff --git a/config/config.go b/config/config.go index d31d3fc..c84c4c3 100644 --- a/config/config.go +++ b/config/config.go @@ -11,6 +11,13 @@ func (g *Config) Get() *Config { type Build struct { ExtensionExclude string `mapstructure:"extensionExclude" validate:"required"` + Docker Docker `mapstructure:"docker"` +} + +type Docker struct { + CacheToEnable bool `mapstructure:"cacheToEnable"` + CacheFromEnable bool `mapstructure:"cacheFromEnable"` + BuildExtraOpts map[string]string `mapstructure:"buildExtraOpts"` } type Template struct { diff --git a/container/docker/client.go b/container/docker/client.go index d0e7168..20e0c80 100644 --- a/container/docker/client.go +++ b/container/docker/client.go @@ -74,10 +74,25 @@ func (b BuilderDocker) BuildImages(images types.Images, pushImages bool) error { } func (b BuilderDocker) Build(image *types.Image, pushImages bool) error { + dockerCfg := b.ctx.Config.Build.Docker b.ctx.Logger.Info(fmt.Sprintf("Start building %s", image.GetFullName())) logger := b.ctx.Logger.With("image", image.Name) - //cmdArgs := []string{"buildx", "build", "--progress", "plain", "--provenance", "false"} - cmdArgs := []string{"build", "--no-cache", "--progress", "plain", "--provenance", "false"} + + cmdArgs := []string{"build", "--progress", "plain"} + + if dockerCfg.CacheToEnable { + cmdArgs = append(cmdArgs, "--cache-to", "type=inline,mode=max") + } + + if dockerCfg.CacheFromEnable { + cmdArgs = append(cmdArgs, "--cache-from", image.GetFullName()) + } + + if len(dockerCfg.BuildExtraOpts) > 0 { + for optKey, optValue := range dockerCfg.BuildExtraOpts { + cmdArgs = append(cmdArgs, fmt.Sprintf("--%s", optKey), optValue) + } + } labels := []string{ fmt.Sprintf("%s=%s", "mib.version", version.GetFormattedVersion()), diff --git a/container/docker/client_test.go b/container/docker/client_test.go index 920e199..71e8d55 100644 --- a/container/docker/client_test.go +++ b/container/docker/client_test.go @@ -194,7 +194,34 @@ func TestBuilderDocker_Build_Success(t *testing.T) { cmd.EXPECT().SetStdout(gomock.Any()).Times(1) cmd.EXPECT().SetStderr(gomock.Any()).Times(1) cmd.EXPECT().Run().Times(1).Return(nil) - defaultsArgs := []string{"build", "--no-cache", "--progress", "plain", "--provenance", "false"} + defaultsArgs := []string{"build", "--progress", "plain"} + testArgs := []string{"--tag", "registry.example.com/foo:0.1", "--tag", "registry2.example.com/foo:0.1", "--label", "mib.version=develop-SNAPSHOT", "."} + wantArgs := append(defaultsArgs, testArgs...) + exec.NewCmd = func(name string, arg ...string) exec.Executable { + assert.Equal(t, "docker", name) + assert.Equal(t, wantArgs, arg) + return cmd + } + b := BuilderDocker{ctx: ctx, AuthConfig: &auth} + err := b.Build(image, false) + assert.NoError(t, err) +} + +func TestBuilderDocker_Build_SuccessWithBuildOpt(t *testing.T) { + ctx := context.TestContext(nil) + ctx.Config.Build.Docker.CacheToEnable = true + ctx.Config.Build.Docker.CacheFromEnable = true + ctx.Config.Build.Docker.BuildExtraOpts = map[string]string{"provenance": "true"} + auth := AuthConfig{AuthConfigs: map[string]registry.AuthConfig{}} + image := &types.Image{ImageName: types.ImageName{Name: "registry.example.com/foo", Tag: "0.1"}, Path: "/app", Alias: []types.ImageName{{Name: "registry2.example.com/foo", Tag: "0.1"}}} + ctrl := gomock.NewController(t) + defer ctrl.Finish() + cmd := mock_exec.NewMockExecutable(ctrl) + cmd.EXPECT().SetDir(gomock.Eq("/app")).Times(1) + cmd.EXPECT().SetStdout(gomock.Any()).Times(1) + cmd.EXPECT().SetStderr(gomock.Any()).Times(1) + cmd.EXPECT().Run().Times(1).Return(nil) + defaultsArgs := []string{"build", "--progress", "plain", "--cache-to", "type=inline,mode=max", "--cache-from", "registry.example.com/foo:0.1", "--provenance", "true"} testArgs := []string{"--tag", "registry.example.com/foo:0.1", "--tag", "registry2.example.com/foo:0.1", "--label", "mib.version=develop-SNAPSHOT", "."} wantArgs := append(defaultsArgs, testArgs...) exec.NewCmd = func(name string, arg ...string) exec.Executable { @@ -218,7 +245,7 @@ func TestBuilderDocker_Build_SuccessWithPush(t *testing.T) { cmd.EXPECT().SetStdout(gomock.Any()).Times(1) cmd.EXPECT().SetStderr(gomock.Any()).Times(1) cmd.EXPECT().Run().Times(1).Return(nil) - defaultsArgs := []string{"build", "--no-cache", "--progress", "plain", "--provenance", "false"} + defaultsArgs := []string{"build", "--progress", "plain"} testArgs := []string{"--tag", "registry.example.com/foo:0.1", "--tag", "registry2.example.com/foo:0.1", "--label", "mib.version=develop-SNAPSHOT", "--push", "."} wantArgs := append(defaultsArgs, testArgs...) exec.NewCmd = func(name string, arg ...string) exec.Executable { @@ -242,7 +269,7 @@ func TestBuilderDocker_Build_SuccessMultiPlatforms(t *testing.T) { cmd.EXPECT().SetStdout(gomock.Any()).Times(1) cmd.EXPECT().SetStderr(gomock.Any()).Times(1) cmd.EXPECT().Run().Times(1).Return(nil) - defaultsArgs := []string{"build", "--no-cache", "--progress", "plain", "--provenance", "false"} + defaultsArgs := []string{"build", "--progress", "plain"} testArgs := []string{"--tag", "registry.example.com/foo:0.1", "--label", "mib.version=develop-SNAPSHOT", "--platform", "linux/amd64,linux/arm64/v8", "."} wantArgs := append(defaultsArgs, testArgs...) exec.NewCmd = func(name string, arg ...string) exec.Executable { @@ -266,7 +293,7 @@ func TestBuilderDocker_Build_Error(t *testing.T) { cmd.EXPECT().SetStdout(gomock.Any()).Times(1) cmd.EXPECT().SetStderr(gomock.Any()).Times(1) cmd.EXPECT().Run().Times(1).Return(errors.New("fail build")) - defaultsArgs := []string{"build", "--no-cache", "--progress", "plain", "--provenance", "false"} + defaultsArgs := []string{"build", "--progress", "plain"} testArgs := []string{"--tag", "registry.example.com/foo:0.1", "--label", "mib.version=develop-SNAPSHOT", "."} wantArgs := append(defaultsArgs, testArgs...) exec.NewCmd = func(name string, arg ...string) exec.Executable { diff --git a/doc/examples/config.yml b/doc/examples/config.yml index 51174c5..89ece6c 100644 --- a/doc/examples/config.yml +++ b/doc/examples/config.yml @@ -1,5 +1,10 @@ build: extensionExclude: ".md,.txt" + docker: + cacheToEnable: true + cacheFromEnable: true + buildExtraOpts: + provenance: "true" template: imagePath: "my-custom-image.tmpl" indexPath: "my-custom-index.tmpl"