diff --git a/acceptance/acceptance_test.go b/acceptance/acceptance_test.go index da19ad6fd..edff79cd4 100644 --- a/acceptance/acceptance_test.go +++ b/acceptance/acceptance_test.go @@ -1551,6 +1551,45 @@ func testAcceptance( assertBuildpackOutput := assertions.NewTestBuildpackOutputAssertionManager(t, output) assertBuildpackOutput.ReportsBuildStep("Simple Layers Buildpack") }) + + when("buildpackage is in a registry", func() { + it("adds the buildpacks to the builder and runs them", func() { + h.SkipIf(t, !pack.SupportsFeature(invoke.PlatformRetries), "") + packageImageName = registryConfig.RepoName("buildpack-" + h.RandString(8)) + + packageTomlPath := generatePackageTomlWithOS(t, assert, pack, tmpDir, "package_for_build_cmd.toml", imageManager.HostOS()) + packageImage := buildpacks.NewPackageImage( + t, + pack, + packageImageName, + packageTomlPath, + buildpacks.WithRequiredBuildpacks( + buildpacks.BpFolderSimpleLayersParent, + buildpacks.BpFolderSimpleLayers, + ), + buildpacks.WithPublish(), + ) + + buildpackManager.PrepareBuildModules(tmpDir, packageImage) + + output := pack.RunSuccessfully( + "build", repoName, + "-p", filepath.Join("testdata", "mock_app"), + "--buildpack", packageImageName, + ) + + assertOutput := assertions.NewOutputAssertionManager(t, output) + assertOutput.ReportsAddingBuildpack( + "simple/layers/parent", + "simple-layers-parent-version", + ) + assertOutput.ReportsAddingBuildpack("simple/layers", "simple-layers-version") + assertOutput.ReportsSuccessfulImageBuild(repoName) + + assertBuildpackOutput := assertions.NewTestBuildpackOutputAssertionManager(t, output) + assertBuildpackOutput.ReportsBuildStep("Simple Layers Buildpack") + }) + }) }) when("the argument is a buildpackage file", func() { diff --git a/acceptance/invoke/pack.go b/acceptance/invoke/pack.go index 35bd58f5b..caa60f136 100644 --- a/acceptance/invoke/pack.go +++ b/acceptance/invoke/pack.go @@ -235,6 +235,7 @@ const ( ForceRebase BuildpackFlatten MetaBuildpackFolder + PlatformRetries ) var featureTests = map[Feature]func(i *PackInvoker) bool{ @@ -262,6 +263,9 @@ var featureTests = map[Feature]func(i *PackInvoker) bool{ MetaBuildpackFolder: func(i *PackInvoker) bool { return i.atLeast("v0.30.0") }, + PlatformRetries: func(i *PackInvoker) bool { + return i.atLeast("v0.32.1") + }, } func (i *PackInvoker) SupportsFeature(f Feature) bool { diff --git a/pkg/image/fetcher.go b/pkg/image/fetcher.go index a014dc8b9..60548fcc1 100644 --- a/pkg/image/fetcher.go +++ b/pkg/image/fetcher.go @@ -109,7 +109,13 @@ func (f *Fetcher) Fetch(ctx context.Context, name string, options FetchOptions) } f.logger.Debugf("Pulling image %s", style.Symbol(name)) - err = f.pullImage(ctx, name, options.Platform) + if err = f.pullImage(ctx, name, options.Platform); err != nil { + // sample error from docker engine: + // image with reference was found but does not match the specified platform: wanted linux/amd64, actual: linux + if strings.Contains(err.Error(), "does not match the specified platform") { + err = f.pullImage(ctx, name, "") + } + } if err != nil && !errors.Is(err, ErrNotFound) { return nil, err } diff --git a/pkg/image/fetcher_test.go b/pkg/image/fetcher_test.go index 03b1f0467..3b119e15f 100644 --- a/pkg/image/fetcher_test.go +++ b/pkg/image/fetcher_test.go @@ -6,8 +6,11 @@ import ( "fmt" "os" "path/filepath" + "runtime" "testing" + "github.com/buildpacks/imgutil" + "github.com/buildpacks/imgutil/local" "github.com/buildpacks/imgutil/remote" "github.com/docker/docker/client" @@ -48,12 +51,17 @@ func testFetcher(t *testing.T, when spec.G, it spec.S) { repoName string repo string outBuf bytes.Buffer + osType string ) it.Before(func() { repo = "some-org/" + h.RandString(10) repoName = registryConfig.RepoName(repo) imageFetcher = image.NewFetcher(logging.NewLogWithWriters(&outBuf, &outBuf), docker) + + info, err := docker.Info(context.TODO()) + h.AssertNil(t, err) + osType = info.OSType }) when("#Fetch", func() { @@ -213,6 +221,19 @@ func testFetcher(t *testing.T, when spec.G, it spec.S) { _, err := imageFetcher.Fetch(context.TODO(), repoName, image.FetchOptions{Daemon: true, PullPolicy: image.PullAlways, Platform: "some-unsupported-platform"}) h.AssertError(t, err, "unknown operating system or architecture") }) + + when("remote platform does not match", func() { + it.Before(func() { + img, err := remote.NewImage(repoName, authn.DefaultKeychain, remote.WithDefaultPlatform(imgutil.Platform{OS: osType, Architecture: ""})) + h.AssertNil(t, err) + h.AssertNil(t, img.Save()) + }) + + it("retry without setting platform", func() { + _, err := imageFetcher.Fetch(context.TODO(), repoName, image.FetchOptions{Daemon: true, PullPolicy: image.PullAlways, Platform: fmt.Sprintf("%s/%s", osType, runtime.GOARCH)}) + h.AssertNil(t, err) + }) + }) }) })