diff --git a/internal/commands/extension_package.go b/internal/commands/extension_package.go index 57395c9f1..9c2642981 100644 --- a/internal/commands/extension_package.go +++ b/internal/commands/extension_package.go @@ -19,13 +19,14 @@ import ( // ExtensionPackageFlags define flags provided to the ExtensionPackage command type ExtensionPackageFlags struct { - PackageTomlPath string - Format string - Targets []string - Publish bool - Policy string - Path string - AdditionalTags []string + PackageTomlPath string + Format string + Targets []string + Publish bool + Policy string + Path string + AppendImageNameSuffix bool + AdditionalTags []string } // ExtensionPackager packages extensions @@ -114,15 +115,20 @@ func ExtensionPackage(logger logging.Logger, cfg config.Config, packager Extensi defer clean(filesToClean) } + if !flags.Publish && flags.AppendImageNameSuffix { + logger.Warnf("--append-image-name-suffix will be ignored, use combined with --publish") + } + if err := packager.PackageExtension(cmd.Context(), client.PackageBuildpackOptions{ - RelativeBaseDir: relativeBaseDir, - Name: name, - Format: flags.Format, - Config: exPackageCfg, - Publish: flags.Publish, - PullPolicy: pullPolicy, - Targets: multiArchCfg.Targets(), - AdditionalTags: flags.AdditionalTags, + RelativeBaseDir: relativeBaseDir, + Name: name, + Format: flags.Format, + Config: exPackageCfg, + Publish: flags.Publish, + AppendImageNameSuffix: flags.AppendImageNameSuffix && flags.Publish, + PullPolicy: pullPolicy, + Targets: multiArchCfg.Targets(), + AdditionalTags: flags.AdditionalTags, }); err != nil { return err } @@ -145,6 +151,7 @@ func ExtensionPackage(logger logging.Logger, cfg config.Config, packager Extensi cmd.Flags().StringVarP(&flags.PackageTomlPath, "config", "c", "", "Path to package TOML config") cmd.Flags().StringVarP(&flags.Format, "format", "f", "", `Format to save package as ("image" or "file")`) cmd.Flags().BoolVar(&flags.Publish, "publish", false, `Publish the extension directly to the container registry specified in , instead of the daemon (applies to "--format=image" only).`) + cmd.Flags().BoolVar(&flags.AppendImageNameSuffix, "append-image-name-suffix", false, "When publishing to a registry that doesn't allow overwrite existing tags use this flag to append a [os]-[arch] suffix to package ") cmd.Flags().StringVar(&flags.Policy, "pull-policy", "", "Pull policy to use. Accepted values are always, never, and if-not-present. The default is always") cmd.Flags().StringVarP(&flags.Path, "path", "p", "", "Path to the Extension that needs to be packaged") cmd.Flags().StringSliceVarP(&flags.Targets, "target", "t", nil, diff --git a/internal/commands/extension_package_test.go b/internal/commands/extension_package_test.go index 241c4dfc0..e90a4924e 100644 --- a/internal/commands/extension_package_test.go +++ b/internal/commands/extension_package_test.go @@ -181,6 +181,39 @@ func testExtensionPackageCommand(t *testing.T, when spec.G, it spec.S) { }) }) + when("--append-image-name-suffix", func() { + it("passes the flag to the packager when publishing", func() { + cmd := packageExtensionCommand(withExtensionPackager(fakeExtensionPackager)) + cmd.SetArgs([]string{ + "some-image-name", + "--config", "/path/to/some/file", + "--publish", + "--append-image-name-suffix", + }) + h.AssertNil(t, cmd.Execute()) + + receivedOptions := fakeExtensionPackager.CreateCalledWithOptions + h.AssertEq(t, receivedOptions.AppendImageNameSuffix, true) + }) + + it("is ignored and warns when not publishing", func() { + cmd := packageExtensionCommand( + withExtensionPackager(fakeExtensionPackager), + withExtensionLogger(logger), + ) + cmd.SetArgs([]string{ + "some-image-name", + "--config", "/path/to/some/file", + "--append-image-name-suffix", + }) + h.AssertNil(t, cmd.Execute()) + + receivedOptions := fakeExtensionPackager.CreateCalledWithOptions + h.AssertEq(t, receivedOptions.AppendImageNameSuffix, false) + h.AssertContains(t, outBuf.String(), "--append-image-name-suffix will be ignored") + }) + }) + when("no config path is specified", func() { when("no path is specified", func() { it("creates a default config with the uri set to the current working directory", func() { diff --git a/pkg/client/package_extension.go b/pkg/client/package_extension.go index 584700eb9..c9d68697b 100644 --- a/pkg/client/package_extension.go +++ b/pkg/client/package_extension.go @@ -8,6 +8,7 @@ import ( "github.com/pkg/errors" "github.com/buildpacks/pack/internal/layer" + "github.com/buildpacks/pack/internal/name" "github.com/buildpacks/pack/internal/style" "github.com/buildpacks/pack/pkg/buildpack" "github.com/buildpacks/pack/pkg/dist" @@ -103,7 +104,14 @@ func (c *Client) packageExtensionTarget(ctx context.Context, opts PackageBuildpa return digest, err } case FormatImage: - img, err := packageBuilder.SaveAsImage(opts.Name, opts.Publish, target, opts.Labels, opts.AdditionalTags...) + packageName := opts.Name + if multiArch && opts.AppendImageNameSuffix { + packageName, err = name.AppendSuffix(packageName, target) + if err != nil { + return "", errors.Wrap(err, "invalid image name") + } + } + img, err := packageBuilder.SaveAsImage(packageName, opts.Publish, target, opts.Labels, opts.AdditionalTags...) if err != nil { return digest, errors.Wrapf(err, "saving image") }