diff --git a/acceptance/acceptance_test.go b/acceptance/acceptance_test.go index 4ab78a4e1..a0ce4a037 100644 --- a/acceptance/acceptance_test.go +++ b/acceptance/acceptance_test.go @@ -2185,20 +2185,45 @@ func testAcceptance( imageManager.CleanupImages(runImageName) }) - it("fails with a message", func() { - output, err := pack.Run( - "build", repoName, - "-p", filepath.Join("testdata", "mock_app"), - "--run-image", runImageName, - ) - assert.NotNil(err) + when("should validate stack", func() { + it.Before(func() { + h.SkipIf(t, pack.SupportsFeature(invoke.StackWarning), "stack is validated in prior versions") + }) + it("fails with a message", func() { - assertOutput := assertions.NewOutputAssertionManager(t, output) - assertOutput.ReportsRunImageStackNotMatchingBuilder( - "other.stack.id", - "pack.test.stack", - ) + output, err := pack.Run( + "build", repoName, + "-p", filepath.Join("testdata", "mock_app"), + "--run-image", runImageName, + ) + assert.NotNil(err) + + assertOutput := assertions.NewOutputAssertionManager(t, output) + assertOutput.ReportsRunImageStackNotMatchingBuilder( + "other.stack.id", + "pack.test.stack", + ) + }) }) + + when("should not validate stack", func() { + it.Before(func() { + h.SkipIf(t, !pack.SupportsFeature(invoke.StackWarning), "stack is no longer validated") + }) + it("succeeds with a warning", func() { + + output, err := pack.Run( + "build", repoName, + "-p", filepath.Join("testdata", "mock_app"), + "--run-image", runImageName, + ) + assert.Nil(err) + + assertOutput := assertions.NewOutputAssertionManager(t, output) + assertOutput.ReportsDeprecatedUseOfStack() + }) + }) + }) }) diff --git a/acceptance/assertions/output.go b/acceptance/assertions/output.go index ba8e644a5..e8d6f337c 100644 --- a/acceptance/assertions/output.go +++ b/acceptance/assertions/output.go @@ -118,6 +118,12 @@ func (o OutputAssertionManager) ReportsRunImageStackNotMatchingBuilder(runImageS ) } +func (o OutputAssertionManager) ReportsDeprecatedUseOfStack() { + o.testObject.Helper() + + o.assert.Contains(o.output, "Warning: deprecated usage of stack") +} + func (o OutputAssertionManager) WithoutColors() { o.testObject.Helper() o.testObject.Log("has no color") diff --git a/acceptance/invoke/pack.go b/acceptance/invoke/pack.go index 9346bdce5..a7a07602f 100644 --- a/acceptance/invoke/pack.go +++ b/acceptance/invoke/pack.go @@ -241,6 +241,7 @@ const ( ManifestCommands PlatformOption MultiPlatformBuildersAndBuildPackages + StackWarning ) var featureTests = map[Feature]func(i *PackInvoker) bool{ @@ -286,6 +287,9 @@ var featureTests = map[Feature]func(i *PackInvoker) bool{ MultiPlatformBuildersAndBuildPackages: func(i *PackInvoker) bool { return i.atLeast("v0.34.0") }, + StackWarning: func(i *PackInvoker) bool { + return i.atLeast("v0.37.0") + }, } func (i *PackInvoker) SupportsFeature(f Feature) bool { diff --git a/pkg/client/build.go b/pkg/client/build.go index 750baa7ac..b44d722d7 100644 --- a/pkg/client/build.go +++ b/pkg/client/build.go @@ -405,10 +405,14 @@ func (c *Client) Build(ctx context.Context, opts BuildOptions) error { pathsConfig.targetRunImagePath = targetRunImagePath pathsConfig.hostRunImagePath = hostRunImagePath } - runImage, err := c.validateRunImage(ctx, runImageName, fetchOptions, bldr.StackID) + + runImage, warnings, err := c.validateRunImage(ctx, runImageName, fetchOptions, bldr.StackID) if err != nil { return errors.Wrapf(err, "invalid run-image '%s'", runImageName) } + for _, warning := range warnings { + c.logger.Warn(warning) + } var runMixins []string if _, err := dist.GetLabel(runImage, stack.MixinsLabel, &runMixins); err != nil { @@ -939,22 +943,24 @@ func (c *Client) getBuilder(img imgutil.Image) (*builder.Builder, error) { return bldr, nil } -func (c *Client) validateRunImage(context context.Context, name string, opts image.FetchOptions, expectedStack string) (imgutil.Image, error) { +func (c *Client) validateRunImage(context context.Context, name string, opts image.FetchOptions, expectedStack string) (runImage imgutil.Image, warnings []string, err error) { if name == "" { - return nil, errors.New("run image must be specified") + return nil, nil, errors.New("run image must be specified") } img, err := c.imageFetcher.Fetch(context, name, opts) if err != nil { - return nil, err + return nil, nil, err } stackID, err := img.Label("io.buildpacks.stack.id") if err != nil { - return nil, err + return nil, nil, err } + if stackID != expectedStack { - return nil, fmt.Errorf("run-image stack id '%s' does not match builder stack '%s'", stackID, expectedStack) + warnings = append(warnings, "deprecated usage of stack") } - return img, nil + + return img, warnings, err } func (c *Client) validateMixins(additionalBuildpacks []buildpack.BuildModule, bldr *builder.Builder, runImageName string, runMixins []string) error { diff --git a/pkg/client/build_test.go b/pkg/client/build_test.go index 987786acd..0cb80a934 100644 --- a/pkg/client/build_test.go +++ b/pkg/client/build_test.go @@ -531,14 +531,14 @@ func testBuild(t *testing.T, when spec.G, it spec.S) { h.AssertNil(t, fakeRunImage.SetLabel("io.buildpacks.stack.id", "other.stack")) }) - it("errors", func() { - h.AssertError(t, subject.Build(context.TODO(), BuildOptions{ + it("warning", func() { + err := subject.Build(context.TODO(), BuildOptions{ Image: "some/app", Builder: defaultBuilderName, RunImage: "custom/run", - }), - "invalid run-image 'custom/run': run-image stack id 'other.stack' does not match builder stack 'some.stack.id'", - ) + }) + h.AssertNil(t, err) + h.AssertContains(t, outBuf.String(), "Warning: deprecated usage of stack") }) })