diff --git a/acceptance/acceptance_test.go b/acceptance/acceptance_test.go index 4ab78a4e1d..d6ad75cccf 100644 --- a/acceptance/acceptance_test.go +++ b/acceptance/acceptance_test.go @@ -2186,6 +2186,9 @@ func testAcceptance( }) it("fails with a message", func() { + it.Before(func() { + h.SkipIf(t, pack.SupportsFeature(invoke.StackWarning), "stack is validated in prior versions") + }) output, err := pack.Run( "build", repoName, "-p", filepath.Join("testdata", "mock_app"), @@ -2199,6 +2202,21 @@ func testAcceptance( "pack.test.stack", ) }) + + it("succeeds with a warning", func() { + it.Before(func() { + h.SkipIf(t, !pack.SupportsFeature(invoke.StackWarning), "stack is no longer validated") + }) + 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 ba8e644a52..e8d6f337c9 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 9346bdce5a..739cb3c6d4 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 750baa7ac6..592f02e851 100644 --- a/pkg/client/build.go +++ b/pkg/client/build.go @@ -405,10 +405,13 @@ 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 +942,22 @@ 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, nil } 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 987786acd6..87d9c355f1 100644 --- a/pkg/client/build_test.go +++ b/pkg/client/build_test.go @@ -287,7 +287,8 @@ func testBuild(t *testing.T, when spec.G, it spec.S) { AppPath: filepath.Join("testdata", "some-app"), })) - h.AssertEq(t, strings.TrimSpace(outBuf.String()), "some/app@sha256:363c754893f0efe22480b4359a5956cf3bd3ce22742fc576973c61348308c2e4") + actual := strings.TrimSpace(outBuf.String()) + h.AssertEq(t, actual, "some/app@sha256:363c754893f0efe22480b4359a5956cf3bd3ce22742fc576973c61348308c2e4") }) }) }) @@ -531,14 +532,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") }) })