diff --git a/internal/build/lifecycle_execution.go b/internal/build/lifecycle_execution.go index 8150ead355..fa8b8ffd65 100644 --- a/internal/build/lifecycle_execution.go +++ b/internal/build/lifecycle_execution.go @@ -265,7 +265,7 @@ func (l *LifecycleExecution) Run(ctx context.Context, phaseFactoryCreator PhaseF if l.platformAPI.AtLeast("0.10") && l.hasExtensionsForBuild() { group.Go(func() error { l.logger.Info(style.Step("EXTENDING (BUILD)")) - return l.ExtendBuild(ctx, kanikoCache, phaseFactory) + return l.ExtendBuild(ctx, kanikoCache, phaseFactory, l.extensionsAreExperimental()) }) } else { group.Go(func() error { @@ -277,7 +277,7 @@ func (l *LifecycleExecution) Run(ctx context.Context, phaseFactoryCreator PhaseF if l.platformAPI.AtLeast("0.12") && l.hasExtensionsForRun() { group.Go(func() error { l.logger.Info(style.Step("EXTENDING (RUN)")) - return l.ExtendRun(ctx, kanikoCache, phaseFactory, ephemeralRunImage) + return l.ExtendRun(ctx, kanikoCache, phaseFactory, ephemeralRunImage, l.extensionsAreExperimental()) }) } @@ -424,7 +424,7 @@ func (l *LifecycleExecution) Detect(ctx context.Context, phaseFactory PhaseFacto envOp := NullOp() if l.platformAPI.AtLeast("0.10") && l.hasExtensions() { - envOp = WithEnv("CNB_EXPERIMENTAL_MODE=warn") + envOp = If(l.extensionsAreExperimental(), WithEnv("CNB_EXPERIMENTAL_MODE=warn")) } configProvider := NewPhaseConfigProvider( @@ -453,6 +453,10 @@ func (l *LifecycleExecution) Detect(ctx context.Context, phaseFactory PhaseFacto return detect.Run(ctx) } +func (l *LifecycleExecution) extensionsAreExperimental() bool { + return l.PlatformAPI().AtLeast("0.10") && l.platformAPI.LessThan("0.13") +} + func (l *LifecycleExecution) Restore(ctx context.Context, buildCache Cache, kanikoCache Cache, phaseFactory PhaseFactory) error { // build up flags and ops var flags []string @@ -709,7 +713,7 @@ func (l *LifecycleExecution) Build(ctx context.Context, phaseFactory PhaseFactor return build.Run(ctx) } -func (l *LifecycleExecution) ExtendBuild(ctx context.Context, kanikoCache Cache, phaseFactory PhaseFactory) error { +func (l *LifecycleExecution) ExtendBuild(ctx context.Context, kanikoCache Cache, phaseFactory PhaseFactory, experimental bool) error { flags := []string{"-app", l.mountPaths.appDir()} configProvider := NewPhaseConfigProvider( @@ -718,7 +722,7 @@ func (l *LifecycleExecution) ExtendBuild(ctx context.Context, kanikoCache Cache, WithLogPrefix("extender (build)"), WithArgs(l.withLogLevel()...), WithBinds(l.opts.Volumes...), - WithEnv("CNB_EXPERIMENTAL_MODE=warn"), + If(experimental, WithEnv("CNB_EXPERIMENTAL_MODE=warn")), WithFlags(flags...), WithNetwork(l.opts.Network), WithRoot(), @@ -730,7 +734,7 @@ func (l *LifecycleExecution) ExtendBuild(ctx context.Context, kanikoCache Cache, return extend.Run(ctx) } -func (l *LifecycleExecution) ExtendRun(ctx context.Context, kanikoCache Cache, phaseFactory PhaseFactory, runImageName string) error { +func (l *LifecycleExecution) ExtendRun(ctx context.Context, kanikoCache Cache, phaseFactory PhaseFactory, runImageName string, experimental bool) error { flags := []string{"-app", l.mountPaths.appDir(), "-kind", "run"} configProvider := NewPhaseConfigProvider( @@ -739,7 +743,7 @@ func (l *LifecycleExecution) ExtendRun(ctx context.Context, kanikoCache Cache, p WithLogPrefix("extender (run)"), WithArgs(l.withLogLevel()...), WithBinds(l.opts.Volumes...), - WithEnv("CNB_EXPERIMENTAL_MODE=warn"), + If(experimental, WithEnv("CNB_EXPERIMENTAL_MODE=warn")), WithFlags(flags...), WithNetwork(l.opts.Network), WithRoot(), @@ -775,7 +779,7 @@ func (l *LifecycleExecution) Export(ctx context.Context, buildCache, launchCache } else { flags = append(flags, "-run", l.mountPaths.runPath()) if l.hasExtensionsForRun() { - expEnv = WithEnv("CNB_EXPERIMENTAL_MODE=warn") + expEnv = If(l.extensionsAreExperimental(), WithEnv("CNB_EXPERIMENTAL_MODE=warn")) kanikoCacheBindOp = WithBinds(fmt.Sprintf("%s:%s", kanikoCache.Name(), l.mountPaths.kanikoCacheDir())) } } diff --git a/internal/build/lifecycle_execution_test.go b/internal/build/lifecycle_execution_test.go index eee480aae8..24545c4ac2 100644 --- a/internal/build/lifecycle_execution_test.go +++ b/internal/build/lifecycle_execution_test.go @@ -2053,8 +2053,10 @@ func testLifecycleExecution(t *testing.T, when spec.G, it spec.S) { }) when("#ExtendBuild", func() { + var experimental bool it.Before(func() { - err := lifecycle.ExtendBuild(context.Background(), fakeKanikoCache, fakePhaseFactory) + experimental = true + err := lifecycle.ExtendBuild(context.Background(), fakeKanikoCache, fakePhaseFactory, experimental) h.AssertNil(t, err) lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 @@ -2092,11 +2094,31 @@ func testLifecycleExecution(t *testing.T, when spec.G, it spec.S) { it("configures the phase with root", func() { h.AssertEq(t, configProvider.ContainerConfig().User, "root") }) + + when("experimental is false", func() { + it.Before(func() { + experimental = false + err := lifecycle.ExtendBuild(context.Background(), fakeKanikoCache, fakePhaseFactory, experimental) + h.AssertNil(t, err) + + lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 + h.AssertNotEq(t, lastCallIndex, -1) + + configProvider = fakePhaseFactory.NewCalledWithProvider[lastCallIndex] + h.AssertEq(t, configProvider.Name(), "extender") + }) + + it("CNB_EXPERIMENTAL_MODE=warn is not enable in the environment", func() { + h.AssertSliceNotContains(t, configProvider.ContainerConfig().Env, "CNB_EXPERIMENTAL_MODE=warn") + }) + }) }) when("#ExtendRun", func() { + var experimental bool it.Before(func() { - err := lifecycle.ExtendRun(context.Background(), fakeKanikoCache, fakePhaseFactory, "some-run-image") + experimental = true + err := lifecycle.ExtendRun(context.Background(), fakeKanikoCache, fakePhaseFactory, "some-run-image", experimental) h.AssertNil(t, err) lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 @@ -2140,6 +2162,24 @@ func testLifecycleExecution(t *testing.T, when spec.G, it spec.S) { it("configures the phase with root", func() { h.AssertEq(t, configProvider.ContainerConfig().User, "root") }) + + when("experimental is false", func() { + it.Before(func() { + experimental = false + err := lifecycle.ExtendRun(context.Background(), fakeKanikoCache, fakePhaseFactory, "some-run-image", experimental) + h.AssertNil(t, err) + + lastCallIndex := len(fakePhaseFactory.NewCalledWithProvider) - 1 + h.AssertNotEq(t, lastCallIndex, -1) + + configProvider = fakePhaseFactory.NewCalledWithProvider[lastCallIndex] + h.AssertEq(t, configProvider.Name(), "extender") + }) + + it("CNB_EXPERIMENTAL_MODE=warn is not enable in the environment", func() { + h.AssertSliceNotContains(t, configProvider.ContainerConfig().Env, "CNB_EXPERIMENTAL_MODE=warn") + }) + }) }) when("#Export", func() { diff --git a/pkg/client/build.go b/pkg/client/build.go index a6cac00606..8db3aedd1b 100644 --- a/pkg/client/build.go +++ b/pkg/client/build.go @@ -492,9 +492,6 @@ func (c *Client) Build(ctx context.Context, opts BuildOptions) error { defer c.docker.ImageRemove(context.Background(), ephemeralBuilder.Name(), types.ImageRemoveOptions{Force: true}) if len(bldr.OrderExtensions()) > 0 || len(ephemeralBuilder.OrderExtensions()) > 0 { - if !c.experimental { - return fmt.Errorf("experimental features must be enabled when builder contains image extensions") - } if builderOS == "windows" { return fmt.Errorf("builder contains image extensions which are not supported for Windows builds") } diff --git a/pkg/client/build_test.go b/pkg/client/build_test.go index 2371abfb94..3bf7eb1075 100644 --- a/pkg/client/build_test.go +++ b/pkg/client/build_test.go @@ -3013,40 +3013,19 @@ api = "0.2" when("there are extensions", func() { withExtensionsLabel = true - when("experimental", func() { - when("false", func() { - it("errors", func() { - err := subject.Build(context.TODO(), BuildOptions{ - Image: "some/app", - Builder: defaultBuilderName, - }) - - h.AssertNotNil(t, err) - }) - }) - - when("true", func() { - it.Before(func() { - subject.experimental = true + when("default configuration", func() { + it("succeeds", func() { + err := subject.Build(context.TODO(), BuildOptions{ + Image: "some/app", + Builder: defaultBuilderName, }) - it("succeeds", func() { - err := subject.Build(context.TODO(), BuildOptions{ - Image: "some/app", - Builder: defaultBuilderName, - }) - - h.AssertNil(t, err) - h.AssertEq(t, fakeLifecycle.Opts.BuilderImage, defaultBuilderName) - }) + h.AssertNil(t, err) + h.AssertEq(t, fakeLifecycle.Opts.BuilderImage, defaultBuilderName) }) }) when("os", func() { - it.Before(func() { - subject.experimental = true - }) - when("windows", func() { it.Before(func() { h.SkipIf(t, runtime.GOOS != "windows", "Skipped on non-windows") @@ -3076,10 +3055,6 @@ api = "0.2" }) when("pull policy", func() { - it.Before(func() { - subject.experimental = true - }) - when("always", func() { it("succeeds", func() { err := subject.Build(context.TODO(), BuildOptions{