From 51c63eab39e41e1184924388184e984ec58d48b3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 5 Oct 2020 22:31:26 +0000 Subject: [PATCH 01/14] Bump actions/setup-go from v2-beta to v2.1.3 Bumps [actions/setup-go](https://github.com/actions/setup-go) from v2-beta to v2.1.3. - [Release notes](https://github.com/actions/setup-go/releases) - [Commits](https://github.com/actions/setup-go/compare/v2-beta...37335c7bb261b353407cff977110895fa0b4f7d8) Signed-off-by: dependabot[bot] --- .github/workflows/build.yml | 2 +- .github/workflows/compatibility.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 724b04eca..d074648e3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -60,7 +60,7 @@ jobs: echo "::set-env name=PACK_VERSION::$version" shell: bash - name: Set up go - uses: actions/setup-go@v2-beta + uses: actions/setup-go@v2.1.3 with: go-version: '1.14' - name: Set up go env diff --git a/.github/workflows/compatibility.yml b/.github/workflows/compatibility.yml index a8f666576..07a341dfa 100644 --- a/.github/workflows/compatibility.yml +++ b/.github/workflows/compatibility.yml @@ -44,7 +44,7 @@ jobs: steps: - uses: actions/checkout@v2 - name: Set up go - uses: actions/setup-go@v2-beta + uses: actions/setup-go@v2.1.3 with: go-version: '1.14' - name: Set up go env From e6fd50cd55a733219a37393940ee0da7ea88679b Mon Sep 17 00:00:00 2001 From: Travis Date: Mon, 5 Oct 2020 14:01:44 -0600 Subject: [PATCH 02/14] feat: pack set-registry Signed-off-by: Travis --- cmd/cmd.go | 3 +- internal/commands/set_default_registry.go | 54 +++++++++++++ .../commands/set_default_registry_test.go | 78 +++++++++++++++++++ 3 files changed, 134 insertions(+), 1 deletion(-) create mode 100644 internal/commands/set_default_registry.go create mode 100644 internal/commands/set_default_registry_test.go diff --git a/cmd/cmd.go b/cmd/cmd.go index e9dedb4f0..a1e3cee52 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -84,9 +84,10 @@ func NewPackCommand(logger ConfigurableLogger) (*cobra.Command, error) { rootCmd.AddCommand(commands.Report(logger, pack.Version)) if cfg.Experimental { - rootCmd.AddCommand(commands.ListBuildpackRegistries(logger, cfg)) rootCmd.AddCommand(commands.AddBuildpackRegistry(logger, cfg, cfgPath)) + rootCmd.AddCommand(commands.ListBuildpackRegistries(logger, cfg)) rootCmd.AddCommand(commands.RegisterBuildpack(logger, cfg, &packClient)) + rootCmd.AddCommand(commands.SetDefaultRegistry(logger, cfg, cfgPath)) rootCmd.AddCommand(commands.YankBuildpack(logger, cfg, &packClient)) } diff --git a/internal/commands/set_default_registry.go b/internal/commands/set_default_registry.go new file mode 100644 index 000000000..938a5cf41 --- /dev/null +++ b/internal/commands/set_default_registry.go @@ -0,0 +1,54 @@ +package commands + +import ( + "github.com/pkg/errors" + "github.com/spf13/cobra" + + "github.com/buildpacks/pack/internal/config" + "github.com/buildpacks/pack/internal/style" + "github.com/buildpacks/pack/logging" +) + +func SetDefaultRegistry(logger logging.Logger, cfg config.Config, cfgPath string) *cobra.Command { + var ( + registryName string + ) + + cmd := &cobra.Command{ + Use: "set-default-registry ", + Args: cobra.ExactArgs(1), + Short: "Set default registry", + RunE: logError(logger, func(cmd *cobra.Command, args []string) error { + registryName = args[0] + if !containsRegistry(config.GetRegistries(cfg), registryName) { + return errors.Errorf("no registry with the name %s exists", style.Symbol(registryName)) + } + + if cfg.DefaultRegistryName != registryName { + cfg.DefaultRegistryName = registryName + err := config.Write(cfg, cfgPath) + if err != nil { + return err + } + } + + logger.Infof("Successfully set %s as the default registry", style.Symbol(registryName)) + + return nil + }), + } + cmd.Example = "pack set-default-registry myregistry" + AddHelpFlag(cmd, "set-default-registry") + + return cmd +} + +func containsRegistry(registries []config.Registry, registry string) bool { + for _, r := range registries { + if r.Name == registry { + return true + } + } + + return false +} diff --git a/internal/commands/set_default_registry_test.go b/internal/commands/set_default_registry_test.go new file mode 100644 index 000000000..743abcf35 --- /dev/null +++ b/internal/commands/set_default_registry_test.go @@ -0,0 +1,78 @@ +package commands_test + +import ( + "bytes" + "io/ioutil" + "os" + "path/filepath" + "testing" + + "github.com/heroku/color" + "github.com/sclevine/spec" + "github.com/sclevine/spec/report" + + "github.com/buildpacks/pack/internal/commands" + "github.com/buildpacks/pack/internal/config" + ilogging "github.com/buildpacks/pack/internal/logging" + h "github.com/buildpacks/pack/testhelpers" +) + +func TestSetDefaultRegistry(t *testing.T) { + color.Disable(true) + defer color.Disable(false) + + spec.Run(t, "Commands", testSetDefaultRegistryCommand, spec.Parallel(), spec.Report(report.Terminal{})) +} + +func testSetDefaultRegistryCommand(t *testing.T, when spec.G, it spec.S) { + when("#SetDefaultRegistry", func() { + var ( + outBuf bytes.Buffer + logger = ilogging.NewLogWithWriters(&outBuf, &outBuf) + tmpDir string + configFile string + assert = h.NewAssertionManager(t) + ) + + it.Before(func() { + var err error + tmpDir, err = ioutil.TempDir("", "pack-home-*") + assert.Nil(err) + + configFile = filepath.Join(tmpDir, "config.toml") + }) + + it.After(func() { + _ = os.RemoveAll(tmpDir) + }) + + it("should set the default registry", func() { + cfg := config.Config{ + Registries: []config.Registry{ + { + Name: "myregistry", + URL: "https://github.com/buildpacks/registry-index", + Type: "Github", + }, + }, + } + command := commands.SetDefaultRegistry(logger, cfg, configFile) + command.SetArgs([]string{"myregistry"}) + assert.Succeeds(command.Execute()) + + cfg, err := config.Read(configFile) + assert.Nil(err) + + assert.Equal(cfg.DefaultRegistryName, "myregistry") + }) + + it("should fail if no corresponding registry exists", func() { + command := commands.SetDefaultRegistry(logger, config.Config{}, configFile) + command.SetArgs([]string{"myregistry"}) + assert.Error(command.Execute()) + + output := outBuf.String() + h.AssertContains(t, output, "no registry with the name 'myregistry' exists") + }) + }) +} From c09405567bfd2a1dc10377f74ef3cbb97b635d93 Mon Sep 17 00:00:00 2001 From: anshlykov Date: Sat, 10 Oct 2020 21:19:04 +0300 Subject: [PATCH 03/14] remove --no-pull flag Signed-off-by: anshlykov --- acceptance/acceptance_test.go | 22 +++--- internal/commands/build.go | 14 ---- internal/commands/build_test.go | 36 +-------- internal/commands/create_builder.go | 22 +----- internal/commands/create_builder_test.go | 68 ---------------- internal/commands/package_buildpack.go | 22 +----- internal/commands/package_buildpack_test.go | 86 --------------------- internal/commands/rebase.go | 14 ---- internal/commands/rebase_test.go | 44 ----------- package_buildpack_test.go | 4 +- 10 files changed, 16 insertions(+), 316 deletions(-) diff --git a/acceptance/acceptance_test.go b/acceptance/acceptance_test.go index d16cffbfe..935f41a19 100644 --- a/acceptance/acceptance_test.go +++ b/acceptance/acceptance_test.go @@ -19,6 +19,8 @@ import ( "testing" "time" + pubcfg "github.com/buildpacks/pack/config" + "github.com/buildpacks/pack/acceptance/buildpacks" "github.com/docker/docker/pkg/stdcopy" @@ -360,7 +362,7 @@ func testWithoutSpecificBuilderRequirement( }) }) - when("--no-pull", func() { + when("--pull-policy=never", func() { it("should use local image", func() { nestedPackageName := "test/package-" + h.RandString(10) nestedPackage := buildpacks.NewPackageImage( @@ -376,11 +378,10 @@ func testWithoutSpecificBuilderRequirement( packageName := registryConfig.RepoName("test/package-" + h.RandString(10)) defer h.DockerRmi(dockerCli, packageName) - // TODO: Replace --no-pull with pull-policy never. See https://github.com/buildpacks/pack/issues/775 pack.JustRunSuccessfully( "package-buildpack", packageName, "-c", aggregatePackageToml, - "--no-pull", + "--pull-policy", pubcfg.PullNever.String(), ) _, _, err := dockerCli.ImageInspectWithRaw(context.Background(), packageName) @@ -404,11 +405,10 @@ func testWithoutSpecificBuilderRequirement( packageName := registryConfig.RepoName("test/package-" + h.RandString(10)) defer h.DockerRmi(dockerCli, packageName) - // TODO: Replace --no-pull with pull-policy never. See https://github.com/buildpacks/pack/issues/775 output, err := pack.Run( "package-buildpack", packageName, "-c", aggregatePackageToml, - "--no-pull", + "--pull-policy", pubcfg.PullNever.String(), ) assert.NotNil(err) assertions.NewOutputAssertionManager(t, output).ReportsImageNotExistingOnDaemon(nestedPackageName) @@ -1941,13 +1941,12 @@ include = [ "*.jar", "media/mountain.jpg", "media/person.png" ] } buildRunImage(runBefore, "contents-before-1", "contents-before-2") - // TODO: Replace --no-pull with pull-policy never. See https://github.com/buildpacks/pack/issues/775 pack.RunSuccessfully( "build", repoName, "-p", filepath.Join("testdata", "mock_app"), "--builder", builderName, "--run-image", runBefore, - "--no-pull", + "--pull-policy", pubcfg.PullNever.String(), ) origID = h.ImageID(t, repoName) assertMockAppRunsWithOutput(t, @@ -1982,11 +1981,10 @@ include = [ "*.jar", "media/mountain.jpg", "media/person.png" ] }) it("uses provided run image", func() { - // TODO: Replace --no-pull with pull-policy never. See https://github.com/buildpacks/pack/issues/775 output := pack.RunSuccessfully( "rebase", repoName, "--run-image", runAfter, - "--no-pull", + "--pull-policy", pubcfg.PullNever.String(), ) assert.Contains(output, fmt.Sprintf("Successfully rebased image '%s'", repoName)) @@ -2013,8 +2011,7 @@ include = [ "*.jar", "media/mountain.jpg", "media/person.png" ] }) it("prefers the local mirror", func() { - // TODO: Replace --no-pull with pull-policy never. See https://github.com/buildpacks/pack/issues/775 - output := pack.RunSuccessfully("rebase", repoName, "--no-pull") + output := pack.RunSuccessfully("rebase", repoName, "--pull-policy", pubcfg.PullNever.String()) assertOutput := assertions.NewOutputAssertionManager(t, output) assertOutput.ReportsSelectingRunImageMirrorFromLocalConfig(localRunImageMirror) @@ -2037,8 +2034,7 @@ include = [ "*.jar", "media/mountain.jpg", "media/person.png" ] }) it("selects the best mirror", func() { - // TODO: Replace --no-pull with pull-policy never. See https://github.com/buildpacks/pack/issues/775 - output := pack.RunSuccessfully("rebase", repoName, "--no-pull") + output := pack.RunSuccessfully("rebase", repoName, "--pull-policy", pubcfg.PullNever.String()) assertOutput := assertions.NewOutputAssertionManager(t, output) assertOutput.ReportsSelectingRunImageMirror(runImageMirror) diff --git a/internal/commands/build.go b/internal/commands/build.go index 62521121c..84901b3c6 100644 --- a/internal/commands/build.go +++ b/internal/commands/build.go @@ -23,7 +23,6 @@ import ( type BuildFlags struct { Publish bool - NoPull bool ClearCache bool TrustBuilder bool AppPath string @@ -160,9 +159,6 @@ func buildCommandFlags(cmd *cobra.Command, buildFlags *BuildFlags, cfg config.Co cmd.Flags().StringArrayVar(&buildFlags.Volumes, "volume", nil, "Mount host volume into the build container, in the form ':[:]'."+multiValueHelp("volume")) cmd.Flags().StringVarP(&buildFlags.DefaultProcessType, "default-process", "D", "", `Set the default process type. (default "web")`) cmd.Flags().StringVar(&buildFlags.Policy, "pull-policy", "", `Pull policy to use. Accepted values are always, never, and if-not-present. (default "always")`) - // TODO: Remove --no-pull flag after v0.13.0 released. See https://github.com/buildpacks/pack/issues/775 - cmd.Flags().BoolVar(&buildFlags.NoPull, "no-pull", false, "Skip pulling builder and run images before use") - cmd.Flags().MarkHidden("no-pull") } func validateBuildFlags(flags *BuildFlags, cfg config.Config, packClient PackClient, logger logging.Logger) error { @@ -175,16 +171,6 @@ func validateBuildFlags(flags *BuildFlags, cfg config.Config, packClient PackCli return pack.NewExperimentError("Support for buildpack registries is currently experimental.") } - if flags.NoPull { - logger.Warn("Flag --no-pull has been deprecated") - - if flags.Policy != "" { - logger.Warn("Flag --no-pull ignored in favor of --pull-policy") - } else { - flags.Policy = pubcfg.PullNever.String() - } - } - return nil } diff --git a/internal/commands/build_test.go b/internal/commands/build_test.go index 497e79e43..41b71eb78 100644 --- a/internal/commands/build_test.go +++ b/internal/commands/build_test.go @@ -9,8 +9,6 @@ import ( "reflect" "testing" - pubcfg "github.com/buildpacks/pack/config" - "github.com/golang/mock/gomock" "github.com/heroku/color" "github.com/pkg/errors" @@ -136,32 +134,9 @@ func testBuildCommand(t *testing.T, when spec.G, it spec.S) { }) }) - when("--no-pull", func() { - it("sets pull-policy=never and logs warning", func() { - mockClient.EXPECT(). - Build(gomock.Any(), EqBuildOptionsWithPullPolicy(pubcfg.PullNever)). - Return(nil) - - command.SetArgs([]string{"image", "--builder", "my-builder", "--no-pull"}) - h.AssertNil(t, command.Execute()) - h.AssertContains(t, outBuf.String(), "Warning: Flag --no-pull has been deprecated") - }) - - it("overrides if pull-policy set to value and logs warning", func() { - mockClient.EXPECT(). - Build(gomock.Any(), EqBuildOptionsWithPullPolicy(pubcfg.PullAlways)). - Return(nil) - - command.SetArgs([]string{"image", "--builder", "my-builder", "--no-pull", "--pull-policy", "always"}) - h.AssertNil(t, command.Execute()) - h.AssertContains(t, outBuf.String(), "Warning: Flag --no-pull has been deprecated") - h.AssertContains(t, outBuf.String(), "Warning: Flag --no-pull ignored in favor of --pull-policy") - }) - }) - when("--pull-policy", func() { it("returns error for unknown policy", func() { - command.SetArgs([]string{"image", "--builder", "my-builder", "--no-pull", "--pull-policy", "unknown-policy"}) + command.SetArgs([]string{"image", "--builder", "my-builder", "--pull-policy", "unknown-policy"}) h.AssertError(t, command.Execute(), "parsing pull policy") }) }) @@ -637,15 +612,6 @@ func EqBuildOptionsDefaultProcess(defaultProc string) gomock.Matcher { } } -func EqBuildOptionsWithPullPolicy(policy pubcfg.PullPolicy) gomock.Matcher { - return buildOptionsMatcher{ - description: fmt.Sprintf("PullPolicy=%s", policy), - equals: func(o pack.BuildOptions) bool { - return o.PullPolicy == policy - }, - } -} - func EqBuildOptionsWithNetwork(network string) gomock.Matcher { return buildOptionsMatcher{ description: fmt.Sprintf("Network=%s", network), diff --git a/internal/commands/create_builder.go b/internal/commands/create_builder.go index 97d069b4b..1a0eccca5 100644 --- a/internal/commands/create_builder.go +++ b/internal/commands/create_builder.go @@ -19,7 +19,6 @@ import ( type CreateBuilderFlags struct { BuilderTomlPath string Publish bool - NoPull bool Registry string Policy string } @@ -33,7 +32,7 @@ func CreateBuilder(logger logging.Logger, cfg config.Config, client PackClient) Args: cobra.ExactArgs(1), Short: "Create builder image", RunE: logError(logger, func(cmd *cobra.Command, args []string) error { - if err := validateCreateBuilderFlags(&flags, cfg, logger); err != nil { + if err := validateCreateBuilderFlags(&flags, cfg); err != nil { return err } @@ -78,23 +77,16 @@ func CreateBuilder(logger logging.Logger, cfg config.Config, client PackClient) cmd.Flags().StringVarP(&flags.BuilderTomlPath, "config", "c", "", "Path to builder TOML file (required)") cmd.Flags().BoolVar(&flags.Publish, "publish", false, "Publish to registry") cmd.Flags().StringVar(&flags.Policy, "pull-policy", "", "Pull policy to use. Accepted values are always, never, and if-not-present. The default is always") - // TODO: Remove --no-pull flag after v0.13.0 released. See https://github.com/buildpacks/pack/issues/775 - cmd.Flags().BoolVar(&flags.NoPull, "no-pull", false, "Skip pulling build image before use") - cmd.Flags().MarkHidden("no-pull") AddHelpFlag(cmd, "create-builder") return cmd } -func validateCreateBuilderFlags(flags *CreateBuilderFlags, cfg config.Config, logger logging.Logger) error { +func validateCreateBuilderFlags(flags *CreateBuilderFlags, cfg config.Config) error { if flags.Publish && flags.Policy == pubcfg.PullNever.String() { return errors.Errorf("--publish and --pull-policy never cannot be used together. The --publish flag requires the use of remote images.") } - if flags.Publish && flags.NoPull { - return errors.Errorf("The --publish and --no-pull flags cannot be used together. The --publish flag requires the use of remote images.") - } - if flags.Registry != "" && !cfg.Experimental { return pack.NewExperimentError("Support for buildpack registries is currently experimental.") } @@ -103,15 +95,5 @@ func validateCreateBuilderFlags(flags *CreateBuilderFlags, cfg config.Config, lo return errors.Errorf("Please provide a builder config path, using --config.") } - if flags.NoPull { - logger.Warn("Flag --no-pull has been deprecated, please use `--pull-policy never` instead") - - if flags.Policy != "" { - logger.Warn("Flag --no-pull ignored in favor of --pull-policy") - } else { - flags.Policy = pubcfg.PullNever.String() - } - } - return nil } diff --git a/internal/commands/create_builder_test.go b/internal/commands/create_builder_test.go index 777a4a007..f0fe9fcbb 100644 --- a/internal/commands/create_builder_test.go +++ b/internal/commands/create_builder_test.go @@ -6,11 +6,6 @@ import ( "path/filepath" "testing" - "github.com/buildpacks/pack" - "github.com/buildpacks/pack/builder" - pubcfg "github.com/buildpacks/pack/config" - "github.com/buildpacks/pack/internal/dist" - "github.com/golang/mock/gomock" "github.com/heroku/color" "github.com/sclevine/spec" @@ -35,11 +30,6 @@ const validConfig = ` ` -var validConfigStruct = builder.Config{ - Buildpacks: []builder.BuildpackConfig{{BuildpackInfo: dist.BuildpackInfo{ID: "some.buildpack"}}}, - Order: dist.Order{{Group: []dist.BuildpackRef{{BuildpackInfo: dist.BuildpackInfo{ID: "some.buildpack"}}}}}, -} - func TestCreateBuilderCommand(t *testing.T) { color.Disable(true) defer color.Disable(false) @@ -76,20 +66,6 @@ func testCreateBuilderCommand(t *testing.T, when spec.G, it spec.S) { }) when("#CreateBuilder", func() { - when("both --publish and --no-pull flags are specified", func() { - it("errors with a descriptive message", func() { - command.SetArgs([]string{ - "some/builder", - "--config", "some-config-path", - "--publish", - "--no-pull", - }) - err := command.Execute() - h.AssertNotNil(t, err) - h.AssertError(t, err, "The --publish and --no-pull flags cannot be used together. The --publish flag requires the use of remote images.") - }) - }) - when("both --publish and pull-policy=never flags are specified", func() { it("errors with a descriptive message", func() { command.SetArgs([]string{ @@ -105,50 +81,6 @@ func testCreateBuilderCommand(t *testing.T, when spec.G, it spec.S) { }) }) - when("no-pull flag is specified", func() { - it.Before(func() { - h.AssertNil(t, ioutil.WriteFile(builderConfigPath, []byte(validConfig), 0666)) - }) - - it("works and logs warning", func() { - opts := pack.CreateBuilderOptions{ - BuilderName: "some/builder", - Config: validConfigStruct, - PullPolicy: pubcfg.PullNever, - } - mockClient.EXPECT().CreateBuilder(gomock.Any(), opts).Return(nil) - - command.SetArgs([]string{ - "some/builder", - "--config", builderConfigPath, - "--no-pull", - }) - h.AssertNil(t, command.Execute()) - h.AssertContains(t, outBuf.String(), "Warning: Flag --no-pull has been deprecated") - }) - - it("disregards no-pull if used with pull-policy always and logs warning", func() { - opts := pack.CreateBuilderOptions{ - BuilderName: "some/builder", - Config: validConfigStruct, - PullPolicy: pubcfg.PullAlways, - } - mockClient.EXPECT().CreateBuilder(gomock.Any(), opts).Return(nil) - - command.SetArgs([]string{ - "some/builder", - "--config", builderConfigPath, - "--no-pull", - "--pull-policy", - "always", - }) - h.AssertNil(t, command.Execute()) - output := outBuf.String() - h.AssertContains(t, output, "Warning: Flag --no-pull has been deprecated") - h.AssertContains(t, output, "Warning: Flag --no-pull ignored in favor of --pull-policy") - }) - }) - when("--pull-policy", func() { it("returns error for unknown policy", func() { command.SetArgs([]string{ diff --git a/internal/commands/package_buildpack.go b/internal/commands/package_buildpack.go index c1c645709..d3a3d68f6 100644 --- a/internal/commands/package_buildpack.go +++ b/internal/commands/package_buildpack.go @@ -19,7 +19,6 @@ type PackageBuildpackFlags struct { PackageTomlPath string Format string Publish bool - NoPull bool Policy string } @@ -42,7 +41,7 @@ func PackageBuildpack(logger logging.Logger, client BuildpackPackager, packageCo Short: "Package buildpack in OCI format.", Args: cobra.ExactValidArgs(1), RunE: logError(logger, func(cmd *cobra.Command, args []string) error { - if err := validatePackageBuildpackFlags(&flags, logger); err != nil { + if err := validatePackageBuildpackFlags(&flags); err != nil { return err } @@ -86,36 +85,19 @@ func PackageBuildpack(logger logging.Logger, client BuildpackPackager, packageCo cmd.Flags().StringVarP(&flags.Format, "format", "f", "", `Format to save package as ("image" or "file")`) cmd.Flags().BoolVar(&flags.Publish, "publish", false, `Publish to registry (applies to "--image" only)`) cmd.Flags().StringVar(&flags.Policy, "pull-policy", "", "Pull policy to use. Accepted values are always, never, and if-not-present. The default is always") - // TODO: Remove --no-pull flag after v0.13.0 released. See https://github.com/buildpacks/pack/issues/775 - cmd.Flags().BoolVar(&flags.NoPull, "no-pull", false, "Skip pulling packages before use") - cmd.Flags().MarkHidden("no-pull") AddHelpFlag(cmd, "package-buildpack") return cmd } -func validatePackageBuildpackFlags(p *PackageBuildpackFlags, logger logging.Logger) error { +func validatePackageBuildpackFlags(p *PackageBuildpackFlags) error { if p.Publish && p.Policy == config.PullNever.String() { return errors.Errorf("--publish and --pull-policy never cannot be used together. The --publish flag requires the use of remote images.") } - if p.Publish && p.NoPull { - return errors.Errorf("The --publish and --no-pull flags cannot be used together. The --publish flag requires the use of remote images.") - } - if p.PackageTomlPath == "" { return errors.Errorf("Please provide a package config path, using --config") } - if p.NoPull { - logger.Warn("Flag --no-pull has been deprecated, please use `--pull-policy never` instead") - - if p.Policy != "" { - logger.Warn("Flag --no-pull ignored in favor of --pull-policy") - } else { - p.Policy = config.PullNever.String() - } - } - return nil } diff --git a/internal/commands/package_buildpack_test.go b/internal/commands/package_buildpack_test.go index d4880d865..a39b6e7bf 100644 --- a/internal/commands/package_buildpack_test.go +++ b/internal/commands/package_buildpack_test.go @@ -81,72 +81,6 @@ func testPackageBuildpackCommand(t *testing.T, when spec.G, it spec.S) { h.AssertEq(t, receivedOptions.Config, myConfig) }) - when("--no-pull", func() { - var ( - outBuf bytes.Buffer - cmd *cobra.Command - args []string - fakeBuildpackPackager *fakes.FakeBuildpackPackager - ) - - it.Before(func() { - logger := logging.NewLogWithWriters(&outBuf, &outBuf) - fakeBuildpackPackager = &fakes.FakeBuildpackPackager{} - - cmd = packageBuildpackCommand(withLogger(logger), withBuildpackPackager(fakeBuildpackPackager)) - args = []string{ - "some-image-name", - "--config", "/path/to/some/file", - } - }) - - it("logs warning and works", func() { - args = append(args, "--no-pull") - cmd.SetArgs(args) - - err := cmd.Execute() - h.AssertContains(t, outBuf.String(), "Warning: Flag --no-pull has been deprecated") - h.AssertNil(t, err) - - receivedOptions := fakeBuildpackPackager.CreateCalledWithOptions - h.AssertEq(t, receivedOptions.PullPolicy, config.PullNever) - }) - - when("used together with --pull-policy always", func() { - it("logs warning and disregards --no-pull", func() { - args = append(args, "--no-pull", "--pull-policy", "always") - cmd.SetArgs(args) - - err := cmd.Execute() - h.AssertNil(t, err) - - output := outBuf.String() - h.AssertContains(t, outBuf.String(), "Warning: Flag --no-pull has been deprecated") - h.AssertContains(t, output, "Flag --no-pull ignored in favor of --pull-policy") - - receivedOptions := fakeBuildpackPackager.CreateCalledWithOptions - h.AssertEq(t, receivedOptions.PullPolicy, config.PullAlways) - }) - }) - - when("used together with --pull-policy never", func() { - it("logs warning and disregards --no-pull", func() { - args = append(args, "--no-pull", "--pull-policy", "never") - cmd.SetArgs(args) - - err := cmd.Execute() - h.AssertNil(t, err) - - output := outBuf.String() - h.AssertContains(t, outBuf.String(), "Warning: Flag --no-pull has been deprecated") - h.AssertContains(t, output, "Flag --no-pull ignored in favor of --pull-policy") - - receivedOptions := fakeBuildpackPackager.CreateCalledWithOptions - h.AssertEq(t, receivedOptions.PullPolicy, config.PullNever) - }) - }) - }) - when("pull-policy", func() { var ( outBuf bytes.Buffer @@ -192,26 +126,6 @@ func testPackageBuildpackCommand(t *testing.T, when spec.G, it spec.S) { }) when("invalid flags", func() { - when("both --publish and --no-pull flags are specified", func() { - it("errors with a descriptive message", func() { - logger := logging.NewLogWithWriters(&bytes.Buffer{}, &bytes.Buffer{}) - configReader := fakes.NewFakePackageConfigReader() - buildpackPackager := &fakes.FakeBuildpackPackager{} - - command := commands.PackageBuildpack(logger, buildpackPackager, configReader) - command.SetArgs([]string{ - "some-image-name", - "--config", "/path/to/some/file", - "--publish", - "--no-pull", - }) - - err := command.Execute() - h.AssertNotNil(t, err) - h.AssertError(t, err, "The --publish and --no-pull flags cannot be used together. The --publish flag requires the use of remote images.") - }) - }) - when("both --publish and --pull-policy never flags are specified", func() { it("errors with a descriptive message", func() { logger := logging.NewLogWithWriters(&bytes.Buffer{}, &bytes.Buffer{}) diff --git a/internal/commands/rebase.go b/internal/commands/rebase.go index 6ca334cfd..0a83d028c 100644 --- a/internal/commands/rebase.go +++ b/internal/commands/rebase.go @@ -14,7 +14,6 @@ import ( func Rebase(logger logging.Logger, cfg config.Config, client PackClient) *cobra.Command { var opts pack.RebaseOptions - var noPull bool var policy string cmd := &cobra.Command{ @@ -25,16 +24,6 @@ func Rebase(logger logging.Logger, cfg config.Config, client PackClient) *cobra. opts.RepoName = args[0] opts.AdditionalMirrors = getMirrors(cfg) - if cmd.Flags().Changed("no-pull") { - logger.Warn("Flag --no-pull has been deprecated, please use `--pull-policy never` instead") - - if cmd.Flags().Changed("pull-policy") { - logger.Warn("Flag --no-pull ignored in favor of --pull-policy") - } else if noPull { - policy = pubcfg.PullNever.String() - } - } - var err error opts.PullPolicy, err = pubcfg.ParsePullPolicy(policy) if err != nil { @@ -52,9 +41,6 @@ func Rebase(logger logging.Logger, cfg config.Config, client PackClient) *cobra. cmd.Flags().BoolVar(&opts.Publish, "publish", false, "Publish to registry") cmd.Flags().StringVar(&opts.RunImage, "run-image", "", "Run image to use for rebasing") cmd.Flags().StringVar(&policy, "pull-policy", "", "Pull policy to use. Accepted values are always, never, and if-not-present. The default is always") - // TODO: Remove --no-pull flag after v0.13.0 released. See https://github.com/buildpacks/pack/issues/775 - cmd.Flags().BoolVar(&noPull, "no-pull", false, "Skip pulling app and run images before use") - cmd.Flags().MarkHidden("no-pull") AddHelpFlag(cmd, "rebase") return cmd diff --git a/internal/commands/rebase_test.go b/internal/commands/rebase_test.go index 2235e0490..4f6c7e8be 100644 --- a/internal/commands/rebase_test.go +++ b/internal/commands/rebase_test.go @@ -93,50 +93,6 @@ func testRebaseCommand(t *testing.T, when spec.G, it spec.S) { h.AssertNil(t, command.Execute()) }) - when("--no-pull", func() { - it("logs warning and works", func() { - opts.PullPolicy = pubcfg.PullNever - mockClient.EXPECT(). - Rebase(gomock.Any(), opts). - Return(nil) - - command.SetArgs([]string{repoName, "--no-pull"}) - h.AssertNil(t, command.Execute()) - h.AssertContains(t, outBuf.String(), "Warning: Flag --no-pull has been deprecated") - }) - - when("used together with --pull-policy always", func() { - it("logs warning and disregards --no-pull", func() { - opts.PullPolicy = pubcfg.PullAlways - mockClient.EXPECT(). - Rebase(gomock.Any(), opts). - Return(nil) - - command.SetArgs([]string{repoName, "--no-pull", "--pull-policy", "always"}) - h.AssertNil(t, command.Execute()) - output := outBuf.String() - h.AssertContains(t, output, "Warning: Flag --no-pull has been deprecated") - h.AssertContains(t, output, "Flag --no-pull ignored in favor of --pull-policy") - }) - }) - - when("used together with --pull-policy never", func() { - it("logs warning and disregards --no-pull", func() { - opts.PullPolicy = pubcfg.PullNever - mockClient.EXPECT(). - Rebase(gomock.Any(), opts). - Return(nil) - - command.SetArgs([]string{repoName, "--no-pull", "--pull-policy", "never"}) - h.AssertNil(t, command.Execute()) - - output := outBuf.String() - h.AssertContains(t, output, "Warning: Flag --no-pull has been deprecated") - h.AssertContains(t, output, "Flag --no-pull ignored in favor of --pull-policy") - }) - }) - }) - when("--pull-policy never", func() { it("works", func() { opts.PullPolicy = pubcfg.PullNever diff --git a/package_buildpack_test.go b/package_buildpack_test.go index 99b8726e6..95feee0fa 100644 --- a/package_buildpack_test.go +++ b/package_buildpack_test.go @@ -197,7 +197,7 @@ func testPackageBuildpack(t *testing.T, when spec.G, it spec.S) { return img } - when("publish=false and no-pull=false", func() { + when("publish=false and pull-policy=always", func() { it("should pull and use local nested package image", func() { shouldFetchNestedPackage(true, config.PullAlways) packageImage := shouldCreateLocalPackage() @@ -223,7 +223,7 @@ func testPackageBuildpack(t *testing.T, when spec.G, it spec.S) { }) }) - when("publish=true and no-pull=false", func() { + when("publish=true and pull-policy=always", func() { it("should use remote nested package image", func() { shouldFetchNestedPackage(false, config.PullAlways) packageImage := shouldCreateRemotePackage() From ad27dad8b8541f341468bb06abcb87a821c2c115 Mon Sep 17 00:00:00 2001 From: anshlykov Date: Mon, 12 Oct 2020 17:48:49 +0300 Subject: [PATCH 04/14] fix comments Signed-off-by: anshlykov --- internal/commands/build_test.go | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/internal/commands/build_test.go b/internal/commands/build_test.go index 41b71eb78..0ce78b1df 100644 --- a/internal/commands/build_test.go +++ b/internal/commands/build_test.go @@ -9,6 +9,8 @@ import ( "reflect" "testing" + pubcfg "github.com/buildpacks/pack/config" + "github.com/golang/mock/gomock" "github.com/heroku/color" "github.com/pkg/errors" @@ -135,6 +137,15 @@ func testBuildCommand(t *testing.T, when spec.G, it spec.S) { }) when("--pull-policy", func() { + it("sets pull-policy=never", func() { + mockClient.EXPECT(). + Build(gomock.Any(), EqBuildOptionsWithPullPolicy(pubcfg.PullNever)). + Return(nil) + + command.SetArgs([]string{"image", "--builder", "my-builder", "--pull-policy", "never"}) + h.AssertNil(t, command.Execute()) + }) + it("returns error for unknown policy", func() { command.SetArgs([]string{"image", "--builder", "my-builder", "--pull-policy", "unknown-policy"}) h.AssertError(t, command.Execute(), "parsing pull policy") @@ -612,6 +623,15 @@ func EqBuildOptionsDefaultProcess(defaultProc string) gomock.Matcher { } } +func EqBuildOptionsWithPullPolicy(policy pubcfg.PullPolicy) gomock.Matcher { + return buildOptionsMatcher{ + description: fmt.Sprintf("PullPolicy=%s", policy), + equals: func(o pack.BuildOptions) bool { + return o.PullPolicy == policy + }, + } +} + func EqBuildOptionsWithNetwork(network string) gomock.Matcher { return buildOptionsMatcher{ description: fmt.Sprintf("Network=%s", network), From cc3a4a217b0c30e2f8422a7d0c9b2021b89878a1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 13 Oct 2020 06:36:05 +0000 Subject: [PATCH 05/14] Bump github.com/onsi/gomega from 1.8.1 to 1.10.3 Bumps [github.com/onsi/gomega](https://github.com/onsi/gomega) from 1.8.1 to 1.10.3. - [Release notes](https://github.com/onsi/gomega/releases) - [Changelog](https://github.com/onsi/gomega/blob/master/CHANGELOG.md) - [Commits](https://github.com/onsi/gomega/compare/v1.8.1...v1.10.3) Signed-off-by: dependabot[bot] --- go.mod | 8 ++------ go.sum | 63 ++++++++++++++++++++++++++++++++++++---------------------- 2 files changed, 41 insertions(+), 30 deletions(-) diff --git a/go.mod b/go.mod index 976de0714..77185a8dc 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,6 @@ require ( github.com/docker/go-connections v0.4.0 github.com/gogo/protobuf v1.3.1 // indirect github.com/golang/mock v1.4.4 - github.com/golang/protobuf v1.3.5 // indirect github.com/google/go-cmp v0.5.2 github.com/google/go-containerregistry v0.0.0-20200313165449-955bf358a3d8 github.com/google/go-github/v30 v30.1.0 @@ -23,8 +22,7 @@ require ( github.com/mattn/go-colorable v0.1.6 // indirect github.com/mitchellh/ioprogress v0.0.0-20180201004757-6a23b12fa88e github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect - github.com/onsi/ginkgo v1.11.0 // indirect - github.com/onsi/gomega v1.8.1 + github.com/onsi/gomega v1.10.3 github.com/opencontainers/image-spec v1.0.1 github.com/opencontainers/runc v0.1.1 // indirect github.com/opencontainers/selinux v1.4.0 // indirect @@ -33,11 +31,9 @@ require ( github.com/sclevine/spec v1.4.0 github.com/sergi/go-diff v1.1.0 // indirect github.com/spf13/cobra v0.0.7 - golang.org/x/crypto v0.0.0-20200311171314-f7b00557c8c4 + golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 golang.org/x/mod v0.3.0 - golang.org/x/net v0.0.0-20200301022130-244492dfa37a // indirect golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 - golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 // indirect golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect google.golang.org/genproto v0.0.0-20200313141609-30c55424f95d // indirect google.golang.org/grpc v1.28.0 // indirect diff --git a/go.sum b/go.sum index 7c0d5491c..ac271db8d 100644 --- a/go.sum +++ b/go.sum @@ -45,11 +45,8 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/apex/log v1.1.2-0.20190827100214-baa5455d1012/go.mod h1:Ls949n1HFtXfbDcjiTTFQqkVUrte0puoIBfO3SVgwOA= -github.com/apex/log v1.1.2 h1:bnDuVoi+o98wOdVqfEzNDlY0tcmBia7r4YkjS9EqGYk= -github.com/apex/log v1.1.2/go.mod h1:SyfRweFO+TlkIJ3DVizTSeI1xk7jOIIqOnUPZQTTsww= github.com/apex/log v1.9.0 h1:FHtw/xuaM8AgmvDDTI9fiwoAL25Sq2cxojnZICUU8l0= github.com/apex/log v1.9.0/go.mod h1:m82fZlWIuiWzWP04XCTXmnX0xRkYYbCdYn8jbJeLBEA= -github.com/apex/logs v0.0.3/go.mod h1:XzxuLZ5myVHDy9SAmYpamKKRNApGj54PfYLcFrXqDwo= github.com/apex/logs v1.0.0/go.mod h1:XzxuLZ5myVHDy9SAmYpamKKRNApGj54PfYLcFrXqDwo= github.com/aphistic/golf v0.0.0-20180712155816-02c07f170c5a/go.mod h1:3NqKYiepwy8kCu4PNA+aP7WUV72eXWJeP9/r3/K9aLE= github.com/aphistic/sweet v0.2.0/go.mod h1:fWDlIh/isSE9n6EPsRmC0det+whmX6dJid3stzu0Xys= @@ -177,8 +174,6 @@ github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1 h1:qGJ6qTW+x6xX/my+8YUVl4WNpX9B7+/l2tRsHGZ7f2s= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/mock v1.4.1 h1:ocYkMQY5RrXTYgXl7ICpV0IXwlEQGwKIsery4gyXa1U= -github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -186,12 +181,19 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.5 h1:F768QJ1E9tib+q5Sc8MkdJi1RxLTbRcTf8LJV56aRls= -github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1 h1:JFrFEBb2xKufg6XkJsJr+WbKb4FQlURi5RUcBveYu9k= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= @@ -306,19 +308,22 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.11.0 h1:JAKSXpt1YjtLA7YpPiqO9ss6sNXEsPfSGdwN0UHqzrw= -github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1 h1:mFwc4LvZ0xpSvDZ3E+k8Yte0hLOMxXUlP+yXtJqkYfQ= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.8.1 h1:C5Dqfs/LeauYDX0jJXIe2SWmwCbGzx9yF8C8xy3Lh34= -github.com/onsi/gomega v1.8.1/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.3 h1:gph6h/qe9GSUw1NhH1gp+qb+h8rXD8Cy60Z32Qw3ELA= +github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc= github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= @@ -390,8 +395,7 @@ github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkU github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= -github.com/spf13/cobra v0.0.6 h1:breEStsVwemnKh2/s6gMvSdMEkwW0sK8vGStnlVBMCs= -github.com/spf13/cobra v0.0.6/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= +github.com/spf13/cobra v0.0.7 h1:FfTH+vuMXOas8jmfb5/M7dzEYx7LpcLb7a0LPe34uOU= github.com/spf13/cobra v0.0.7/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= @@ -412,9 +416,11 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/tj/assert v0.0.0-20171129193455-018094318fb0/go.mod h1:mZ9/Rh9oLWpLLDRpvE+3b7gP/C2YyLFYxNmcLnPTMe0= +github.com/tj/assert v0.0.3 h1:Df/BlaZ20mq6kuai7f5z2TvPFiwC3xaWJSDQNiIS3Rk= github.com/tj/assert v0.0.3/go.mod h1:Ne6X72Q+TB1AteidzQncjw9PabbMp4PBMZ1k+vd1Pvk= github.com/tj/go-buffer v1.1.0/go.mod h1:iyiJpfFcR2B9sXu7KvjbT9fpM4mOelRSDTbntVj52Uc= github.com/tj/go-elastic v0.0.0-20171221160941-36157cbbebc2/go.mod h1:WjeM0Oo1eNAjXGDx2yma7uG2XoyRZTq1uv3M/o7imD0= @@ -459,8 +465,8 @@ golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200311171314-f7b00557c8c4 h1:QmwruyY+bKbDDL0BaglrbZABEali68eoMFhTZpCjYVA= -golang.org/x/crypto v0.0.0-20200311171314-f7b00557c8c4/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190312203227-4b39c73a6495/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -475,8 +481,6 @@ golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee h1:WG0RUwxtNT4qqaXX3DPA8zHFNm/D9xaBpxzHt1WcA/E= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -500,8 +504,8 @@ golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0 h1:wBouT66WTYFXdxfVdz9sVWARVd/2vfGcmI45D2gj45M= +golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0= @@ -534,20 +538,23 @@ golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 h1:uYVVQ9WP/Ds2ROhcaGPeIdVq0RIXVLwsHlnvJ+cT1So= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ= @@ -608,6 +615,13 @@ google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQ google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.28.0 h1:bO/TA4OxCOummhSf10siHuG7vJOiwh7SpRpFZDkOgl4= google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -642,7 +656,10 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c h1:grhR+C34yXImVGp7EzNk+DTIk+323eIUWOmEevy6bDo= gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= @@ -683,8 +700,6 @@ modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs= modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I= -rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= -rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= From 5a9ab1219f5c6dbe4b4700cdb23b8c5471296f0c Mon Sep 17 00:00:00 2001 From: Joe Kutner Date: Wed, 14 Oct 2020 12:54:44 -0500 Subject: [PATCH 06/14] Add support for docker:// URIs and warn about image key Signed-off-by: Joe Kutner --- build.go | 3 +- create_builder.go | 7 ++-- internal/buildpack/locator_type.go | 17 +++++++-- internal/buildpack/locator_type_test.go | 45 +++++++++++++++++++++-- internal/buildpack/parse_name.go | 24 ++++++++++++- package_buildpack.go | 48 +++++++++++++++---------- 6 files changed, 115 insertions(+), 29 deletions(-) diff --git a/build.go b/build.go index 944f7a061..46b75a610 100644 --- a/build.go +++ b/build.go @@ -643,7 +643,8 @@ func (c *Client) processBuildpacks(ctx context.Context, builderImage imgutil.Ima fetchedBPs = append(append(fetchedBPs, mainBP), dependencyBPs...) order = appendBuildpackToOrder(order, mainBP.Descriptor().Info) case buildpack.PackageLocator: - mainBP, depBPs, err := extractPackagedBuildpacks(ctx, bp, c.imageFetcher, publish, pullPolicy) + imageName := buildpack.ParsePackageLocator(bp) + mainBP, depBPs, err := extractPackagedBuildpacks(ctx, imageName, c.imageFetcher, publish, pullPolicy) if err != nil { return fetchedBPs, order, errors.Wrapf(err, "creating from buildpackage %s", style.Symbol(bp)) } diff --git a/create_builder.go b/create_builder.go index 3d2cb786a..9bb35b3aa 100644 --- a/create_builder.go +++ b/create_builder.go @@ -202,6 +202,7 @@ func (c *Client) addBuildpacksToBuilder(ctx context.Context, opts CreateBuilderO locator := b.URI if locator == "" && b.ImageName != "" { + c.logger.Warn("The 'image' key is deprecated. Use 'uri=\"docker://...\"' instead.") locator = b.ImageName } @@ -214,9 +215,9 @@ func (c *Client) addBuildpacksToBuilder(ctx context.Context, opts CreateBuilderO var depBPs []dist.Buildpack switch locatorType { case buildpack.PackageLocator: - c.logger.Debugf("Downloading buildpack from image: %s", style.Symbol(b.ImageName)) - - mainBP, depBPs, err = extractPackagedBuildpacks(ctx, b.ImageName, c.imageFetcher, opts.Publish, opts.PullPolicy) + imageName := buildpack.ParsePackageLocator(locator) + c.logger.Debugf("Downloading buildpack from image: %s", style.Symbol(imageName)) + mainBP, depBPs, err = extractPackagedBuildpacks(ctx, imageName, c.imageFetcher, opts.Publish, opts.PullPolicy) if err != nil { return err } diff --git a/internal/buildpack/locator_type.go b/internal/buildpack/locator_type.go index 407755b4b..9be2afe97 100644 --- a/internal/buildpack/locator_type.go +++ b/internal/buildpack/locator_type.go @@ -23,8 +23,10 @@ const ( RegistryLocator ) -const fromBuilderPrefix = "from=builder" +const fromBuilderPrefix = "urn:cnb:builder" +const deprecatedFromBuilderPrefix = "from=builder" const fromRegistryPrefix = "urn:cnb:registry" +const fromDockerPrefix = "docker:/" func (l LocatorType) String() string { return []string{ @@ -40,11 +42,11 @@ func (l LocatorType) String() string { // If a type cannot be determined, `INVALID_LOCATOR` will be returned. If an error // is encountered, it will be returned. func GetLocatorType(locator string, buildpacksFromBuilder []dist.BuildpackInfo) (LocatorType, error) { - if locator == fromBuilderPrefix { + if locator == deprecatedFromBuilderPrefix { return FromBuilderLocator, nil } - if strings.HasPrefix(locator, fromBuilderPrefix+":") { + if strings.HasPrefix(locator, fromBuilderPrefix+":") || strings.HasPrefix(locator, deprecatedFromBuilderPrefix+":") { if !builderMatchFound(locator, buildpacksFromBuilder) { return InvalidLocator, fmt.Errorf("%s is not a valid identifier", style.Symbol(locator)) } @@ -56,6 +58,11 @@ func GetLocatorType(locator string, buildpacksFromBuilder []dist.BuildpackInfo) } if paths.IsURI(locator) { + if HasDockerLocator(locator) { + if _, err := name.ParseReference(locator); err == nil { + return PackageLocator, nil + } + } return URILocator, nil } @@ -74,6 +81,10 @@ func GetLocatorType(locator string, buildpacksFromBuilder []dist.BuildpackInfo) return InvalidLocator, nil } +func HasDockerLocator(locator string) bool { + return strings.HasPrefix(locator, fromDockerPrefix) +} + func builderMatchFound(locator string, candidates []dist.BuildpackInfo) bool { id, version := ParseIDLocator(locator) for _, c := range candidates { diff --git a/internal/buildpack/locator_type_test.go b/internal/buildpack/locator_type_test.go index 8937b4d01..ca3594720 100644 --- a/internal/buildpack/locator_type_test.go +++ b/internal/buildpack/locator_type_test.go @@ -53,6 +53,21 @@ func testGetLocatorType(t *testing.T, when spec.G, it spec.S) { builderBPs: []dist.BuildpackInfo{{ID: "some-bp", Version: "some-version"}}, expectedErr: "'from=builder:some-bp@some-other-version' is not a valid identifier", }, + { + locator: "urn:cnb:builder:some-bp", + builderBPs: []dist.BuildpackInfo{{ID: "some-bp", Version: "some-version"}}, + expectedType: buildpack.IDLocator, + }, + { + locator: "urn:cnb:builder:some-bp", + builderBPs: nil, + expectedErr: "'urn:cnb:builder:some-bp' is not a valid identifier", + }, + { + locator: "urn:cnb:builder:some-bp@some-other-version", + builderBPs: []dist.BuildpackInfo{{ID: "some-bp", Version: "some-version"}}, + expectedErr: "'urn:cnb:builder:some-bp@some-other-version' is not a valid identifier", + }, { locator: "some-bp", builderBPs: []dist.BuildpackInfo{{ID: "some-bp", Version: "any-version"}}, @@ -69,17 +84,41 @@ func testGetLocatorType(t *testing.T, when spec.G, it spec.S) { expectedType: buildpack.URILocator, }, { - locator: "cnbs/some-bp", + locator: "docker://cnbs/some-bp", builderBPs: nil, localPath: "", expectedType: buildpack.PackageLocator, }, { - locator: "cnbs/some-bp@sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", + locator: "docker://cnbs/some-bp@sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", + expectedType: buildpack.PackageLocator, + }, + { + locator: "docker://cnbs/some-bp:some-tag", + expectedType: buildpack.PackageLocator, + }, + { + locator: "docker://cnbs/some-bp:some-tag@sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", + expectedType: buildpack.PackageLocator, + }, + { + locator: "docker://registry.com/cnbs/some-bp", + expectedType: buildpack.PackageLocator, + }, + { + locator: "docker://registry.com/cnbs/some-bp@sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", expectedType: buildpack.PackageLocator, }, { - locator: "cnbs/some-bp:some-tag", + locator: "docker://registry.com/cnbs/some-bp:some-tag", + expectedType: buildpack.PackageLocator, + }, + { + locator: "docker://registry.com/cnbs/some-bp:some-tag@sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", + expectedType: buildpack.PackageLocator, + }, + { + locator: "cnbs/some-bp@sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", expectedType: buildpack.PackageLocator, }, { diff --git a/internal/buildpack/parse_name.go b/internal/buildpack/parse_name.go index ba058b376..23f543c3b 100644 --- a/internal/buildpack/parse_name.go +++ b/internal/buildpack/parse_name.go @@ -5,10 +5,14 @@ import ( "strings" ) +func ParseLocator(locator string) (id string) { + return ParseRegistryLocator(ParseBuilderLocator(ParsePackageLocator(locator))) +} + // ParseIDLocator parses a buildpack locator of the form @ into its ID and version. // If version is omitted, the version returned will be empty. Any "from=builder:" or "urn:cnb" prefix will be ignored. func ParseIDLocator(locator string) (id string, version string) { - nakedLocator := strings.TrimPrefix(strings.TrimPrefix(locator, fromBuilderPrefix+":"), fromRegistryPrefix+":") + nakedLocator := ParseLocator(locator) parts := strings.Split(nakedLocator, "@") if len(parts) == 2 { @@ -26,3 +30,21 @@ func ParseRegistryID(registryID string) (namespace string, name string, version } return parts[0], "", version, fmt.Errorf("invalid registry ID: %s", registryID) } + +func ParseRegistryLocator(locator string) (path string) { + return strings.TrimPrefix(locator, fromRegistryPrefix+":") +} + +func ParseBuilderLocator(locator string) (path string) { + return strings.TrimPrefix( + strings.TrimPrefix(locator, deprecatedFromBuilderPrefix+":"), + fromBuilderPrefix+":") +} + +func ParsePackageLocator(locator string) (path string) { + return strings.TrimPrefix( + strings.TrimPrefix( + strings.TrimPrefix(locator, fromDockerPrefix+"//"), + fromDockerPrefix+"/"), + fromDockerPrefix) +} diff --git a/package_buildpack.go b/package_buildpack.go index f475c0ff5..dcf2d54f3 100644 --- a/package_buildpack.go +++ b/package_buildpack.go @@ -3,12 +3,12 @@ package pack import ( "context" - "github.com/buildpacks/pack/config" - "github.com/pkg/errors" pubbldpkg "github.com/buildpacks/pack/buildpackage" + "github.com/buildpacks/pack/config" "github.com/buildpacks/pack/internal/archive" + "github.com/buildpacks/pack/internal/buildpack" "github.com/buildpacks/pack/internal/buildpackage" "github.com/buildpacks/pack/internal/dist" "github.com/buildpacks/pack/internal/style" @@ -71,31 +71,43 @@ func (c *Client) PackageBuildpack(ctx context.Context, opts PackageBuildpackOpti var depBPs []dist.Buildpack if dep.URI != "" { - blob, err := c.downloader.Download(ctx, dep.URI) - if err != nil { - return errors.Wrapf(err, "downloading buildpack from %s", style.Symbol(dep.URI)) - } - - isOCILayout, err := buildpackage.IsOCILayoutBlob(blob) - if err != nil { - return errors.Wrap(err, "inspecting buildpack blob") - } - - if isOCILayout { - mainBP, deps, err := buildpackage.BuildpacksFromOCILayoutBlob(blob) + if buildpack.HasDockerLocator(dep.URI) { + imageName := buildpack.ParsePackageLocator(dep.URI) + c.logger.Debugf("Downloading buildpack from image: %s", style.Symbol(imageName)) + mainBP, deps, err := extractPackagedBuildpacks(ctx, imageName, c.imageFetcher, opts.Publish, opts.PullPolicy) if err != nil { - return errors.Wrapf(err, "extracting buildpacks from %s", style.Symbol(dep.URI)) + return err } depBPs = append([]dist.Buildpack{mainBP}, deps...) } else { - depBP, err := dist.BuildpackFromRootBlob(blob, archive.DefaultTarWriterFactory()) + blob, err := c.downloader.Download(ctx, dep.URI) if err != nil { - return errors.Wrapf(err, "creating buildpack from %s", style.Symbol(dep.URI)) + return errors.Wrapf(err, "downloading buildpack from %s", style.Symbol(dep.URI)) + } + + isOCILayout, err := buildpackage.IsOCILayoutBlob(blob) + if err != nil { + return errors.Wrap(err, "inspecting buildpack blob") + } + + if isOCILayout { + mainBP, deps, err := buildpackage.BuildpacksFromOCILayoutBlob(blob) + if err != nil { + return errors.Wrapf(err, "extracting buildpacks from %s", style.Symbol(dep.URI)) + } + + depBPs = append([]dist.Buildpack{mainBP}, deps...) + } else { + depBP, err := dist.BuildpackFromRootBlob(blob, archive.DefaultTarWriterFactory()) + if err != nil { + return errors.Wrapf(err, "creating buildpack from %s", style.Symbol(dep.URI)) + } + depBPs = []dist.Buildpack{depBP} } - depBPs = []dist.Buildpack{depBP} } } else if dep.ImageName != "" { + c.logger.Warn("The 'image' key is deprecated. Use 'uri=\"docker://...\"' instead.") mainBP, deps, err := extractPackagedBuildpacks(ctx, dep.ImageName, c.imageFetcher, opts.Publish, opts.PullPolicy) if err != nil { return err From 85b8d7e362daa4161f1c051b95511a439c85b58b Mon Sep 17 00:00:00 2001 From: Anthony Emengo Date: Wed, 2 Sep 2020 11:00:55 -0400 Subject: [PATCH 07/14] Enable package-buildpack for windows Signed-off-by: Anthony Emengo Signed-off-by: Andrew Meyer Signed-off-by: Victoria Henry --- acceptance/acceptance_test.go | 10 - build.go | 6 +- create_builder.go | 6 +- create_builder_test.go | 13 +- internal/builder/builder.go | 6 +- internal/buildpackage/builder.go | 34 +++- internal/buildpackage/builder_test.go | 271 ++++++++++++++++++-------- internal/layer/writer_factory.go | 11 +- internal/layer/writer_factory_test.go | 20 +- package_buildpack.go | 20 +- package_buildpack_test.go | 7 + 11 files changed, 280 insertions(+), 124 deletions(-) diff --git a/acceptance/acceptance_test.go b/acceptance/acceptance_test.go index d16cffbfe..1d27c6712 100644 --- a/acceptance/acceptance_test.go +++ b/acceptance/acceptance_test.go @@ -1247,10 +1247,6 @@ func testAcceptance( pack.Supports("package-buildpack"), "--buildpack does not accept buildpackage unless package-buildpack is supported", ) - h.SkipIf(t, - dockerHostOS() == "windows", - "These tests are not yet compatible with Windows-based containers", - ) }) it.After(func() { @@ -1297,12 +1293,6 @@ func testAcceptance( var tmpDir string it.Before(func() { - h.SkipIf(t, - !pack.Supports("package-buildpack --format"), - "--buildpack does not accept buildpackage file unless package-buildpack with --format is supported", - ) - h.SkipIf(t, dockerHostOS() == "windows", "These tests are not yet compatible with Windows-based containers") - var err error tmpDir, err = ioutil.TempDir("", "package-file") assert.Nil(err) diff --git a/build.go b/build.go index 944f7a061..91cfd7bfc 100644 --- a/build.go +++ b/build.go @@ -630,7 +630,11 @@ func (c *Client) processBuildpacks(ctx context.Context, builderImage imgutil.Ima return fetchedBPs, order, errors.Wrapf(err, "extracting buildpacks from %s", style.Symbol(bp)) } } else { - layerWriterFactory, err := layer.NewWriterFactory(builderImage) + imageOS, err := builderImage.OS() + if err != nil { + return fetchedBPs, order, errors.Wrap(err, "getting image OS") + } + layerWriterFactory, err := layer.NewWriterFactory(imageOS) if err != nil { return fetchedBPs, order, errors.Wrapf(err, "get tar writer factory for image %s", style.Symbol(builderImage.Name())) } diff --git a/create_builder.go b/create_builder.go index 3d2cb786a..ea4a63653 100644 --- a/create_builder.go +++ b/create_builder.go @@ -261,7 +261,11 @@ func (c *Client) addBuildpacksToBuilder(ctx context.Context, opts CreateBuilderO return errors.Wrapf(err, "extracting buildpacks from %s", style.Symbol(b.ID)) } } else { - layerWriterFactory, err := layer.NewWriterFactory(bldr.Image()) + imageOS, err := bldr.Image().OS() + if err != nil { + return errors.Wrap(err, "getting image OS") + } + layerWriterFactory, err := layer.NewWriterFactory(imageOS) if err != nil { return errors.Wrapf(err, "get tar writer factory for image %s", style.Symbol(bldr.Name())) } diff --git a/create_builder_test.go b/create_builder_test.go index 99241c285..35c676214 100644 --- a/create_builder_test.go +++ b/create_builder_test.go @@ -10,10 +10,9 @@ import ( "runtime" "testing" - "github.com/buildpacks/pack/config" - "github.com/buildpacks/imgutil/fakes" "github.com/buildpacks/lifecycle/api" + "github.com/docker/docker/api/types" "github.com/golang/mock/gomock" "github.com/heroku/color" "github.com/pkg/errors" @@ -23,6 +22,7 @@ import ( "github.com/buildpacks/pack" pubbldr "github.com/buildpacks/pack/builder" pubbldpkg "github.com/buildpacks/pack/buildpackage" + "github.com/buildpacks/pack/config" "github.com/buildpacks/pack/internal/blob" "github.com/buildpacks/pack/internal/builder" cfg "github.com/buildpacks/pack/internal/config" @@ -48,6 +48,7 @@ func testCreateBuilder(t *testing.T, when spec.G, it spec.S) { mockDownloader *testmocks.MockDownloader mockImageFactory *testmocks.MockImageFactory mockImageFetcher *testmocks.MockImageFetcher + mockDockerClient *testmocks.MockCommonAPIClient fakeBuildImage *fakes.Image fakeRunImage *fakes.Image fakeRunImageMirror *fakes.Image @@ -64,6 +65,7 @@ func testCreateBuilder(t *testing.T, when spec.G, it spec.S) { mockDownloader = testmocks.NewMockDownloader(mockController) mockImageFetcher = testmocks.NewMockImageFetcher(mockController) mockImageFactory = testmocks.NewMockImageFactory(mockController) + mockDockerClient = testmocks.NewMockCommonAPIClient(mockController) fakeBuildImage = fakes.NewImage("some/build-image", "", nil) h.AssertNil(t, fakeBuildImage.SetLabel("io.buildpacks.stack.id", "some.stack.id")) @@ -88,9 +90,12 @@ func testCreateBuilder(t *testing.T, when spec.G, it spec.S) { pack.WithDownloader(mockDownloader), pack.WithImageFactory(mockImageFactory), pack.WithFetcher(mockImageFetcher), + pack.WithDockerClient(mockDockerClient), ) h.AssertNil(t, err) + mockDockerClient.EXPECT().Info(context.TODO()).Return(types.Info{OSType: "linux"}, nil).AnyTimes() + opts = pack.CreateBuilderOptions{ BuilderName: "some/builder", Config: pubbldr.Config{ @@ -563,9 +568,9 @@ func testCreateBuilder(t *testing.T, when spec.G, it spec.S) { bldr := successfullyCreateBuilder() h.AssertEq(t, bldr.LifecycleDescriptor().Info.Version.String(), "0.0.0") - //nolint:staticcheck + // nolint:staticcheck h.AssertEq(t, bldr.LifecycleDescriptor().API.BuildpackVersion.String(), "0.2") - //nolint:staticcheck + // nolint:staticcheck h.AssertEq(t, bldr.LifecycleDescriptor().API.PlatformVersion.String(), "0.2") h.AssertEq(t, bldr.LifecycleDescriptor().APIs.Buildpack.Deprecated.AsStrings(), []string{}) h.AssertEq(t, bldr.LifecycleDescriptor().APIs.Buildpack.Supported.AsStrings(), []string{"0.2", "0.3", "0.4"}) diff --git a/internal/builder/builder.go b/internal/builder/builder.go index 2afbbc863..c73bd7628 100644 --- a/internal/builder/builder.go +++ b/internal/builder/builder.go @@ -89,7 +89,11 @@ func New(baseImage imgutil.Image, name string) (*Builder, error) { } func constructBuilder(img imgutil.Image, newName string, metadata Metadata) (*Builder, error) { - layerWriterFactory, err := layer.NewWriterFactory(img) + imageOS, err := img.OS() + if err != nil { + return nil, errors.Wrap(err, "getting image OS") + } + layerWriterFactory, err := layer.NewWriterFactory(imageOS) if err != nil { return nil, err } diff --git a/internal/buildpackage/builder.go b/internal/buildpackage/builder.go index 43bddb19e..2b10c19f0 100644 --- a/internal/buildpackage/builder.go +++ b/internal/buildpackage/builder.go @@ -3,6 +3,7 @@ package buildpackage import ( "archive/tar" "compress/gzip" + "context" "io/ioutil" "os" @@ -14,16 +15,23 @@ import ( "github.com/google/go-containerregistry/pkg/v1/tarball" "github.com/pkg/errors" + pubcfg "github.com/buildpacks/pack/config" "github.com/buildpacks/pack/internal/archive" "github.com/buildpacks/pack/internal/dist" "github.com/buildpacks/pack/internal/stack" "github.com/buildpacks/pack/internal/style" ) +const windowsPackageBase = "mcr.microsoft.com/windows/nanoserver:1809-amd64" // TODO: Should this be hard-coded? + type ImageFactory interface { NewImage(repoName string, local bool) (imgutil.Image, error) } +type ImageFetcher interface { + Fetch(ctx context.Context, name string, daemon bool, pullPolicy pubcfg.PullPolicy) (imgutil.Image, error) +} + type WorkableImage interface { SetLabel(string, string) error AddLayerWithDiffID(path, diffID string) error @@ -62,12 +70,16 @@ func (i *layoutImage) AddLayerWithDiffID(path, _ string) error { type PackageBuilder struct { buildpack dist.Buildpack dependencies []dist.Buildpack + imageOS string imageFactory ImageFactory + imageFetcher ImageFetcher } -func NewBuilder(imageFactory ImageFactory) *PackageBuilder { +func NewBuilder(imageOS string, imageFactory ImageFactory, imageFetcher ImageFetcher) *PackageBuilder { return &PackageBuilder{ + imageOS: imageOS, imageFactory: imageFactory, + imageFetcher: imageFetcher, } } @@ -192,14 +204,26 @@ func (b *PackageBuilder) SaveAsFile(path string) error { return archive.WriteDirToTar(tw, layoutDir, "/", 0, 0, 0755, true, nil) } -func (b *PackageBuilder) SaveAsImage(repoName string, publish bool) (imgutil.Image, error) { +func (b *PackageBuilder) SaveAsImage(ctx context.Context, repoName string, publish bool, pullPolicy pubcfg.PullPolicy) (imgutil.Image, error) { if err := b.validate(); err != nil { return nil, err } - image, err := b.imageFactory.NewImage(repoName, !publish) - if err != nil { - return nil, errors.Wrapf(err, "creating image") + var ( + image imgutil.Image + err error + ) + if b.imageOS == "windows" { + image, err = b.imageFetcher.Fetch(ctx, windowsPackageBase, !publish, pullPolicy) + if err != nil { + return nil, errors.Wrapf(err, "fetching base image") + } + image.Rename(repoName) + } else { + image, err = b.imageFactory.NewImage(repoName, !publish) + if err != nil { + return nil, errors.Wrapf(err, "creating image") + } } tmpDir, err := ioutil.TempDir("", "package-buildpack") diff --git a/internal/buildpackage/builder_test.go b/internal/buildpackage/builder_test.go index a7b5dbe4c..1d3d58017 100644 --- a/internal/buildpackage/builder_test.go +++ b/internal/buildpackage/builder_test.go @@ -3,6 +3,7 @@ package buildpackage_test import ( "archive/tar" "compress/gzip" + "context" "encoding/json" "fmt" "io" @@ -21,6 +22,7 @@ import ( "github.com/sclevine/spec" "github.com/sclevine/spec/report" + "github.com/buildpacks/pack/config" "github.com/buildpacks/pack/internal/buildpackage" "github.com/buildpacks/pack/internal/dist" ifakes "github.com/buildpacks/pack/internal/fakes" @@ -36,7 +38,6 @@ func TestPackageBuilder(t *testing.T) { func testPackageBuilder(t *testing.T, when spec.G, it spec.S) { var ( - fakePackageImage *fakes.Image mockController *gomock.Controller mockImageFactory *testmocks.MockImageFactory subject *buildpackage.PackageBuilder @@ -47,10 +48,10 @@ func testPackageBuilder(t *testing.T, when spec.G, it spec.S) { mockController = gomock.NewController(t) mockImageFactory = testmocks.NewMockImageFactory(mockController) - fakePackageImage = fakes.NewImage("some/package", "", nil) + fakePackageImage := fakes.NewImage("some/package", "", nil) mockImageFactory.EXPECT().NewImage("some/package", true).Return(fakePackageImage, nil).AnyTimes() - subject = buildpackage.NewBuilder(mockImageFactory) + subject = buildpackage.NewBuilder("linux", mockImageFactory, nil) var err error tmpDir, err = ioutil.TempDir("", "package_builder_tests") @@ -68,7 +69,7 @@ func testPackageBuilder(t *testing.T, when spec.G, it spec.S) { fn func() error }{ {name: "SaveAsImage", fn: func() error { - _, err := subject.SaveAsImage(fakePackageImage.Name(), false) + _, err := subject.SaveAsImage(context.TODO(), "some/package", false, config.PullAlways) return err }}, {name: "SaveAsFile", fn: func() error { @@ -269,7 +270,7 @@ func testPackageBuilder(t *testing.T, when spec.G, it spec.S) { h.AssertNil(t, err) subject.AddDependency(dependency2) - _, err = subject.SaveAsImage("some/package", false) + _, err = subject.SaveAsImage(context.TODO(), "some/package", false, config.PullAlways) h.AssertError(t, err, "no compatible stacks among provided buildpacks") }) }) @@ -324,7 +325,7 @@ func testPackageBuilder(t *testing.T, when spec.G, it spec.S) { h.AssertNil(t, err) subject.AddDependency(dependency2) - img, err := subject.SaveAsImage("some/package", false) + img, err := subject.SaveAsImage(context.TODO(), "some/package", false, config.PullAlways) h.AssertNil(t, err) metadata := buildpackage.Metadata{} @@ -388,7 +389,7 @@ func testPackageBuilder(t *testing.T, when spec.G, it spec.S) { subject.AddDependency(dependencyNestedNested) - img, err := subject.SaveAsImage("some/package", false) + img, err := subject.SaveAsImage(context.TODO(), "some/package", false, config.PullAlways) h.AssertNil(t, err) metadata := buildpackage.Metadata{} @@ -404,97 +405,203 @@ func testPackageBuilder(t *testing.T, when spec.G, it spec.S) { }) when("#SaveAsImage", func() { - it("sets metadata", func() { - buildpack1, err := ifakes.NewFakeBuildpack(dist.BuildpackDescriptor{ - API: api.MustParse("0.2"), - Info: dist.BuildpackInfo{ - ID: "bp.1.id", - Version: "bp.1.version", - }, - Stacks: []dist.Stack{ - {ID: "stack.id.1"}, - {ID: "stack.id.2"}, - }, - Order: nil, - }, 0644) - h.AssertNil(t, err) + when("creating linux package", func() { + it("sets metadata", func() { + buildpack1, err := ifakes.NewFakeBuildpack(dist.BuildpackDescriptor{ + API: api.MustParse("0.2"), + Info: dist.BuildpackInfo{ + ID: "bp.1.id", + Version: "bp.1.version", + }, + Stacks: []dist.Stack{ + {ID: "stack.id.1"}, + {ID: "stack.id.2"}, + }, + Order: nil, + }, 0644) + h.AssertNil(t, err) - subject.SetBuildpack(buildpack1) + subject.SetBuildpack(buildpack1) - packageImage, err := subject.SaveAsImage(fakePackageImage.Name(), false) - h.AssertNil(t, err) + packageImage, err := subject.SaveAsImage(context.TODO(), "some/package", false, config.PullAlways) + h.AssertNil(t, err) - labelData, err := packageImage.Label("io.buildpacks.buildpackage.metadata") - h.AssertNil(t, err) - var md buildpackage.Metadata - h.AssertNil(t, json.Unmarshal([]byte(labelData), &md)) - - h.AssertEq(t, md.ID, "bp.1.id") - h.AssertEq(t, md.Version, "bp.1.version") - h.AssertEq(t, len(md.Stacks), 2) - h.AssertEq(t, md.Stacks[0].ID, "stack.id.1") - h.AssertEq(t, md.Stacks[1].ID, "stack.id.2") - }) + labelData, err := packageImage.Label("io.buildpacks.buildpackage.metadata") + h.AssertNil(t, err) + var md buildpackage.Metadata + h.AssertNil(t, json.Unmarshal([]byte(labelData), &md)) + + h.AssertEq(t, md.ID, "bp.1.id") + h.AssertEq(t, md.Version, "bp.1.version") + h.AssertEq(t, len(md.Stacks), 2) + h.AssertEq(t, md.Stacks[0].ID, "stack.id.1") + h.AssertEq(t, md.Stacks[1].ID, "stack.id.2") + }) - it("sets buildpack layers label", func() { - buildpack1, err := ifakes.NewFakeBuildpack(dist.BuildpackDescriptor{ - API: api.MustParse("0.2"), - Info: dist.BuildpackInfo{ID: "bp.1.id", Version: "bp.1.version"}, - Stacks: []dist.Stack{{ID: "stack.id.1"}, {ID: "stack.id.2"}}, - Order: nil, - }, 0644) - h.AssertNil(t, err) - subject.SetBuildpack(buildpack1) + it("sets buildpack layers label", func() { + buildpack1, err := ifakes.NewFakeBuildpack(dist.BuildpackDescriptor{ + API: api.MustParse("0.2"), + Info: dist.BuildpackInfo{ID: "bp.1.id", Version: "bp.1.version"}, + Stacks: []dist.Stack{{ID: "stack.id.1"}, {ID: "stack.id.2"}}, + Order: nil, + }, 0644) + h.AssertNil(t, err) + subject.SetBuildpack(buildpack1) - _, err = subject.SaveAsImage(fakePackageImage.Name(), false) - h.AssertNil(t, err) + packageImage, err := subject.SaveAsImage(context.TODO(), "some/package", false, config.PullAlways) + h.AssertNil(t, err) - var bpLayers dist.BuildpackLayers - _, err = dist.GetLabel(fakePackageImage, "io.buildpacks.buildpack.layers", &bpLayers) - h.AssertNil(t, err) + var bpLayers dist.BuildpackLayers + _, err = dist.GetLabel(packageImage, "io.buildpacks.buildpack.layers", &bpLayers) + h.AssertNil(t, err) + + bp1Info, ok1 := bpLayers["bp.1.id"]["bp.1.version"] + h.AssertEq(t, ok1, true) + h.AssertEq(t, bp1Info.Stacks, []dist.Stack{{ID: "stack.id.1"}, {ID: "stack.id.2"}}) + }) + + it("adds buildpack layers", func() { + buildpack1, err := ifakes.NewFakeBuildpack(dist.BuildpackDescriptor{ + API: api.MustParse("0.2"), + Info: dist.BuildpackInfo{ID: "bp.1.id", Version: "bp.1.version"}, + Stacks: []dist.Stack{{ID: "stack.id.1"}, {ID: "stack.id.2"}}, + Order: nil, + }, 0644) + h.AssertNil(t, err) + subject.SetBuildpack(buildpack1) + + packageImage, err := subject.SaveAsImage(context.TODO(), "some/package", false, config.PullAlways) + h.AssertNil(t, err) + + buildpackExists := func(name, version string) { + t.Helper() + dirPath := fmt.Sprintf("/cnb/buildpacks/%s/%s", name, version) + fakePackageImage := packageImage.(*fakes.Image) + layerTar, err := fakePackageImage.FindLayerWithPath(dirPath) + h.AssertNil(t, err) + + h.AssertOnTarEntry(t, layerTar, dirPath, + h.IsDirectory(), + ) + + h.AssertOnTarEntry(t, layerTar, dirPath+"/bin/build", + h.ContentEquals("build-contents"), + h.HasOwnerAndGroup(0, 0), + h.HasFileMode(0644), + ) - bp1Info, ok1 := bpLayers["bp.1.id"]["bp.1.version"] - h.AssertEq(t, ok1, true) - h.AssertEq(t, bp1Info.Stacks, []dist.Stack{{ID: "stack.id.1"}, {ID: "stack.id.2"}}) + h.AssertOnTarEntry(t, layerTar, dirPath+"/bin/detect", + h.ContentEquals("detect-contents"), + h.HasOwnerAndGroup(0, 0), + h.HasFileMode(0644), + ) + } + + buildpackExists("bp.1.id", "bp.1.version") + }) }) - it("adds buildpack layers", func() { - buildpack1, err := ifakes.NewFakeBuildpack(dist.BuildpackDescriptor{ - API: api.MustParse("0.2"), - Info: dist.BuildpackInfo{ID: "bp.1.id", Version: "bp.1.version"}, - Stacks: []dist.Stack{{ID: "stack.id.1"}, {ID: "stack.id.2"}}, - Order: nil, - }, 0644) - h.AssertNil(t, err) - subject.SetBuildpack(buildpack1) + when("creating windows package", func() { + it.Before(func() { + mockImageFetcher := testmocks.NewMockImageFetcher(mockController) + subject = buildpackage.NewBuilder("windows", nil, mockImageFetcher) + fakeBaseImage := fakes.NewImage("", "", nil) + mockImageFetcher.EXPECT().Fetch(context.TODO(), "mcr.microsoft.com/windows/nanoserver:1809-amd64", gomock.Any(), gomock.Any()).Return(fakeBaseImage, nil) + }) - _, err = subject.SaveAsImage(fakePackageImage.Name(), false) - h.AssertNil(t, err) + it("sets metadata", func() { + buildpack1, err := ifakes.NewFakeBuildpack(dist.BuildpackDescriptor{ + API: api.MustParse("0.2"), + Info: dist.BuildpackInfo{ + ID: "bp.1.id", + Version: "bp.1.version", + }, + Stacks: []dist.Stack{ + {ID: "stack.id.1"}, + {ID: "stack.id.2"}, + }, + Order: nil, + }, 0644) + h.AssertNil(t, err) + + subject.SetBuildpack(buildpack1) - buildpackExists := func(name, version string) { - t.Helper() - dirPath := fmt.Sprintf("/cnb/buildpacks/%s/%s", name, version) - layerTar, err := fakePackageImage.FindLayerWithPath(dirPath) + packageImage, err := subject.SaveAsImage(context.TODO(), "some/package", false, config.PullAlways) h.AssertNil(t, err) - h.AssertOnTarEntry(t, layerTar, dirPath, - h.IsDirectory(), - ) + labelData, err := packageImage.Label("io.buildpacks.buildpackage.metadata") + h.AssertNil(t, err) + var md buildpackage.Metadata + h.AssertNil(t, json.Unmarshal([]byte(labelData), &md)) + + h.AssertEq(t, md.ID, "bp.1.id") + h.AssertEq(t, md.Version, "bp.1.version") + h.AssertEq(t, len(md.Stacks), 2) + h.AssertEq(t, md.Stacks[0].ID, "stack.id.1") + h.AssertEq(t, md.Stacks[1].ID, "stack.id.2") + }) - h.AssertOnTarEntry(t, layerTar, dirPath+"/bin/build", - h.ContentEquals("build-contents"), - h.HasOwnerAndGroup(0, 0), - h.HasFileMode(0644), - ) + it("sets buildpack layers label", func() { + buildpack1, err := ifakes.NewFakeBuildpack(dist.BuildpackDescriptor{ + API: api.MustParse("0.2"), + Info: dist.BuildpackInfo{ID: "bp.1.id", Version: "bp.1.version"}, + Stacks: []dist.Stack{{ID: "stack.id.1"}, {ID: "stack.id.2"}}, + Order: nil, + }, 0644) + h.AssertNil(t, err) + subject.SetBuildpack(buildpack1) - h.AssertOnTarEntry(t, layerTar, dirPath+"/bin/detect", - h.ContentEquals("detect-contents"), - h.HasOwnerAndGroup(0, 0), - h.HasFileMode(0644), - ) - } + image, err := subject.SaveAsImage(context.TODO(), "some/package", false, config.PullAlways) + h.AssertNil(t, err) + + var bpLayers dist.BuildpackLayers + _, err = dist.GetLabel(image, "io.buildpacks.buildpack.layers", &bpLayers) + h.AssertNil(t, err) + + bp1Info, ok1 := bpLayers["bp.1.id"]["bp.1.version"] + h.AssertEq(t, ok1, true) + h.AssertEq(t, bp1Info.Stacks, []dist.Stack{{ID: "stack.id.1"}, {ID: "stack.id.2"}}) + }) + + it("adds buildpack layers", func() { + buildpack1, err := ifakes.NewFakeBuildpack(dist.BuildpackDescriptor{ + API: api.MustParse("0.2"), + Info: dist.BuildpackInfo{ID: "bp.1.id", Version: "bp.1.version"}, + Stacks: []dist.Stack{{ID: "stack.id.1"}, {ID: "stack.id.2"}}, + Order: nil, + }, 0644) + h.AssertNil(t, err) + subject.SetBuildpack(buildpack1) + + packageImage, err := subject.SaveAsImage(context.TODO(), "some/package", false, config.PullAlways) + h.AssertNil(t, err) + + buildpackExists := func(name, version string) { + t.Helper() + dirPath := fmt.Sprintf("/cnb/buildpacks/%s/%s", name, version) + fakePackageImage := packageImage.(*fakes.Image) + layerTar, err := fakePackageImage.FindLayerWithPath(dirPath) + h.AssertNil(t, err) + + h.AssertOnTarEntry(t, layerTar, dirPath, + h.IsDirectory(), + ) + + h.AssertOnTarEntry(t, layerTar, dirPath+"/bin/build", + h.ContentEquals("build-contents"), + h.HasOwnerAndGroup(0, 0), + h.HasFileMode(0644), + ) - buildpackExists("bp.1.id", "bp.1.version") + h.AssertOnTarEntry(t, layerTar, dirPath+"/bin/detect", + h.ContentEquals("detect-contents"), + h.HasOwnerAndGroup(0, 0), + h.HasFileMode(0644), + ) + } + + buildpackExists("bp.1.id", "bp.1.version") + }) }) }) diff --git a/internal/layer/writer_factory.go b/internal/layer/writer_factory.go index 4faa11653..72d9c8694 100644 --- a/internal/layer/writer_factory.go +++ b/internal/layer/writer_factory.go @@ -2,9 +2,9 @@ package layer import ( "archive/tar" + "fmt" "io" - "github.com/buildpacks/imgutil" ilayer "github.com/buildpacks/imgutil/layer" "github.com/buildpacks/pack/internal/archive" @@ -14,13 +14,12 @@ type WriterFactory struct { os string } -func NewWriterFactory(image imgutil.Image) (*WriterFactory, error) { - os, err := image.OS() - if err != nil { - return nil, err +func NewWriterFactory(imageOS string) (*WriterFactory, error) { + if imageOS != "linux" && imageOS != "windows" { + return nil, fmt.Errorf("provided image OS '%s' must be either 'linux' or 'windows'", imageOS) } - return &WriterFactory{os: os}, nil + return &WriterFactory{os: imageOS}, nil } func (f *WriterFactory) NewWriter(fileWriter io.Writer) archive.TarWriter { diff --git a/internal/layer/writer_factory_test.go b/internal/layer/writer_factory_test.go index df1074702..af9c5cfc5 100644 --- a/internal/layer/writer_factory_test.go +++ b/internal/layer/writer_factory_test.go @@ -4,7 +4,6 @@ import ( "archive/tar" "testing" - "github.com/buildpacks/imgutil/fakes" ilayer "github.com/buildpacks/imgutil/layer" "github.com/sclevine/spec" "github.com/sclevine/spec/report" @@ -18,11 +17,16 @@ func TestTarWriterFactory(t *testing.T) { } func testWriterFactory(t *testing.T, when spec.G, it spec.S) { + when("#NewWriterFactory", func() { + it("returns an error for invalid image OS", func() { + _, err := layer.NewWriterFactory("not-an-os") + h.AssertError(t, err, "provided image OS 'not-an-os' must be either 'linux' or 'windows'") + }) + }) + when("#NewWriter", func() { - it("returns a regular tar writer for posix-based images", func() { - image := fakes.NewImage("fake-image", "", nil) - image.SetPlatform("linux", "", "") - factory, err := layer.NewWriterFactory(image) + it("returns a regular tar writer for Linux", func() { + factory, err := layer.NewWriterFactory("linux") h.AssertNil(t, err) _, ok := factory.NewWriter(nil).(*tar.Writer) @@ -31,10 +35,8 @@ func testWriterFactory(t *testing.T, when spec.G, it spec.S) { } }) - it("returns a Windows layer writer for Windows-based images", func() { - image := fakes.NewImage("fake-image", "", nil) - image.SetPlatform("windows", "", "") - factory, err := layer.NewWriterFactory(image) + it("returns a Windows layer writer for Windows", func() { + factory, err := layer.NewWriterFactory("windows") h.AssertNil(t, err) _, ok := factory.NewWriter(nil).(*ilayer.WindowsWriter) diff --git a/package_buildpack.go b/package_buildpack.go index f475c0ff5..114b0c36b 100644 --- a/package_buildpack.go +++ b/package_buildpack.go @@ -4,11 +4,11 @@ import ( "context" "github.com/buildpacks/pack/config" + "github.com/buildpacks/pack/internal/layer" "github.com/pkg/errors" pubbldpkg "github.com/buildpacks/pack/buildpackage" - "github.com/buildpacks/pack/internal/archive" "github.com/buildpacks/pack/internal/buildpackage" "github.com/buildpacks/pack/internal/dist" "github.com/buildpacks/pack/internal/style" @@ -44,7 +44,17 @@ type PackageBuildpackOptions struct { // PackageBuildpack packages buildpack(s) into either an image or file. func (c *Client) PackageBuildpack(ctx context.Context, opts PackageBuildpackOptions) error { - packageBuilder := buildpackage.NewBuilder(c.imageFactory) + info, err := c.docker.Info(ctx) + if err != nil { + return errors.Wrap(err, "getting docker info") + } + + writerFactory, err := layer.NewWriterFactory(info.OSType) + if err != nil { + return errors.Wrap(err, "creating layer writer factory") + } + + packageBuilder := buildpackage.NewBuilder(info.OSType, c.imageFactory, c.imageFetcher) if opts.Format == "" { opts.Format = FormatImage @@ -60,7 +70,7 @@ func (c *Client) PackageBuildpack(ctx context.Context, opts PackageBuildpackOpti return errors.Wrapf(err, "downloading buildpack from %s", style.Symbol(bpURI)) } - bp, err := dist.BuildpackFromRootBlob(blob, archive.DefaultTarWriterFactory()) + bp, err := dist.BuildpackFromRootBlob(blob, writerFactory) if err != nil { return errors.Wrapf(err, "creating buildpack from %s", style.Symbol(bpURI)) } @@ -89,7 +99,7 @@ func (c *Client) PackageBuildpack(ctx context.Context, opts PackageBuildpackOpti depBPs = append([]dist.Buildpack{mainBP}, deps...) } else { - depBP, err := dist.BuildpackFromRootBlob(blob, archive.DefaultTarWriterFactory()) + depBP, err := dist.BuildpackFromRootBlob(blob, writerFactory) if err != nil { return errors.Wrapf(err, "creating buildpack from %s", style.Symbol(dep.URI)) } @@ -113,7 +123,7 @@ func (c *Client) PackageBuildpack(ctx context.Context, opts PackageBuildpackOpti case FormatFile: return packageBuilder.SaveAsFile(opts.Name) case FormatImage: - _, err = packageBuilder.SaveAsImage(opts.Name, opts.Publish) + _, err = packageBuilder.SaveAsImage(ctx, opts.Name, opts.Publish, opts.PullPolicy) return errors.Wrapf(err, "saving image") default: return errors.Errorf("unknown format: %s", style.Symbol(opts.Format)) diff --git a/package_buildpack_test.go b/package_buildpack_test.go index 99b8726e6..8c634b682 100644 --- a/package_buildpack_test.go +++ b/package_buildpack_test.go @@ -9,6 +9,8 @@ import ( "path/filepath" "testing" + "github.com/docker/docker/api/types" + "github.com/buildpacks/pack/config" "github.com/buildpacks/imgutil" @@ -44,6 +46,7 @@ func testPackageBuildpack(t *testing.T, when spec.G, it spec.S) { mockDownloader *testmocks.MockDownloader mockImageFactory *testmocks.MockImageFactory mockImageFetcher *testmocks.MockImageFetcher + mockDockerClient *testmocks.MockCommonAPIClient out bytes.Buffer ) @@ -52,6 +55,7 @@ func testPackageBuildpack(t *testing.T, when spec.G, it spec.S) { mockDownloader = testmocks.NewMockDownloader(mockController) mockImageFactory = testmocks.NewMockImageFactory(mockController) mockImageFetcher = testmocks.NewMockImageFetcher(mockController) + mockDockerClient = testmocks.NewMockCommonAPIClient(mockController) var err error subject, err = pack.NewClient( @@ -59,8 +63,11 @@ func testPackageBuildpack(t *testing.T, when spec.G, it spec.S) { pack.WithDownloader(mockDownloader), pack.WithImageFactory(mockImageFactory), pack.WithFetcher(mockImageFetcher), + pack.WithDockerClient(mockDockerClient), ) h.AssertNil(t, err) + + mockDockerClient.EXPECT().Info(context.TODO()).Return(types.Info{OSType: "linux"}, nil).AnyTimes() }) it.After(func() { From b592d4b88546a1f9c4a74b2938b5c755edaad524 Mon Sep 17 00:00:00 2001 From: Micah Young Date: Tue, 6 Oct 2020 17:10:18 -0400 Subject: [PATCH 08/14] Refactors Windows package-buildpack to use baselayer shim Signed-off-by: Micah Young --- acceptance/acceptance_test.go | 2 - build_test.go | 4 +- create_builder_test.go | 12 +- go.mod | 2 +- go.sum | 22 +- internal/build/phase_config_provider_test.go | 6 +- internal/buildpackage/builder.go | 103 ++++-- internal/buildpackage/builder_test.go | 363 +++++++++---------- package_buildpack.go | 6 +- 9 files changed, 258 insertions(+), 262 deletions(-) diff --git a/acceptance/acceptance_test.go b/acceptance/acceptance_test.go index 1d27c6712..b188393ad 100644 --- a/acceptance/acceptance_test.go +++ b/acceptance/acceptance_test.go @@ -240,8 +240,6 @@ func testWithoutSpecificBuilderRequirement( "pack does not support 'package-buildpack'", ) - h.SkipIf(t, dockerHostOS() == "windows", "These tests are not yet compatible with Windows-based containers") - var err error tmpDir, err = ioutil.TempDir("", "package-buildpack-tests") assert.Nil(err) diff --git a/build_test.go b/build_test.go index b71602828..25afcd4e0 100644 --- a/build_test.go +++ b/build_test.go @@ -2253,7 +2253,9 @@ func newWindowsImage(name, topLayerSha string, identifier imgutil.Identifier) *f result := fakes.NewImage(name, topLayerSha, identifier) arch, _ := result.Architecture() osVersion, _ := result.OSVersion() - result.SetPlatform("windows", osVersion, arch) + result.SetOS("windows") + result.SetOSVersion(osVersion) + result.SetArchitecture(arch) return result } diff --git a/create_builder_test.go b/create_builder_test.go index 35c676214..46f002de4 100644 --- a/create_builder_test.go +++ b/create_builder_test.go @@ -350,7 +350,7 @@ func testCreateBuilder(t *testing.T, when spec.G, it spec.S) { prepareFetcherWithRunImages() - fakeBuildImage.SetPlatform("windows", "0123", "amd64") + h.AssertNil(t, fakeBuildImage.SetOS("windows")) mockImageFetcher.EXPECT().Fetch(gomock.Any(), "some/build-image", true, config.PullAlways).Return(fakeBuildImage, nil) err = packClientWithExperimental.CreateBuilder(context.TODO(), opts) @@ -362,7 +362,7 @@ func testCreateBuilder(t *testing.T, when spec.G, it spec.S) { it("fails", func() { prepareFetcherWithRunImages() - fakeBuildImage.SetPlatform("windows", "0123", "amd64") + h.AssertNil(t, fakeBuildImage.SetOS("windows")) mockImageFetcher.EXPECT().Fetch(gomock.Any(), "some/build-image", true, config.PullAlways).Return(fakeBuildImage, nil) err := subject.CreateBuilder(context.TODO(), opts) @@ -429,7 +429,7 @@ func testCreateBuilder(t *testing.T, when spec.G, it spec.S) { prepareFetcherWithRunImages() opts.Config.Lifecycle.URI = "" opts.Config.Lifecycle.Version = "3.4.5" - fakeBuildImage.SetPlatform("windows", "0123", "amd64") + h.AssertNil(t, fakeBuildImage.SetOS("windows")) mockDownloader.EXPECT().Download( gomock.Any(), @@ -481,7 +481,7 @@ func testCreateBuilder(t *testing.T, when spec.G, it spec.S) { prepareFetcherWithRunImages() opts.Config.Lifecycle.URI = "" opts.Config.Lifecycle.Version = "" - fakeBuildImage.SetPlatform("windows", "0123", "amd64") + h.AssertNil(t, fakeBuildImage.SetOS("windows")) mockDownloader.EXPECT().Download( gomock.Any(), @@ -568,9 +568,9 @@ func testCreateBuilder(t *testing.T, when spec.G, it spec.S) { bldr := successfullyCreateBuilder() h.AssertEq(t, bldr.LifecycleDescriptor().Info.Version.String(), "0.0.0") - // nolint:staticcheck + //nolint:staticcheck h.AssertEq(t, bldr.LifecycleDescriptor().API.BuildpackVersion.String(), "0.2") - // nolint:staticcheck + //nolint:staticcheck h.AssertEq(t, bldr.LifecycleDescriptor().API.PlatformVersion.String(), "0.2") h.AssertEq(t, bldr.LifecycleDescriptor().APIs.Buildpack.Deprecated.AsStrings(), []string{}) h.AssertEq(t, bldr.LifecycleDescriptor().APIs.Buildpack.Supported.AsStrings(), []string{"0.2", "0.3", "0.4"}) diff --git a/go.mod b/go.mod index 976de0714..252dec09e 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ require ( github.com/Masterminds/semver v1.5.0 github.com/Microsoft/hcsshim v0.8.7 // indirect github.com/apex/log v1.9.0 - github.com/buildpacks/imgutil v0.0.0-20200805143852-1844b230530d + github.com/buildpacks/imgutil v0.0.0-20201015202701-6dd3ca364074 github.com/buildpacks/lifecycle v0.7.2 github.com/containerd/containerd v1.3.3 // indirect github.com/containerd/continuity v0.0.0-20200107194136-26c1120b8d41 // indirect diff --git a/go.sum b/go.sum index 7c0d5491c..30707cb5a 100644 --- a/go.sum +++ b/go.sum @@ -45,11 +45,8 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/apex/log v1.1.2-0.20190827100214-baa5455d1012/go.mod h1:Ls949n1HFtXfbDcjiTTFQqkVUrte0puoIBfO3SVgwOA= -github.com/apex/log v1.1.2 h1:bnDuVoi+o98wOdVqfEzNDlY0tcmBia7r4YkjS9EqGYk= -github.com/apex/log v1.1.2/go.mod h1:SyfRweFO+TlkIJ3DVizTSeI1xk7jOIIqOnUPZQTTsww= github.com/apex/log v1.9.0 h1:FHtw/xuaM8AgmvDDTI9fiwoAL25Sq2cxojnZICUU8l0= github.com/apex/log v1.9.0/go.mod h1:m82fZlWIuiWzWP04XCTXmnX0xRkYYbCdYn8jbJeLBEA= -github.com/apex/logs v0.0.3/go.mod h1:XzxuLZ5myVHDy9SAmYpamKKRNApGj54PfYLcFrXqDwo= github.com/apex/logs v1.0.0/go.mod h1:XzxuLZ5myVHDy9SAmYpamKKRNApGj54PfYLcFrXqDwo= github.com/aphistic/golf v0.0.0-20180712155816-02c07f170c5a/go.mod h1:3NqKYiepwy8kCu4PNA+aP7WUV72eXWJeP9/r3/K9aLE= github.com/aphistic/sweet v0.2.0/go.mod h1:fWDlIh/isSE9n6EPsRmC0det+whmX6dJid3stzu0Xys= @@ -66,8 +63,8 @@ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kB github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/buildpacks/imgutil v0.0.0-20200313170640-a02052f47d62/go.mod h1:TjPmM78urjQIiMal4T7en6iBekAPv6z1yVMZobc4Kd8= -github.com/buildpacks/imgutil v0.0.0-20200805143852-1844b230530d h1:uVTFIiev3f7fi5BSv1RtM5W5lcqQodqLRBG5AdoDe2U= -github.com/buildpacks/imgutil v0.0.0-20200805143852-1844b230530d/go.mod h1:uVv0fNwOEBNgyM9ZvwV0g2Dvzk31q5TtSeoC1GGmW+k= +github.com/buildpacks/imgutil v0.0.0-20201015202701-6dd3ca364074 h1:uqgt8gd/oekjLqyk8oXRZdWaHv9Sc85ssjpmUcfn/cg= +github.com/buildpacks/imgutil v0.0.0-20201015202701-6dd3ca364074/go.mod h1:Oj9x40zkDyafaKpvgPuLGFjzzrdQQ+w9DNi1JzqJV1I= github.com/buildpacks/lifecycle v0.7.2 h1:FO7i2cokLNc7lcuThq/LYt1jmkB8HBrjpK+2GWWsaLI= github.com/buildpacks/lifecycle v0.7.2/go.mod h1:k41tT3XOt7ufaMGAvOpEsXyuJpUPoo4F686Z652lU3E= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= @@ -177,8 +174,6 @@ github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1 h1:qGJ6qTW+x6xX/my+8YUVl4WNpX9B7+/l2tRsHGZ7f2s= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/mock v1.4.1 h1:ocYkMQY5RrXTYgXl7ICpV0IXwlEQGwKIsery4gyXa1U= -github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -192,8 +187,6 @@ github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Z github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.5.1 h1:JFrFEBb2xKufg6XkJsJr+WbKb4FQlURi5RUcBveYu9k= -github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-containerregistry v0.0.0-20200311163244-4b1985e5ea21/go.mod h1:m8YvHwSOuBCq25yrj1DaX/fIMrv6ec3CNg8jY8+5PEA= @@ -390,8 +383,7 @@ github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkU github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= -github.com/spf13/cobra v0.0.6 h1:breEStsVwemnKh2/s6gMvSdMEkwW0sK8vGStnlVBMCs= -github.com/spf13/cobra v0.0.6/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= +github.com/spf13/cobra v0.0.7 h1:FfTH+vuMXOas8jmfb5/M7dzEYx7LpcLb7a0LPe34uOU= github.com/spf13/cobra v0.0.7/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= @@ -412,9 +404,11 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/tj/assert v0.0.0-20171129193455-018094318fb0/go.mod h1:mZ9/Rh9oLWpLLDRpvE+3b7gP/C2YyLFYxNmcLnPTMe0= +github.com/tj/assert v0.0.3 h1:Df/BlaZ20mq6kuai7f5z2TvPFiwC3xaWJSDQNiIS3Rk= github.com/tj/assert v0.0.3/go.mod h1:Ne6X72Q+TB1AteidzQncjw9PabbMp4PBMZ1k+vd1Pvk= github.com/tj/go-buffer v1.1.0/go.mod h1:iyiJpfFcR2B9sXu7KvjbT9fpM4mOelRSDTbntVj52Uc= github.com/tj/go-elastic v0.0.0-20171221160941-36157cbbebc2/go.mod h1:WjeM0Oo1eNAjXGDx2yma7uG2XoyRZTq1uv3M/o7imD0= @@ -475,8 +469,6 @@ golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee h1:WG0RUwxtNT4qqaXX3DPA8zHFNm/D9xaBpxzHt1WcA/E= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -543,7 +535,6 @@ golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 h1:uYVVQ9WP/Ds2ROhcaGPeIdVq0RIXVLwsHlnvJ+cT1So= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= @@ -643,6 +634,7 @@ gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c h1:grhR+C34yXImVGp7EzNk+DTIk+323eIUWOmEevy6bDo= gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= @@ -683,8 +675,6 @@ modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs= modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I= -rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= -rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= diff --git a/internal/build/phase_config_provider_test.go b/internal/build/phase_config_provider_test.go index 2cf09aaac..105f65af2 100644 --- a/internal/build/phase_config_provider_test.go +++ b/internal/build/phase_config_provider_test.go @@ -64,7 +64,7 @@ func testPhaseConfigProvider(t *testing.T, when spec.G, it spec.S) { when("building for Windows", func() { it("sets process isolation", func() { fakeBuilderImage := ifakes.NewImage("fake-builder", "", nil) - fakeBuilderImage.SetPlatform("windows", "", "") + h.AssertNil(t, fakeBuilderImage.SetOS("windows")) fakeBuilder, err := fakes.NewFakeBuilder(fakes.WithImage(fakeBuilderImage)) h.AssertNil(t, err) lifecycle := newTestLifecycleExec(t, false, fakes.WithBuilder(fakeBuilder)) @@ -141,7 +141,7 @@ func testPhaseConfigProvider(t *testing.T, when spec.G, it spec.S) { when("building for Windows", func() { it("sets daemon access on the config", func() { fakeBuilderImage := ifakes.NewImage("fake-builder", "", nil) - fakeBuilderImage.SetPlatform("windows", "", "") + h.AssertNil(t, fakeBuilderImage.SetOS("windows")) fakeBuilder, err := fakes.NewFakeBuilder(fakes.WithImage(fakeBuilderImage)) h.AssertNil(t, err) lifecycle := newTestLifecycleExec(t, false, fakes.WithBuilder(fakeBuilder)) @@ -242,7 +242,7 @@ func testPhaseConfigProvider(t *testing.T, when spec.G, it spec.S) { when("building for Windows", func() { it("sets root user on the config", func() { fakeBuilderImage := ifakes.NewImage("fake-builder", "", nil) - fakeBuilderImage.SetPlatform("windows", "", "") + h.AssertNil(t, fakeBuilderImage.SetOS("windows")) fakeBuilder, err := fakes.NewFakeBuilder(fakes.WithImage(fakeBuilderImage)) h.AssertNil(t, err) lifecycle := newTestLifecycleExec(t, false, fakes.WithBuilder(fakeBuilder)) diff --git a/internal/buildpackage/builder.go b/internal/buildpackage/builder.go index 2b10c19f0..1680ca61e 100644 --- a/internal/buildpackage/builder.go +++ b/internal/buildpackage/builder.go @@ -3,10 +3,12 @@ package buildpackage import ( "archive/tar" "compress/gzip" - "context" + "io" "io/ioutil" "os" + "github.com/buildpacks/imgutil/layer" + "github.com/buildpacks/imgutil" v1 "github.com/google/go-containerregistry/pkg/v1" "github.com/google/go-containerregistry/pkg/v1/empty" @@ -15,24 +17,18 @@ import ( "github.com/google/go-containerregistry/pkg/v1/tarball" "github.com/pkg/errors" - pubcfg "github.com/buildpacks/pack/config" "github.com/buildpacks/pack/internal/archive" "github.com/buildpacks/pack/internal/dist" "github.com/buildpacks/pack/internal/stack" "github.com/buildpacks/pack/internal/style" ) -const windowsPackageBase = "mcr.microsoft.com/windows/nanoserver:1809-amd64" // TODO: Should this be hard-coded? - type ImageFactory interface { NewImage(repoName string, local bool) (imgutil.Image, error) } -type ImageFetcher interface { - Fetch(ctx context.Context, name string, daemon bool, pullPolicy pubcfg.PullPolicy) (imgutil.Image, error) -} - type WorkableImage interface { + SetOS(string) error SetLabel(string, string) error AddLayerWithDiffID(path, diffID string) error } @@ -55,12 +51,22 @@ func (i *layoutImage) SetLabel(key string, val string) error { return err } +func (i *layoutImage) SetOS(osVal string) error { + configFile, err := i.ConfigFile() + if err != nil { + return err + } + configFile.OS = osVal + i.Image, err = mutate.ConfigFile(i.Image, configFile) + return err +} + func (i *layoutImage) AddLayerWithDiffID(path, _ string) error { - layer, err := tarball.LayerFromFile(path, tarball.WithCompressionLevel(gzip.DefaultCompression)) + tarLayer, err := tarball.LayerFromFile(path, tarball.WithCompressionLevel(gzip.DefaultCompression)) if err != nil { return err } - i.Image, err = mutate.AppendLayers(i.Image, layer) + i.Image, err = mutate.AppendLayers(i.Image, tarLayer) if err != nil { return errors.Wrap(err, "add layer") } @@ -70,16 +76,12 @@ func (i *layoutImage) AddLayerWithDiffID(path, _ string) error { type PackageBuilder struct { buildpack dist.Buildpack dependencies []dist.Buildpack - imageOS string imageFactory ImageFactory - imageFetcher ImageFetcher } -func NewBuilder(imageOS string, imageFactory ImageFactory, imageFetcher ImageFetcher) *PackageBuilder { +func NewBuilder(imageFactory ImageFactory) *PackageBuilder { return &PackageBuilder{ - imageOS: imageOS, imageFactory: imageFactory, - imageFetcher: imageFetcher, } } @@ -91,7 +93,7 @@ func (b *PackageBuilder) AddDependency(buildpack dist.Buildpack) { b.dependencies = append(b.dependencies, buildpack) } -func (b *PackageBuilder) finalizeImage(tmpDir string, image WorkableImage) error { +func (b *PackageBuilder) finalizeImage(image WorkableImage, imageOS, tmpDir string) error { if err := dist.SetLabel(image, MetadataLabel, &Metadata{ BuildpackInfo: b.buildpack.Descriptor().Info, Stacks: b.resolvedStacks(), @@ -99,6 +101,16 @@ func (b *PackageBuilder) finalizeImage(tmpDir string, image WorkableImage) error return err } + if err := image.SetOS(imageOS); err != nil { + return err + } + + if imageOS == "windows" { + if err := addWindowsShimBaseLayer(image, tmpDir); err != nil { + return err + } + } + bpLayers := dist.BuildpackLayers{} for _, bp := range append(b.dependencies, b.buildpack) { bpLayerTar, err := dist.BuildpackToLayerTar(tmpDir, bp) @@ -128,6 +140,39 @@ func (b *PackageBuilder) finalizeImage(tmpDir string, image WorkableImage) error return nil } +func addWindowsShimBaseLayer(image WorkableImage, tmpDir string) error { + baseLayerFile, err := ioutil.TempFile(tmpDir, "windows-baselayer") + if err != nil { + return err + } + defer baseLayerFile.Close() + + baseLayer, err := layer.WindowsBaseLayer() + if err != nil { + return err + } + + if _, err := io.Copy(baseLayerFile, baseLayer); err != nil { + return err + } + + if err := baseLayerFile.Close(); err != nil { + return err + } + + baseLayerPath := baseLayerFile.Name() + diffID, err := dist.LayerDiffID(baseLayerPath) + if err != nil { + return err + } + + if err := image.AddLayerWithDiffID(baseLayerPath, diffID.String()); err != nil { + return err + } + + return nil +} + func (b *PackageBuilder) validate() error { if b.buildpack == nil { return errors.New("buildpack must be set") @@ -159,7 +204,7 @@ func (b *PackageBuilder) resolvedStacks() []dist.Stack { return stacks } -func (b *PackageBuilder) SaveAsFile(path string) error { +func (b *PackageBuilder) SaveAsFile(path, imageOS string) error { if err := b.validate(); err != nil { return err } @@ -174,7 +219,7 @@ func (b *PackageBuilder) SaveAsFile(path string) error { } defer os.RemoveAll(tmpDir) - if err := b.finalizeImage(tmpDir, layoutImage); err != nil { + if err := b.finalizeImage(layoutImage, imageOS, tmpDir); err != nil { return err } @@ -204,26 +249,14 @@ func (b *PackageBuilder) SaveAsFile(path string) error { return archive.WriteDirToTar(tw, layoutDir, "/", 0, 0, 0755, true, nil) } -func (b *PackageBuilder) SaveAsImage(ctx context.Context, repoName string, publish bool, pullPolicy pubcfg.PullPolicy) (imgutil.Image, error) { +func (b *PackageBuilder) SaveAsImage(repoName string, publish bool, imageOS string) (imgutil.Image, error) { if err := b.validate(); err != nil { return nil, err } - var ( - image imgutil.Image - err error - ) - if b.imageOS == "windows" { - image, err = b.imageFetcher.Fetch(ctx, windowsPackageBase, !publish, pullPolicy) - if err != nil { - return nil, errors.Wrapf(err, "fetching base image") - } - image.Rename(repoName) - } else { - image, err = b.imageFactory.NewImage(repoName, !publish) - if err != nil { - return nil, errors.Wrapf(err, "creating image") - } + image, err := b.imageFactory.NewImage(repoName, !publish) + if err != nil { + return nil, errors.Wrapf(err, "creating image") } tmpDir, err := ioutil.TempDir("", "package-buildpack") @@ -232,7 +265,7 @@ func (b *PackageBuilder) SaveAsImage(ctx context.Context, repoName string, publi } defer os.RemoveAll(tmpDir) - if err := b.finalizeImage(tmpDir, image); err != nil { + if err := b.finalizeImage(image, imageOS, tmpDir); err != nil { return nil, err } diff --git a/internal/buildpackage/builder_test.go b/internal/buildpackage/builder_test.go index 1d3d58017..0076b7156 100644 --- a/internal/buildpackage/builder_test.go +++ b/internal/buildpackage/builder_test.go @@ -3,7 +3,6 @@ package buildpackage_test import ( "archive/tar" "compress/gzip" - "context" "encoding/json" "fmt" "io" @@ -13,6 +12,8 @@ import ( "path/filepath" "testing" + "github.com/buildpacks/imgutil/layer" + "github.com/buildpacks/imgutil/fakes" "github.com/buildpacks/lifecycle/api" "github.com/golang/mock/gomock" @@ -22,7 +23,6 @@ import ( "github.com/sclevine/spec" "github.com/sclevine/spec/report" - "github.com/buildpacks/pack/config" "github.com/buildpacks/pack/internal/buildpackage" "github.com/buildpacks/pack/internal/dist" ifakes "github.com/buildpacks/pack/internal/fakes" @@ -51,7 +51,7 @@ func testPackageBuilder(t *testing.T, when spec.G, it spec.S) { fakePackageImage := fakes.NewImage("some/package", "", nil) mockImageFactory.EXPECT().NewImage("some/package", true).Return(fakePackageImage, nil).AnyTimes() - subject = buildpackage.NewBuilder("linux", mockImageFactory, nil) + subject = buildpackage.NewBuilder(mockImageFactory) var err error tmpDir, err = ioutil.TempDir("", "package_builder_tests") @@ -69,11 +69,18 @@ func testPackageBuilder(t *testing.T, when spec.G, it spec.S) { fn func() error }{ {name: "SaveAsImage", fn: func() error { - _, err := subject.SaveAsImage(context.TODO(), "some/package", false, config.PullAlways) + _, err := subject.SaveAsImage("some/package", false, "linux") + return err + }}, + {name: "SaveAsImage", fn: func() error { + _, err := subject.SaveAsImage("some/package", false, "windows") return err }}, {name: "SaveAsFile", fn: func() error { - return subject.SaveAsFile(path.Join(tmpDir, "package.cnb")) + return subject.SaveAsFile(path.Join(tmpDir, "package.cnb"), "windows") + }}, + {name: "SaveAsFile", fn: func() error { + return subject.SaveAsFile(path.Join(tmpDir, "package.cnb"), "linux") }}, } { testFn := test.fn @@ -270,7 +277,7 @@ func testPackageBuilder(t *testing.T, when spec.G, it spec.S) { h.AssertNil(t, err) subject.AddDependency(dependency2) - _, err = subject.SaveAsImage(context.TODO(), "some/package", false, config.PullAlways) + _, err = subject.SaveAsImage("some/package", false, "linux") h.AssertError(t, err, "no compatible stacks among provided buildpacks") }) }) @@ -325,7 +332,7 @@ func testPackageBuilder(t *testing.T, when spec.G, it spec.S) { h.AssertNil(t, err) subject.AddDependency(dependency2) - img, err := subject.SaveAsImage(context.TODO(), "some/package", false, config.PullAlways) + img, err := subject.SaveAsImage("some/package", false, "linux") h.AssertNil(t, err) metadata := buildpackage.Metadata{} @@ -389,7 +396,7 @@ func testPackageBuilder(t *testing.T, when spec.G, it spec.S) { subject.AddDependency(dependencyNestedNested) - img, err := subject.SaveAsImage(context.TODO(), "some/package", false, config.PullAlways) + img, err := subject.SaveAsImage("some/package", false, "linux") h.AssertNil(t, err) metadata := buildpackage.Metadata{} @@ -405,203 +412,127 @@ func testPackageBuilder(t *testing.T, when spec.G, it spec.S) { }) when("#SaveAsImage", func() { - when("creating linux package", func() { - it("sets metadata", func() { - buildpack1, err := ifakes.NewFakeBuildpack(dist.BuildpackDescriptor{ - API: api.MustParse("0.2"), - Info: dist.BuildpackInfo{ - ID: "bp.1.id", - Version: "bp.1.version", - }, - Stacks: []dist.Stack{ - {ID: "stack.id.1"}, - {ID: "stack.id.2"}, - }, - Order: nil, - }, 0644) - h.AssertNil(t, err) - - subject.SetBuildpack(buildpack1) - - packageImage, err := subject.SaveAsImage(context.TODO(), "some/package", false, config.PullAlways) - h.AssertNil(t, err) - - labelData, err := packageImage.Label("io.buildpacks.buildpackage.metadata") - h.AssertNil(t, err) - var md buildpackage.Metadata - h.AssertNil(t, json.Unmarshal([]byte(labelData), &md)) - - h.AssertEq(t, md.ID, "bp.1.id") - h.AssertEq(t, md.Version, "bp.1.version") - h.AssertEq(t, len(md.Stacks), 2) - h.AssertEq(t, md.Stacks[0].ID, "stack.id.1") - h.AssertEq(t, md.Stacks[1].ID, "stack.id.2") - }) - - it("sets buildpack layers label", func() { - buildpack1, err := ifakes.NewFakeBuildpack(dist.BuildpackDescriptor{ - API: api.MustParse("0.2"), - Info: dist.BuildpackInfo{ID: "bp.1.id", Version: "bp.1.version"}, - Stacks: []dist.Stack{{ID: "stack.id.1"}, {ID: "stack.id.2"}}, - Order: nil, - }, 0644) - h.AssertNil(t, err) - subject.SetBuildpack(buildpack1) - - packageImage, err := subject.SaveAsImage(context.TODO(), "some/package", false, config.PullAlways) - h.AssertNil(t, err) + it("sets metadata", func() { + buildpack1, err := ifakes.NewFakeBuildpack(dist.BuildpackDescriptor{ + API: api.MustParse("0.2"), + Info: dist.BuildpackInfo{ + ID: "bp.1.id", + Version: "bp.1.version", + }, + Stacks: []dist.Stack{ + {ID: "stack.id.1"}, + {ID: "stack.id.2"}, + }, + Order: nil, + }, 0644) + h.AssertNil(t, err) - var bpLayers dist.BuildpackLayers - _, err = dist.GetLabel(packageImage, "io.buildpacks.buildpack.layers", &bpLayers) - h.AssertNil(t, err) + subject.SetBuildpack(buildpack1) - bp1Info, ok1 := bpLayers["bp.1.id"]["bp.1.version"] - h.AssertEq(t, ok1, true) - h.AssertEq(t, bp1Info.Stacks, []dist.Stack{{ID: "stack.id.1"}, {ID: "stack.id.2"}}) - }) + packageImage, err := subject.SaveAsImage("some/package", false, "linux") + h.AssertNil(t, err) - it("adds buildpack layers", func() { - buildpack1, err := ifakes.NewFakeBuildpack(dist.BuildpackDescriptor{ - API: api.MustParse("0.2"), - Info: dist.BuildpackInfo{ID: "bp.1.id", Version: "bp.1.version"}, - Stacks: []dist.Stack{{ID: "stack.id.1"}, {ID: "stack.id.2"}}, - Order: nil, - }, 0644) - h.AssertNil(t, err) - subject.SetBuildpack(buildpack1) + labelData, err := packageImage.Label("io.buildpacks.buildpackage.metadata") + h.AssertNil(t, err) + var md buildpackage.Metadata + h.AssertNil(t, json.Unmarshal([]byte(labelData), &md)) - packageImage, err := subject.SaveAsImage(context.TODO(), "some/package", false, config.PullAlways) - h.AssertNil(t, err) + h.AssertEq(t, md.ID, "bp.1.id") + h.AssertEq(t, md.Version, "bp.1.version") + h.AssertEq(t, len(md.Stacks), 2) + h.AssertEq(t, md.Stacks[0].ID, "stack.id.1") + h.AssertEq(t, md.Stacks[1].ID, "stack.id.2") - buildpackExists := func(name, version string) { - t.Helper() - dirPath := fmt.Sprintf("/cnb/buildpacks/%s/%s", name, version) - fakePackageImage := packageImage.(*fakes.Image) - layerTar, err := fakePackageImage.FindLayerWithPath(dirPath) - h.AssertNil(t, err) + osVal, err := packageImage.OS() + h.AssertNil(t, err) + h.AssertEq(t, osVal, "linux") + }) - h.AssertOnTarEntry(t, layerTar, dirPath, - h.IsDirectory(), - ) + it("sets buildpack layers label", func() { + buildpack1, err := ifakes.NewFakeBuildpack(dist.BuildpackDescriptor{ + API: api.MustParse("0.2"), + Info: dist.BuildpackInfo{ID: "bp.1.id", Version: "bp.1.version"}, + Stacks: []dist.Stack{{ID: "stack.id.1"}, {ID: "stack.id.2"}}, + Order: nil, + }, 0644) + h.AssertNil(t, err) + subject.SetBuildpack(buildpack1) - h.AssertOnTarEntry(t, layerTar, dirPath+"/bin/build", - h.ContentEquals("build-contents"), - h.HasOwnerAndGroup(0, 0), - h.HasFileMode(0644), - ) + packageImage, err := subject.SaveAsImage("some/package", false, "linux") + h.AssertNil(t, err) - h.AssertOnTarEntry(t, layerTar, dirPath+"/bin/detect", - h.ContentEquals("detect-contents"), - h.HasOwnerAndGroup(0, 0), - h.HasFileMode(0644), - ) - } + var bpLayers dist.BuildpackLayers + _, err = dist.GetLabel(packageImage, "io.buildpacks.buildpack.layers", &bpLayers) + h.AssertNil(t, err) - buildpackExists("bp.1.id", "bp.1.version") - }) + bp1Info, ok1 := bpLayers["bp.1.id"]["bp.1.version"] + h.AssertEq(t, ok1, true) + h.AssertEq(t, bp1Info.Stacks, []dist.Stack{{ID: "stack.id.1"}, {ID: "stack.id.2"}}) }) - when("creating windows package", func() { - it.Before(func() { - mockImageFetcher := testmocks.NewMockImageFetcher(mockController) - subject = buildpackage.NewBuilder("windows", nil, mockImageFetcher) - fakeBaseImage := fakes.NewImage("", "", nil) - mockImageFetcher.EXPECT().Fetch(context.TODO(), "mcr.microsoft.com/windows/nanoserver:1809-amd64", gomock.Any(), gomock.Any()).Return(fakeBaseImage, nil) - }) - - it("sets metadata", func() { - buildpack1, err := ifakes.NewFakeBuildpack(dist.BuildpackDescriptor{ - API: api.MustParse("0.2"), - Info: dist.BuildpackInfo{ - ID: "bp.1.id", - Version: "bp.1.version", - }, - Stacks: []dist.Stack{ - {ID: "stack.id.1"}, - {ID: "stack.id.2"}, - }, - Order: nil, - }, 0644) - h.AssertNil(t, err) - - subject.SetBuildpack(buildpack1) - - packageImage, err := subject.SaveAsImage(context.TODO(), "some/package", false, config.PullAlways) - h.AssertNil(t, err) + it("adds buildpack layers for linux", func() { + buildpack1, err := ifakes.NewFakeBuildpack(dist.BuildpackDescriptor{ + API: api.MustParse("0.2"), + Info: dist.BuildpackInfo{ID: "bp.1.id", Version: "bp.1.version"}, + Stacks: []dist.Stack{{ID: "stack.id.1"}, {ID: "stack.id.2"}}, + Order: nil, + }, 0644) + h.AssertNil(t, err) + subject.SetBuildpack(buildpack1) - labelData, err := packageImage.Label("io.buildpacks.buildpackage.metadata") - h.AssertNil(t, err) - var md buildpackage.Metadata - h.AssertNil(t, json.Unmarshal([]byte(labelData), &md)) - - h.AssertEq(t, md.ID, "bp.1.id") - h.AssertEq(t, md.Version, "bp.1.version") - h.AssertEq(t, len(md.Stacks), 2) - h.AssertEq(t, md.Stacks[0].ID, "stack.id.1") - h.AssertEq(t, md.Stacks[1].ID, "stack.id.2") - }) + packageImage, err := subject.SaveAsImage("some/package", false, "linux") + h.AssertNil(t, err) - it("sets buildpack layers label", func() { - buildpack1, err := ifakes.NewFakeBuildpack(dist.BuildpackDescriptor{ - API: api.MustParse("0.2"), - Info: dist.BuildpackInfo{ID: "bp.1.id", Version: "bp.1.version"}, - Stacks: []dist.Stack{{ID: "stack.id.1"}, {ID: "stack.id.2"}}, - Order: nil, - }, 0644) + buildpackExists := func(name, version string) { + t.Helper() + dirPath := fmt.Sprintf("/cnb/buildpacks/%s/%s", name, version) + fakePackageImage := packageImage.(*fakes.Image) + layerTar, err := fakePackageImage.FindLayerWithPath(dirPath) h.AssertNil(t, err) - subject.SetBuildpack(buildpack1) - image, err := subject.SaveAsImage(context.TODO(), "some/package", false, config.PullAlways) - h.AssertNil(t, err) + h.AssertOnTarEntry(t, layerTar, dirPath, + h.IsDirectory(), + ) - var bpLayers dist.BuildpackLayers - _, err = dist.GetLabel(image, "io.buildpacks.buildpack.layers", &bpLayers) - h.AssertNil(t, err) + h.AssertOnTarEntry(t, layerTar, dirPath+"/bin/build", + h.ContentEquals("build-contents"), + h.HasOwnerAndGroup(0, 0), + h.HasFileMode(0644), + ) - bp1Info, ok1 := bpLayers["bp.1.id"]["bp.1.version"] - h.AssertEq(t, ok1, true) - h.AssertEq(t, bp1Info.Stacks, []dist.Stack{{ID: "stack.id.1"}, {ID: "stack.id.2"}}) - }) + h.AssertOnTarEntry(t, layerTar, dirPath+"/bin/detect", + h.ContentEquals("detect-contents"), + h.HasOwnerAndGroup(0, 0), + h.HasFileMode(0644), + ) + } - it("adds buildpack layers", func() { - buildpack1, err := ifakes.NewFakeBuildpack(dist.BuildpackDescriptor{ - API: api.MustParse("0.2"), - Info: dist.BuildpackInfo{ID: "bp.1.id", Version: "bp.1.version"}, - Stacks: []dist.Stack{{ID: "stack.id.1"}, {ID: "stack.id.2"}}, - Order: nil, - }, 0644) - h.AssertNil(t, err) - subject.SetBuildpack(buildpack1) + buildpackExists("bp.1.id", "bp.1.version") - packageImage, err := subject.SaveAsImage(context.TODO(), "some/package", false, config.PullAlways) - h.AssertNil(t, err) + fakePackageImage := packageImage.(*fakes.Image) + h.AssertEq(t, fakePackageImage.NumberOfAddedLayers(), 1) + }) - buildpackExists := func(name, version string) { - t.Helper() - dirPath := fmt.Sprintf("/cnb/buildpacks/%s/%s", name, version) - fakePackageImage := packageImage.(*fakes.Image) - layerTar, err := fakePackageImage.FindLayerWithPath(dirPath) - h.AssertNil(t, err) + it("adds baselayer + buildpack layers for windows", func() { + buildpack1, err := ifakes.NewFakeBuildpack(dist.BuildpackDescriptor{ + API: api.MustParse("0.2"), + Info: dist.BuildpackInfo{ID: "bp.1.id", Version: "bp.1.version"}, + Stacks: []dist.Stack{{ID: "stack.id.1"}, {ID: "stack.id.2"}}, + Order: nil, + }, 0644) + h.AssertNil(t, err) + subject.SetBuildpack(buildpack1) - h.AssertOnTarEntry(t, layerTar, dirPath, - h.IsDirectory(), - ) + packageImage, err := subject.SaveAsImage("some/package", false, "windows") + h.AssertNil(t, err) - h.AssertOnTarEntry(t, layerTar, dirPath+"/bin/build", - h.ContentEquals("build-contents"), - h.HasOwnerAndGroup(0, 0), - h.HasFileMode(0644), - ) + fakePackageImage := packageImage.(*fakes.Image) - h.AssertOnTarEntry(t, layerTar, dirPath+"/bin/detect", - h.ContentEquals("detect-contents"), - h.HasOwnerAndGroup(0, 0), - h.HasFileMode(0644), - ) - } + osVal, err := fakePackageImage.OS() + h.AssertNil(t, err) + h.AssertEq(t, osVal, "windows") - buildpackExists("bp.1.id", "bp.1.version") - }) + h.AssertEq(t, fakePackageImage.NumberOfAddedLayers(), 2) }) }) @@ -617,7 +548,7 @@ func testPackageBuilder(t *testing.T, when spec.G, it spec.S) { subject.SetBuildpack(buildpack1) outputFile := filepath.Join(tmpDir, fmt.Sprintf("package-%s.cnb", h.RandString(10))) - h.AssertNil(t, subject.SaveAsFile(outputFile)) + h.AssertNil(t, subject.SaveAsFile(outputFile, "linux")) withContents := func(fn func(data []byte)) h.TarEntryAssertion { return func(t *testing.T, header *tar.Header, data []byte) { @@ -639,6 +570,7 @@ func testPackageBuilder(t *testing.T, when spec.G, it spec.S) { "/blobs/sha256/"+index.Manifests[0].Digest.Hex(), h.HasOwnerAndGroup(0, 0), h.IsJSON(), + withContents(func(data []byte) { manifest := v1.Manifest{} err := json.Unmarshal(data, &manifest) @@ -653,12 +585,14 @@ func testPackageBuilder(t *testing.T, when spec.G, it spec.S) { h.ContentContains(`"io.buildpacks.buildpackage.metadata":"{\"id\":\"bp.1.id\",\"version\":\"bp.1.version\",\"stacks\":[{\"id\":\"stack.id.1\"},{\"id\":\"stack.id.2\"}]}"`), // buildpack layers metadata h.ContentContains(`"io.buildpacks.buildpack.layers":"{\"bp.1.id\":{\"bp.1.version\":{\"api\":\"0.2\",\"stacks\":[{\"id\":\"stack.id.1\"},{\"id\":\"stack.id.2\"}],\"layerDiffID\":\"sha256:a10862daec7a8a62fd04cc5d4520fdb80d4d5c07a3c146fb604a9c23c22fd5b0\"}}}"`), + // image os + h.ContentContains(`"os":"linux"`), ) })) })) }) - it("adds buildpack layers", func() { + it("adds buildpack layers for linux", func() { buildpack1, err := ifakes.NewFakeBuildpack(dist.BuildpackDescriptor{ API: api.MustParse("0.2"), Info: dist.BuildpackInfo{ID: "bp.1.id", Version: "bp.1.version"}, @@ -669,7 +603,7 @@ func testPackageBuilder(t *testing.T, when spec.G, it spec.S) { subject.SetBuildpack(buildpack1) outputFile := filepath.Join(tmpDir, fmt.Sprintf("package-%s.cnb", h.RandString(10))) - h.AssertNil(t, subject.SaveAsFile(outputFile)) + h.AssertNil(t, subject.SaveAsFile(outputFile, "linux")) h.AssertOnTarEntry(t, outputFile, "/blobs", h.IsDirectory(), @@ -680,8 +614,12 @@ func testPackageBuilder(t *testing.T, when spec.G, it spec.S) { h.HasOwnerAndGroup(0, 0), h.HasFileMode(0755)) + bpReader, err := buildpack1.Open() + h.AssertNil(t, err) + defer bpReader.Close() + // layer: application/vnd.docker.image.rootfs.diff.tar.gzip - buildpackLayerSHA, err := computeBuildpackLayerSHA(buildpack1) + buildpackLayerSHA, err := computeLayerSHA(bpReader) h.AssertNil(t, err) h.AssertOnTarEntry(t, outputFile, "/blobs/sha256/"+buildpackLayerSHA, @@ -701,18 +639,53 @@ func testPackageBuilder(t *testing.T, when spec.G, it spec.S) { h.HasOwnerAndGroup(0, 0), h.HasFileMode(0644))) }) + + it("adds baselayer + buildpack layers for windows", func() { + buildpack1, err := ifakes.NewFakeBuildpack(dist.BuildpackDescriptor{ + API: api.MustParse("0.2"), + Info: dist.BuildpackInfo{ID: "bp.1.id", Version: "bp.1.version"}, + Stacks: []dist.Stack{{ID: "stack.id.1"}, {ID: "stack.id.2"}}, + Order: nil, + }, 0644) + h.AssertNil(t, err) + subject.SetBuildpack(buildpack1) + + outputFile := filepath.Join(tmpDir, fmt.Sprintf("package-%s.cnb", h.RandString(10))) + h.AssertNil(t, subject.SaveAsFile(outputFile, "windows")) + + // Windows baselayer content is constant + expectedBaseLayerReader, err := layer.WindowsBaseLayer() + h.AssertNil(t, err) + + // layer: application/vnd.docker.image.rootfs.diff.tar.gzip + expectedBaseLayerSHA, err := computeLayerSHA(ioutil.NopCloser(expectedBaseLayerReader)) + h.AssertNil(t, err) + h.AssertOnTarEntry(t, outputFile, + "/blobs/sha256/"+expectedBaseLayerSHA, + h.HasOwnerAndGroup(0, 0), + h.HasFileMode(0755), + h.IsGzipped(), + ) + + bpReader, err := buildpack1.Open() + h.AssertNil(t, err) + defer bpReader.Close() + + buildpackLayerSHA, err := computeLayerSHA(bpReader) + h.AssertNil(t, err) + h.AssertOnTarEntry(t, outputFile, + "/blobs/sha256/"+buildpackLayerSHA, + h.HasOwnerAndGroup(0, 0), + h.HasFileMode(0755), + h.IsGzipped(), + ) + }) }) } -func computeBuildpackLayerSHA(buildpack dist.Buildpack) (string, error) { - reader, err := buildpack.Open() - if err != nil { - return "", err - } - defer reader.Close() - - layer := stream.NewLayer(reader, stream.WithCompressionLevel(gzip.DefaultCompression)) - compressed, err := layer.Compressed() +func computeLayerSHA(reader io.ReadCloser) (string, error) { + bpLayer := stream.NewLayer(reader, stream.WithCompressionLevel(gzip.DefaultCompression)) + compressed, err := bpLayer.Compressed() if err != nil { return "", err } @@ -722,7 +695,7 @@ func computeBuildpackLayerSHA(buildpack dist.Buildpack) (string, error) { return "", err } - digest, err := layer.Digest() + digest, err := bpLayer.Digest() if err != nil { return "", err } diff --git a/package_buildpack.go b/package_buildpack.go index 114b0c36b..f4fe76f72 100644 --- a/package_buildpack.go +++ b/package_buildpack.go @@ -54,7 +54,7 @@ func (c *Client) PackageBuildpack(ctx context.Context, opts PackageBuildpackOpti return errors.Wrap(err, "creating layer writer factory") } - packageBuilder := buildpackage.NewBuilder(info.OSType, c.imageFactory, c.imageFetcher) + packageBuilder := buildpackage.NewBuilder(c.imageFactory) if opts.Format == "" { opts.Format = FormatImage @@ -121,9 +121,9 @@ func (c *Client) PackageBuildpack(ctx context.Context, opts PackageBuildpackOpti switch opts.Format { case FormatFile: - return packageBuilder.SaveAsFile(opts.Name) + return packageBuilder.SaveAsFile(opts.Name, info.OSType) case FormatImage: - _, err = packageBuilder.SaveAsImage(ctx, opts.Name, opts.Publish, opts.PullPolicy) + _, err = packageBuilder.SaveAsImage(opts.Name, opts.Publish, info.OSType) return errors.Wrapf(err, "saving image") default: return errors.Errorf("unknown format: %s", style.Symbol(opts.Format)) From af1a3ab89f20c7b136d183fd3173987489ebbab4 Mon Sep 17 00:00:00 2001 From: Micah Young Date: Tue, 13 Oct 2020 07:23:32 -0400 Subject: [PATCH 09/14] Add package-buildpack arg for OS - Important for publish scenarios to not depend on daemon Signed-off-by: Micah Young --- acceptance/acceptance_test.go | 29 +- acceptance/buildpacks/manager.go | 25 + .../buildpacks/package_file_buildpack.go | 32 +- .../buildpacks/package_image_buildpack.go | 23 +- .../testdata/pack_fixtures/report_output.txt | 1 + cmd/cmd.go | 2 +- internal/commands/package_buildpack.go | 32 +- internal/commands/package_buildpack_test.go | 129 +++-- package_buildpack.go | 50 +- package_buildpack_test.go | 461 +++++++++++------- 10 files changed, 526 insertions(+), 258 deletions(-) diff --git a/acceptance/acceptance_test.go b/acceptance/acceptance_test.go index b188393ad..b088a46de 100644 --- a/acceptance/acceptance_test.go +++ b/acceptance/acceptance_test.go @@ -125,6 +125,7 @@ func testWithoutSpecificBuilderRequirement( it.Before(func() { pack = invoke.NewPackInvoker(t, assert, packConfig, registryConfig.DockerConfigDir) + pack.EnableExperimental() buildpackManager = buildpacks.NewBuildpackManager(t, assert) }) @@ -325,6 +326,8 @@ func testWithoutSpecificBuilderRequirement( when("--publish", func() { it("publishes image to registry", func() { + h.SkipIf(t, !pack.Supports("package-buildpack --os"), "os not supported") + nestedPackageName := registryConfig.RepoName("test/package-" + h.RandString(10)) nestedPackage := buildpacks.NewPackageImage( @@ -332,8 +335,9 @@ func testWithoutSpecificBuilderRequirement( pack, nestedPackageName, simplePackageConfigPath, - buildpacks.WithPublish(), buildpacks.WithRequiredBuildpacks(buildpacks.SimpleLayers), + buildpacks.WithPublish(), + buildpacks.WithOS(dockerHostOS()), ) buildpackManager.PrepareBuildpacks(tmpDir, nestedPackage) defer h.DockerRmi(dockerCli, nestedPackageName) @@ -344,6 +348,7 @@ func testWithoutSpecificBuilderRequirement( "package-buildpack", packageName, "-c", aggregatePackageToml, "--publish", + "--os", dockerHostOS(), ) defer h.DockerRmi(dockerCli, packageName) assertions.NewOutputAssertionManager(t, output).ReportsPackagePublished(packageName) @@ -535,8 +540,10 @@ func testWithoutSpecificBuilderRequirement( pack, packageFileLocation, pack.FixtureManager().FixtureLocation("package_for_build_cmd.toml"), - buildpacks.FolderSimpleLayersParent, - buildpacks.FolderSimpleLayers, + buildpacks.WithRequiredBuildpacks( + buildpacks.FolderSimpleLayersParent, + buildpacks.FolderSimpleLayers, + ), ) buildpackManager.PrepareBuildpacks(tmpDir, packageFile) @@ -1242,8 +1249,8 @@ func testAcceptance( it.Before(func() { h.SkipUnless(t, - pack.Supports("package-buildpack"), - "--buildpack does not accept buildpackage unless package-buildpack is supported", + pack.Supports("package-buildpack --os"), + "--buildpack does not accept buildpackage unless package-buildpack --os is supported", ) }) @@ -1291,6 +1298,11 @@ func testAcceptance( var tmpDir string it.Before(func() { + h.SkipUnless(t, + pack.Supports("package-buildpack --os"), + "--buildpack does not accept buildpackage unless package-buildpack --os is supported", + ) + var err error tmpDir, err = ioutil.TempDir("", "package-file") assert.Nil(err) @@ -1311,8 +1323,11 @@ func testAcceptance( pack, packageFileLocation, pack.FixtureManager().FixtureLocation("package_for_build_cmd.toml"), - buildpacks.FolderSimpleLayersParent, - buildpacks.FolderSimpleLayers, + buildpacks.WithRequiredBuildpacks( + buildpacks.FolderSimpleLayersParent, + buildpacks.FolderSimpleLayers, + ), + buildpacks.WithOS(dockerHostOS()), ) buildpackManager.PrepareBuildpacks(tmpDir, packageFile) diff --git a/acceptance/buildpacks/manager.go b/acceptance/buildpacks/manager.go index 58f46f073..f3777bd42 100644 --- a/acceptance/buildpacks/manager.go +++ b/acceptance/buildpacks/manager.go @@ -51,3 +51,28 @@ func (b BuildpackManager) PrepareBuildpacks(destination string, buildpacks ...Te b.assert.Nil(err) } } + +type Modifiable interface { + SetOS(string) + SetPublish() + SetBuildpacks([]TestBuildpack) +} +type PackageModifier func(p Modifiable) + +func WithRequiredBuildpacks(buildpacks ...TestBuildpack) PackageModifier { + return func(p Modifiable) { + p.SetBuildpacks(buildpacks) + } +} + +func WithPublish() PackageModifier { + return func(p Modifiable) { + p.SetPublish() + } +} + +func WithOS(osVal string) PackageModifier { + return func(p Modifiable) { + p.SetOS(osVal) + } +} diff --git a/acceptance/buildpacks/package_file_buildpack.go b/acceptance/buildpacks/package_file_buildpack.go index 21c478a15..3b6d5cb61 100644 --- a/acceptance/buildpacks/package_file_buildpack.go +++ b/acceptance/buildpacks/package_file_buildpack.go @@ -21,22 +21,37 @@ type PackageFile struct { destination string sourceConfigLocation string buildpacks []TestBuildpack + os string } +func (p *PackageFile) SetOS(os string) { + p.os = os +} + +func (p *PackageFile) SetBuildpacks(buildpacks []TestBuildpack) { + p.buildpacks = buildpacks +} + +func (p *PackageFile) SetPublish() {} + func NewPackageFile( t *testing.T, pack *invoke.PackInvoker, destination, configLocation string, - buildpacks ...TestBuildpack, + modifiers ...PackageModifier, ) PackageFile { - return PackageFile{ + p := PackageFile{ testObject: t, pack: pack, destination: destination, sourceConfigLocation: configLocation, - buildpacks: buildpacks, } + for _, mod := range modifiers { + mod(&p) + } + + return p } func (p PackageFile) Prepare(sourceDir, _ string) error { @@ -59,13 +74,18 @@ func (p PackageFile) Prepare(sourceDir, _ string) error { configLocation := filepath.Join(tmpDir, "package.toml") h.CopyFile(p.testObject, p.sourceConfigLocation, configLocation) - output := p.pack.RunSuccessfully( - "package-buildpack", + packArgs := []string{ p.destination, "--no-color", "-c", configLocation, "--format", "file", - ) + } + + if p.os != "" { + packArgs = append(packArgs, "--os", p.os) + } + + output := p.pack.RunSuccessfully("package-buildpack", packArgs...) if !strings.Contains(output, fmt.Sprintf("Successfully created package '%s'", p.destination)) { return errors.New("failed to create package") diff --git a/acceptance/buildpacks/package_image_buildpack.go b/acceptance/buildpacks/package_image_buildpack.go index 81719abc9..e2302a49b 100644 --- a/acceptance/buildpacks/package_image_buildpack.go +++ b/acceptance/buildpacks/package_image_buildpack.go @@ -23,27 +23,26 @@ type PackageImage struct { sourceConfigLocation string buildpacks []TestBuildpack publish bool + os string } -type PackageImageModifier func(p *PackageImage) +func (p *PackageImage) SetOS(os string) { + p.os = os +} -func WithRequiredBuildpacks(buildpacks ...TestBuildpack) PackageImageModifier { - return func(p *PackageImage) { - p.buildpacks = buildpacks - } +func (p *PackageImage) SetBuildpacks(buildpacks []TestBuildpack) { + p.buildpacks = buildpacks } -func WithPublish() PackageImageModifier { - return func(p *PackageImage) { - p.publish = true - } +func (p *PackageImage) SetPublish() { + p.publish = true } func NewPackageImage( t *testing.T, pack *invoke.PackInvoker, name, configLocation string, - modifiers ...PackageImageModifier, + modifiers ...PackageModifier, ) PackageImage { p := PackageImage{ testObject: t, @@ -90,6 +89,10 @@ func (p PackageImage) Prepare(sourceDir, _ string) error { packArgs = append(packArgs, "--publish") } + if p.os != "" { + packArgs = append(packArgs, "--os", p.os) + } + output := p.pack.RunSuccessfully("package-buildpack", packArgs...) assertOutput := assertions.NewOutputAssertionManager(p.testObject, output) diff --git a/acceptance/testdata/pack_fixtures/report_output.txt b/acceptance/testdata/pack_fixtures/report_output.txt index 66cf032d8..d432ae706 100644 --- a/acceptance/testdata/pack_fixtures/report_output.txt +++ b/acceptance/testdata/pack_fixtures/report_output.txt @@ -8,3 +8,4 @@ Supported Platform APIs: 0.3, 0.4 Config: default-builder-image = "{{ .DefaultBuilder }}" + experimental = true diff --git a/cmd/cmd.go b/cmd/cmd.go index e9dedb4f0..6106c7709 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -76,7 +76,7 @@ func NewPackCommand(logger ConfigurableLogger) (*cobra.Command, error) { rootCmd.AddCommand(commands.ListTrustedBuilders(logger, cfg)) rootCmd.AddCommand(commands.CreateBuilder(logger, cfg, &packClient)) - rootCmd.AddCommand(commands.PackageBuildpack(logger, &packClient, buildpackage.NewConfigReader())) + rootCmd.AddCommand(commands.PackageBuildpack(logger, cfg, &packClient, buildpackage.NewConfigReader())) rootCmd.AddCommand(commands.SuggestStacks(logger)) diff --git a/internal/commands/package_buildpack.go b/internal/commands/package_buildpack.go index c1c645709..6a00ca4bb 100644 --- a/internal/commands/package_buildpack.go +++ b/internal/commands/package_buildpack.go @@ -3,12 +3,14 @@ package commands import ( "context" - "github.com/buildpacks/pack/config" + pubcfg "github.com/buildpacks/pack/config" "github.com/pkg/errors" "github.com/spf13/cobra" "github.com/buildpacks/pack" + "github.com/buildpacks/pack/internal/config" + pubbldpkg "github.com/buildpacks/pack/buildpackage" "github.com/buildpacks/pack/internal/style" "github.com/buildpacks/pack/logging" @@ -18,6 +20,7 @@ import ( type PackageBuildpackFlags struct { PackageTomlPath string Format string + OS string Publish bool NoPull bool Policy string @@ -34,7 +37,7 @@ type PackageConfigReader interface { } // PackageBuildpack packages (a) buildpack(s) into OCI format, based on a package config -func PackageBuildpack(logger logging.Logger, client BuildpackPackager, packageConfigReader PackageConfigReader) *cobra.Command { +func PackageBuildpack(logger logging.Logger, cfg config.Config, client BuildpackPackager, packageConfigReader PackageConfigReader) *cobra.Command { var flags PackageBuildpackFlags cmd := &cobra.Command{ @@ -42,12 +45,12 @@ func PackageBuildpack(logger logging.Logger, client BuildpackPackager, packageCo Short: "Package buildpack in OCI format.", Args: cobra.ExactValidArgs(1), RunE: logError(logger, func(cmd *cobra.Command, args []string) error { - if err := validatePackageBuildpackFlags(&flags, logger); err != nil { + if err := validatePackageBuildpackFlags(&flags, cfg, logger); err != nil { return err } var err error - pullPolicy, err := config.ParsePullPolicy(flags.Policy) + pullPolicy, err := pubcfg.ParsePullPolicy(flags.Policy) if err != nil { return errors.Wrap(err, "parsing pull policy") } @@ -56,7 +59,7 @@ func PackageBuildpack(logger logging.Logger, client BuildpackPackager, packageCo logger.Warn("Flag --package-config has been deprecated, please use --config instead") } - config, err := packageConfigReader.Read(flags.PackageTomlPath) + cfg, err := packageConfigReader.Read(flags.PackageTomlPath) if err != nil { return errors.Wrap(err, "reading config") } @@ -65,7 +68,8 @@ func PackageBuildpack(logger logging.Logger, client BuildpackPackager, packageCo if err := client.PackageBuildpack(cmd.Context(), pack.PackageBuildpackOptions{ Name: name, Format: flags.Format, - Config: config, + OS: flags.OS, + Config: cfg, Publish: flags.Publish, PullPolicy: pullPolicy, }); err != nil { @@ -84,7 +88,11 @@ func PackageBuildpack(logger logging.Logger, client BuildpackPackager, packageCo cmd.Flags().StringVarP(&flags.PackageTomlPath, "config", "c", "", "Path to package TOML config (required)") cmd.Flags().StringVarP(&flags.Format, "format", "f", "", `Format to save package as ("image" or "file")`) - cmd.Flags().BoolVar(&flags.Publish, "publish", false, `Publish to registry (applies to "--image" only)`) + cmd.Flags().BoolVar(&flags.Publish, "publish", false, `Publish to registry (applies to "--format=image" only)`) + cmd.Flags().StringVar(&flags.OS, "os", "", `Operating system format of the package OCI image: "linux" or "windows" (defaults to "linux", except local images which use the daemon OS)`) + if !cfg.Experimental { + cmd.Flags().MarkHidden("os") + } cmd.Flags().StringVar(&flags.Policy, "pull-policy", "", "Pull policy to use. Accepted values are always, never, and if-not-present. The default is always") // TODO: Remove --no-pull flag after v0.13.0 released. See https://github.com/buildpacks/pack/issues/775 cmd.Flags().BoolVar(&flags.NoPull, "no-pull", false, "Skip pulling packages before use") @@ -94,8 +102,8 @@ func PackageBuildpack(logger logging.Logger, client BuildpackPackager, packageCo return cmd } -func validatePackageBuildpackFlags(p *PackageBuildpackFlags, logger logging.Logger) error { - if p.Publish && p.Policy == config.PullNever.String() { +func validatePackageBuildpackFlags(p *PackageBuildpackFlags, cfg config.Config, logger logging.Logger) error { + if p.Publish && p.Policy == pubcfg.PullNever.String() { return errors.Errorf("--publish and --pull-policy never cannot be used together. The --publish flag requires the use of remote images.") } @@ -113,9 +121,13 @@ func validatePackageBuildpackFlags(p *PackageBuildpackFlags, logger logging.Logg if p.Policy != "" { logger.Warn("Flag --no-pull ignored in favor of --pull-policy") } else { - p.Policy = config.PullNever.String() + p.Policy = pubcfg.PullNever.String() } } + if p.OS != "" && !cfg.Experimental { + return pack.NewExperimentError("Support for OS flag is currently experimental.") + } + return nil } diff --git a/internal/commands/package_buildpack_test.go b/internal/commands/package_buildpack_test.go index d4880d865..0d470164c 100644 --- a/internal/commands/package_buildpack_test.go +++ b/internal/commands/package_buildpack_test.go @@ -5,7 +5,9 @@ import ( "fmt" "testing" - "github.com/buildpacks/pack/config" + "github.com/buildpacks/pack/internal/config" + + pubcfg "github.com/buildpacks/pack/config" "github.com/heroku/color" "github.com/pkg/errors" @@ -32,17 +34,17 @@ func testPackageBuildpackCommand(t *testing.T, when spec.G, it spec.S) { when("valid package config", func() { it("reads package config from the configured path", func() { fakePackageConfigReader := fakes.NewFakePackageConfigReader() - expectedConfigPath := "/path/to/some/file" + expectedPackageConfigPath := "/path/to/some/file" packageBuildpackCommand := packageBuildpackCommand( - withConfigReader(fakePackageConfigReader), - withConfigPath(expectedConfigPath), + withPackageConfigReader(fakePackageConfigReader), + withPackageConfigPath(expectedPackageConfigPath), ) err := packageBuildpackCommand.Execute() h.AssertNil(t, err) - h.AssertEq(t, fakePackageConfigReader.ReadCalledWithArg, expectedConfigPath) + h.AssertEq(t, fakePackageConfigReader.ReadCalledWithArg, expectedPackageConfigPath) }) it("creates package with correct image name", func() { @@ -70,7 +72,7 @@ func testPackageBuildpackCommand(t *testing.T, when spec.G, it spec.S) { packageBuildpackCommand := packageBuildpackCommand( withBuildpackPackager(fakeBuildpackPackager), - withConfigReader(fakes.NewFakePackageConfigReader(whereReadReturns(myConfig, nil))), + withPackageConfigReader(fakes.NewFakePackageConfigReader(whereReadReturns(myConfig, nil))), ) err := packageBuildpackCommand.Execute() @@ -109,7 +111,7 @@ func testPackageBuildpackCommand(t *testing.T, when spec.G, it spec.S) { h.AssertNil(t, err) receivedOptions := fakeBuildpackPackager.CreateCalledWithOptions - h.AssertEq(t, receivedOptions.PullPolicy, config.PullNever) + h.AssertEq(t, receivedOptions.PullPolicy, pubcfg.PullNever) }) when("used together with --pull-policy always", func() { @@ -125,7 +127,7 @@ func testPackageBuildpackCommand(t *testing.T, when spec.G, it spec.S) { h.AssertContains(t, output, "Flag --no-pull ignored in favor of --pull-policy") receivedOptions := fakeBuildpackPackager.CreateCalledWithOptions - h.AssertEq(t, receivedOptions.PullPolicy, config.PullAlways) + h.AssertEq(t, receivedOptions.PullPolicy, pubcfg.PullAlways) }) }) @@ -142,7 +144,7 @@ func testPackageBuildpackCommand(t *testing.T, when spec.G, it spec.S) { h.AssertContains(t, output, "Flag --no-pull ignored in favor of --pull-policy") receivedOptions := fakeBuildpackPackager.CreateCalledWithOptions - h.AssertEq(t, receivedOptions.PullPolicy, config.PullNever) + h.AssertEq(t, receivedOptions.PullPolicy, pubcfg.PullNever) }) }) }) @@ -174,7 +176,7 @@ func testPackageBuildpackCommand(t *testing.T, when spec.G, it spec.S) { h.AssertNil(t, err) receivedOptions := fakeBuildpackPackager.CreateCalledWithOptions - h.AssertEq(t, receivedOptions.PullPolicy, config.PullNever) + h.AssertEq(t, receivedOptions.PullPolicy, pubcfg.PullNever) }) it("pull-policy=always sets policy", func() { @@ -185,7 +187,35 @@ func testPackageBuildpackCommand(t *testing.T, when spec.G, it spec.S) { h.AssertNil(t, err) receivedOptions := fakeBuildpackPackager.CreateCalledWithOptions - h.AssertEq(t, receivedOptions.PullPolicy, config.PullAlways) + h.AssertEq(t, receivedOptions.PullPolicy, pubcfg.PullAlways) + }) + }) + + when("--os", func() { + when("experimental enabled", func() { + it("creates package with correct image name and os", func() { + fakeBuildpackPackager := &fakes.FakeBuildpackPackager{} + + packageBuildpackCommand := packageBuildpackCommand( + withBuildpackPackager(fakeBuildpackPackager), + withExperimental(), + ) + + packageBuildpackCommand.SetArgs( + []string{ + "some-image-name", + "--config", "/path/to/some/file", + "--os", "windows", + }, + ) + + err := packageBuildpackCommand.Execute() + h.AssertNil(t, err) + + receivedOptions := fakeBuildpackPackager.CreateCalledWithOptions + + h.AssertEq(t, receivedOptions.OS, "windows") + }) }) }) }) @@ -197,8 +227,9 @@ func testPackageBuildpackCommand(t *testing.T, when spec.G, it spec.S) { logger := logging.NewLogWithWriters(&bytes.Buffer{}, &bytes.Buffer{}) configReader := fakes.NewFakePackageConfigReader() buildpackPackager := &fakes.FakeBuildpackPackager{} + clientConfig := config.Config{} - command := commands.PackageBuildpack(logger, buildpackPackager, configReader) + command := commands.PackageBuildpack(logger, clientConfig, buildpackPackager, configReader) command.SetArgs([]string{ "some-image-name", "--config", "/path/to/some/file", @@ -217,8 +248,9 @@ func testPackageBuildpackCommand(t *testing.T, when spec.G, it spec.S) { logger := logging.NewLogWithWriters(&bytes.Buffer{}, &bytes.Buffer{}) configReader := fakes.NewFakePackageConfigReader() buildpackPackager := &fakes.FakeBuildpackPackager{} + clientConfig := config.Config{} - command := commands.PackageBuildpack(logger, buildpackPackager, configReader) + command := commands.PackageBuildpack(logger, clientConfig, buildpackPackager, configReader) command.SetArgs([]string{ "some-image-name", "--config", "/path/to/some/file", @@ -239,7 +271,7 @@ func testPackageBuildpackCommand(t *testing.T, when spec.G, it spec.S) { packageBuildpackCommand := packageBuildpackCommand( withLogger(logging.NewLogWithWriters(outBuf, outBuf)), - withConfigReader( + withPackageConfigReader( fakes.NewFakePackageConfigReader(whereReadReturns(pubbldpkg.Config{}, expectedErr)), ), ) @@ -255,15 +287,15 @@ func testPackageBuildpackCommand(t *testing.T, when spec.G, it spec.S) { outBuf := &bytes.Buffer{} config := &packageCommandConfig{ - logger: logging.NewLogWithWriters(outBuf, outBuf), - configReader: fakes.NewFakePackageConfigReader(), - buildpackPackager: &fakes.FakeBuildpackPackager{}, + logger: logging.NewLogWithWriters(outBuf, outBuf), + packageConfigReader: fakes.NewFakePackageConfigReader(), + buildpackPackager: &fakes.FakeBuildpackPackager{}, imageName: "some-image-name", configPath: "/path/to/some/file", } - cmd := commands.PackageBuildpack(config.logger, config.buildpackPackager, config.configReader) + cmd := commands.PackageBuildpack(config.logger, config.clientConfig, config.buildpackPackager, config.packageConfigReader) cmd.SetArgs([]string{config.imageName, "--package-config", config.configPath}) err := cmd.Execute() @@ -274,14 +306,14 @@ func testPackageBuildpackCommand(t *testing.T, when spec.G, it spec.S) { when("no config path is specified", func() { it("errors with a descriptive message", func() { config := &packageCommandConfig{ - logger: logging.NewLogWithWriters(&bytes.Buffer{}, &bytes.Buffer{}), - configReader: fakes.NewFakePackageConfigReader(), - buildpackPackager: &fakes.FakeBuildpackPackager{}, + logger: logging.NewLogWithWriters(&bytes.Buffer{}, &bytes.Buffer{}), + packageConfigReader: fakes.NewFakePackageConfigReader(), + buildpackPackager: &fakes.FakeBuildpackPackager{}, imageName: "some-image-name", } - cmd := commands.PackageBuildpack(config.logger, config.buildpackPackager, config.configReader) + cmd := commands.PackageBuildpack(config.logger, config.clientConfig, config.buildpackPackager, config.packageConfigReader) cmd.SetArgs([]string{config.imageName}) err := cmd.Execute() @@ -294,8 +326,9 @@ func testPackageBuildpackCommand(t *testing.T, when spec.G, it spec.S) { logger := logging.NewLogWithWriters(&bytes.Buffer{}, &bytes.Buffer{}) configReader := fakes.NewFakePackageConfigReader() buildpackPackager := &fakes.FakeBuildpackPackager{} + clientConfig := config.Config{} - command := commands.PackageBuildpack(logger, buildpackPackager, configReader) + command := commands.PackageBuildpack(logger, clientConfig, buildpackPackager, configReader) command.SetArgs([]string{ "some-image-name", "--config", "/path/to/some/file", @@ -306,13 +339,36 @@ func testPackageBuildpackCommand(t *testing.T, when spec.G, it spec.S) { h.AssertError(t, command.Execute(), "parsing pull policy") }) }) + + when("--os flag is specified but experimental isn't set in the config", func() { + it("errors with a descriptive message", func() { + fakeBuildpackPackager := &fakes.FakeBuildpackPackager{} + + packageBuildpackCommand := packageBuildpackCommand( + withBuildpackPackager(fakeBuildpackPackager), + ) + + packageBuildpackCommand.SetArgs( + []string{ + "some-image-name", + "--config", "/path/to/some/file", + "--os", "windows", + }, + ) + + err := packageBuildpackCommand.Execute() + h.AssertNotNil(t, err) + h.AssertError(t, err, "Support for OS flag is currently experimental") + }) + }) }) } type packageCommandConfig struct { - logger *logging.LogWithWriters - configReader *fakes.FakePackageConfigReader - buildpackPackager *fakes.FakeBuildpackPackager + logger *logging.LogWithWriters + packageConfigReader *fakes.FakePackageConfigReader + buildpackPackager *fakes.FakeBuildpackPackager + clientConfig config.Config imageName string configPath string @@ -322,9 +378,10 @@ type packageCommandOption func(config *packageCommandConfig) func packageBuildpackCommand(ops ...packageCommandOption) *cobra.Command { config := &packageCommandConfig{ - logger: logging.NewLogWithWriters(&bytes.Buffer{}, &bytes.Buffer{}), - configReader: fakes.NewFakePackageConfigReader(), - buildpackPackager: &fakes.FakeBuildpackPackager{}, + logger: logging.NewLogWithWriters(&bytes.Buffer{}, &bytes.Buffer{}), + packageConfigReader: fakes.NewFakePackageConfigReader(), + buildpackPackager: &fakes.FakeBuildpackPackager{}, + clientConfig: config.Config{}, imageName: "some-image-name", configPath: "/path/to/some/file", @@ -334,7 +391,7 @@ func packageBuildpackCommand(ops ...packageCommandOption) *cobra.Command { op(config) } - cmd := commands.PackageBuildpack(config.logger, config.buildpackPackager, config.configReader) + cmd := commands.PackageBuildpack(config.logger, config.clientConfig, config.buildpackPackager, config.packageConfigReader) cmd.SetArgs([]string{config.imageName, "--config", config.configPath}) return cmd @@ -346,9 +403,9 @@ func withLogger(logger *logging.LogWithWriters) packageCommandOption { } } -func withConfigReader(reader *fakes.FakePackageConfigReader) packageCommandOption { +func withPackageConfigReader(reader *fakes.FakePackageConfigReader) packageCommandOption { return func(config *packageCommandConfig) { - config.configReader = reader + config.packageConfigReader = reader } } @@ -364,12 +421,18 @@ func withImageName(name string) packageCommandOption { } } -func withConfigPath(path string) packageCommandOption { +func withPackageConfigPath(path string) packageCommandOption { return func(config *packageCommandConfig) { config.configPath = path } } +func withExperimental() packageCommandOption { + return func(config *packageCommandConfig) { + config.clientConfig.Experimental = true + } +} + func whereReadReturns(config pubbldpkg.Config, err error) func(*fakes.FakePackageConfigReader) { return func(r *fakes.FakePackageConfigReader) { r.ReadReturnConfig = config diff --git a/package_buildpack.go b/package_buildpack.go index f4fe76f72..1bd9a0a70 100644 --- a/package_buildpack.go +++ b/package_buildpack.go @@ -3,11 +3,11 @@ package pack import ( "context" + "github.com/pkg/errors" + "github.com/buildpacks/pack/config" "github.com/buildpacks/pack/internal/layer" - "github.com/pkg/errors" - pubbldpkg "github.com/buildpacks/pack/buildpackage" "github.com/buildpacks/pack/internal/buildpackage" "github.com/buildpacks/pack/internal/dist" @@ -31,6 +31,9 @@ type PackageBuildpackOptions struct { // Type of output format, The options are the either the const FormatImage, or FormatFile. Format string + // Type of OCI image to generate in the image or file. The options are "windows" or "linux" + OS string + // Defines the Buildpacks configuration. Config pubbldpkg.Config @@ -44,22 +47,30 @@ type PackageBuildpackOptions struct { // PackageBuildpack packages buildpack(s) into either an image or file. func (c *Client) PackageBuildpack(ctx context.Context, opts PackageBuildpackOptions) error { - info, err := c.docker.Info(ctx) - if err != nil { - return errors.Wrap(err, "getting docker info") + if opts.Format == "" { + opts.Format = FormatImage + } + + if opts.OS == "" { + osType, err := c.defaultOSType(ctx, opts.Publish, opts.Format) + if err != nil { + return errors.Wrap(err, "daemon OS cannot be detected") + } + + opts.OS = osType + } + + if opts.OS == "windows" && !c.experimental { + return NewExperimentError("Windows buildpackage support is currently experimental.") } - writerFactory, err := layer.NewWriterFactory(info.OSType) + writerFactory, err := layer.NewWriterFactory(opts.OS) if err != nil { return errors.Wrap(err, "creating layer writer factory") } packageBuilder := buildpackage.NewBuilder(c.imageFactory) - if opts.Format == "" { - opts.Format = FormatImage - } - bpURI := opts.Config.Buildpack.URI if bpURI == "" { return errors.New("buildpack URI must be provided") @@ -121,11 +132,26 @@ func (c *Client) PackageBuildpack(ctx context.Context, opts PackageBuildpackOpti switch opts.Format { case FormatFile: - return packageBuilder.SaveAsFile(opts.Name, info.OSType) + return packageBuilder.SaveAsFile(opts.Name, opts.OS) case FormatImage: - _, err = packageBuilder.SaveAsImage(opts.Name, opts.Publish, info.OSType) + _, err = packageBuilder.SaveAsImage(opts.Name, opts.Publish, opts.OS) return errors.Wrapf(err, "saving image") default: return errors.Errorf("unknown format: %s", style.Symbol(opts.Format)) } } + +func (c *Client) defaultOSType(ctx context.Context, publish bool, format string) (string, error) { + if publish || format == FormatFile { + c.logger.Warnf(`buildpackage OS unspecified - defaulting to "linux"`) + + return "linux", nil + } + + info, err := c.docker.Info(ctx) + if err != nil { + return "", err + } + + return info.OSType, nil +} diff --git a/package_buildpack_test.go b/package_buildpack_test.go index 8c634b682..79e46ff45 100644 --- a/package_buildpack_test.go +++ b/package_buildpack_test.go @@ -11,7 +11,7 @@ import ( "github.com/docker/docker/api/types" - "github.com/buildpacks/pack/config" + pubcfg "github.com/buildpacks/pack/config" "github.com/buildpacks/imgutil" "github.com/buildpacks/imgutil/fakes" @@ -66,8 +66,6 @@ func testPackageBuildpack(t *testing.T, when spec.G, it spec.S) { pack.WithDockerClient(mockDockerClient), ) h.AssertNil(t, err) - - mockDockerClient.EXPECT().Info(context.TODO()).Return(types.Info{OSType: "linux"}, nil).AnyTimes() }) it.After(func() { @@ -136,6 +134,8 @@ func testPackageBuildpack(t *testing.T, when spec.G, it spec.S) { dependencyPath := "fakePath.file" mockDownloader.EXPECT().Download(gomock.Any(), dependencyPath).Return(blob.NewBlob("no-file.txt"), nil).AnyTimes() + mockDockerClient.EXPECT().Info(context.TODO()).Return(types.Info{OSType: "linux"}, nil).AnyTimes() + packageDescriptor := dist.BuildpackDescriptor{ API: api.MustParse("0.2"), Info: dist.BuildpackInfo{ID: "bp.1", Version: "1.2.3"}, @@ -154,7 +154,7 @@ func testPackageBuildpack(t *testing.T, when spec.G, it spec.S) { Dependencies: []dist.ImageOrURI{{BuildpackURI: dist.BuildpackURI{URI: dependencyPath}}}, }, Publish: false, - PullPolicy: config.PullAlways, + PullPolicy: pubcfg.PullAlways, }) h.AssertError(t, err, "inspecting buildpack blob") @@ -163,6 +163,61 @@ func testPackageBuildpack(t *testing.T, when spec.G, it spec.S) { }) when("FormatImage", func() { + when("simple package for both OS formats (experimental only)", func() { + it("creates package image based on daemon OS", func() { + for _, daemonOS := range []string{"linux", "windows"} { + localMockDockerClient := testmocks.NewMockCommonAPIClient(mockController) + localMockDockerClient.EXPECT().Info(context.TODO()).Return(types.Info{OSType: daemonOS}, nil).AnyTimes() + + packClientWithExperimental, err := pack.NewClient( + pack.WithDockerClient(localMockDockerClient), + pack.WithDownloader(mockDownloader), + pack.WithImageFactory(mockImageFactory), + pack.WithExperimental(true), + ) + h.AssertNil(t, err) + + fakeImage := fakes.NewImage("basic/package-"+h.RandString(12), "", nil) + mockImageFactory.EXPECT().NewImage(fakeImage.Name(), true).Return(fakeImage, nil) + + fakeBlob := blob.NewBlob(filepath.Join("testdata", "empty-file")) + bpURL := fmt.Sprintf("https://example.com/bp.%s.tgz", h.RandString(12)) + mockDownloader.EXPECT().Download(gomock.Any(), bpURL).Return(fakeBlob, nil).AnyTimes() + + h.AssertNil(t, packClientWithExperimental.PackageBuildpack(context.TODO(), pack.PackageBuildpackOptions{ + Format: pack.FormatImage, + Name: fakeImage.Name(), + Config: pubbldpkg.Config{ + Buildpack: dist.BuildpackURI{URI: createBuildpack(dist.BuildpackDescriptor{ + API: api.MustParse("0.2"), + Info: dist.BuildpackInfo{ID: "bp.basic", Version: "2.3.4"}, + Stacks: []dist.Stack{{ID: "some.stack.id"}}, + })}, + }, + PullPolicy: pubcfg.PullNever, + })) + + actualImageOS, err := fakeImage.OS() + h.AssertNil(t, err) + h.AssertEq(t, actualImageOS, daemonOS) + } + }) + + it("fails without experimental on Windows daemons", func() { + windowsMockDockerClient := testmocks.NewMockCommonAPIClient(mockController) + windowsMockDockerClient.EXPECT().Info(context.TODO()).Return(types.Info{OSType: "windows"}, nil).AnyTimes() + + packClientWithoutExperimental, err := pack.NewClient( + pack.WithDockerClient(windowsMockDockerClient), + pack.WithExperimental(false), + ) + h.AssertNil(t, err) + + err = packClientWithoutExperimental.PackageBuildpack(context.TODO(), pack.PackageBuildpackOptions{}) + h.AssertError(t, err, "Windows buildpackage support is currently experimental.") + }) + }) + when("nested package lives in registry", func() { var nestedPackage *fakes.Image @@ -170,6 +225,8 @@ func testPackageBuildpack(t *testing.T, when spec.G, it spec.S) { nestedPackage = fakes.NewImage("nested/package-"+h.RandString(12), "", nil) mockImageFactory.EXPECT().NewImage(nestedPackage.Name(), false).Return(nestedPackage, nil) + mockDockerClient.EXPECT().Info(context.TODO()).Return(types.Info{OSType: "linux"}, nil).AnyTimes() + h.AssertNil(t, subject.PackageBuildpack(context.TODO(), pack.PackageBuildpackOptions{ Name: nestedPackage.Name(), Config: pubbldpkg.Config{ @@ -180,15 +237,15 @@ func testPackageBuildpack(t *testing.T, when spec.G, it spec.S) { })}, }, Publish: true, - PullPolicy: config.PullAlways, + PullPolicy: pubcfg.PullAlways, })) }) - shouldFetchNestedPackage := func(demon bool, pull config.PullPolicy) { + shouldFetchNestedPackage := func(demon bool, pull pubcfg.PullPolicy) { mockImageFetcher.EXPECT().Fetch(gomock.Any(), nestedPackage.Name(), demon, pull).Return(nestedPackage, nil) } - shouldNotFindNestedPackageWhenCallingImageFetcherWith := func(demon bool, pull config.PullPolicy) { + shouldNotFindNestedPackageWhenCallingImageFetcherWith := func(demon bool, pull pubcfg.PullPolicy) { mockImageFetcher.EXPECT().Fetch(gomock.Any(), nestedPackage.Name(), demon, pull).Return(nil, image.ErrNotFound) } @@ -206,7 +263,7 @@ func testPackageBuildpack(t *testing.T, when spec.G, it spec.S) { when("publish=false and no-pull=false", func() { it("should pull and use local nested package image", func() { - shouldFetchNestedPackage(true, config.PullAlways) + shouldFetchNestedPackage(true, pubcfg.PullAlways) packageImage := shouldCreateLocalPackage() h.AssertNil(t, subject.PackageBuildpack(context.TODO(), pack.PackageBuildpackOptions{ @@ -225,14 +282,14 @@ func testPackageBuildpack(t *testing.T, when spec.G, it spec.S) { Dependencies: []dist.ImageOrURI{{ImageRef: dist.ImageRef{ImageName: nestedPackage.Name()}}}, }, Publish: false, - PullPolicy: config.PullAlways, + PullPolicy: pubcfg.PullAlways, })) }) }) when("publish=true and no-pull=false", func() { it("should use remote nested package image", func() { - shouldFetchNestedPackage(false, config.PullAlways) + shouldFetchNestedPackage(false, pubcfg.PullAlways) packageImage := shouldCreateRemotePackage() h.AssertNil(t, subject.PackageBuildpack(context.TODO(), pack.PackageBuildpackOptions{ @@ -251,14 +308,14 @@ func testPackageBuildpack(t *testing.T, when spec.G, it spec.S) { Dependencies: []dist.ImageOrURI{{ImageRef: dist.ImageRef{ImageName: nestedPackage.Name()}}}, }, Publish: true, - PullPolicy: config.PullAlways, + PullPolicy: pubcfg.PullAlways, })) }) }) when("publish=true and pull-policy=never", func() { it("should push to registry and not pull nested package image", func() { - shouldFetchNestedPackage(false, config.PullNever) + shouldFetchNestedPackage(false, pubcfg.PullNever) packageImage := shouldCreateRemotePackage() h.AssertNil(t, subject.PackageBuildpack(context.TODO(), pack.PackageBuildpackOptions{ @@ -277,14 +334,14 @@ func testPackageBuildpack(t *testing.T, when spec.G, it spec.S) { Dependencies: []dist.ImageOrURI{{ImageRef: dist.ImageRef{ImageName: nestedPackage.Name()}}}, }, Publish: true, - PullPolicy: config.PullNever, + PullPolicy: pubcfg.PullNever, })) }) }) when("publish=false pull-policy=never and there is no local image", func() { it("should fail without trying to retrieve nested image from registry", func() { - shouldNotFindNestedPackageWhenCallingImageFetcherWith(true, config.PullNever) + shouldNotFindNestedPackageWhenCallingImageFetcherWith(true, pubcfg.PullNever) h.AssertError(t, subject.PackageBuildpack(context.TODO(), pack.PackageBuildpackOptions{ Name: "some/package", @@ -297,7 +354,7 @@ func testPackageBuildpack(t *testing.T, when spec.G, it spec.S) { Dependencies: []dist.ImageOrURI{{ImageRef: dist.ImageRef{ImageName: nestedPackage.Name()}}}, }, Publish: false, - PullPolicy: config.PullNever, + PullPolicy: pubcfg.PullNever, }), "not found") }) }) @@ -306,7 +363,9 @@ func testPackageBuildpack(t *testing.T, when spec.G, it spec.S) { when("nested package is not a valid package", func() { it("should error", func() { notPackageImage := fakes.NewImage("not/package", "", nil) - mockImageFetcher.EXPECT().Fetch(gomock.Any(), notPackageImage.Name(), true, config.PullAlways).Return(notPackageImage, nil) + mockImageFetcher.EXPECT().Fetch(gomock.Any(), notPackageImage.Name(), true, pubcfg.PullAlways).Return(notPackageImage, nil) + + mockDockerClient.EXPECT().Info(context.TODO()).Return(types.Info{OSType: "linux"}, nil).AnyTimes() h.AssertError(t, subject.PackageBuildpack(context.TODO(), pack.PackageBuildpackOptions{ Name: "some/package", @@ -319,233 +378,277 @@ func testPackageBuildpack(t *testing.T, when spec.G, it spec.S) { Dependencies: []dist.ImageOrURI{{ImageRef: dist.ImageRef{ImageName: notPackageImage.Name()}}}, }, Publish: false, - PullPolicy: config.PullAlways, + PullPolicy: pubcfg.PullAlways, }), "extracting buildpacks from 'not/package': could not find label 'io.buildpacks.buildpackage.metadata'") }) }) }) when("FormatFile", func() { - var ( - nestedPackage *fakes.Image - childDescriptor dist.BuildpackDescriptor - packageDescriptor dist.BuildpackDescriptor - tmpDir string - err error - ) + when("simple package for both OS formats (experimental only)", func() { + it("creates package image in either OS format", func() { + tmpDir, err := ioutil.TempDir("", "package-buildpack") + h.AssertNil(t, err) + defer os.Remove(tmpDir) + + for _, imageOS := range []string{"linux", "windows"} { + localMockDockerClient := testmocks.NewMockCommonAPIClient(mockController) + localMockDockerClient.EXPECT().Info(context.TODO()).Return(types.Info{OSType: imageOS}, nil).AnyTimes() + + packClientWithExperimental, err := pack.NewClient( + pack.WithDockerClient(localMockDockerClient), + pack.WithLogger(logging.NewLogWithWriters(&out, &out)), + pack.WithDownloader(mockDownloader), + pack.WithExperimental(true), + ) + h.AssertNil(t, err) - it.Before(func() { - childDescriptor = dist.BuildpackDescriptor{ - API: api.MustParse("0.2"), - Info: dist.BuildpackInfo{ID: "bp.nested", Version: "2.3.4"}, - Stacks: []dist.Stack{{ID: "some.stack.id"}}, - } - - packageDescriptor = dist.BuildpackDescriptor{ - API: api.MustParse("0.2"), - Info: dist.BuildpackInfo{ID: "bp.1", Version: "1.2.3"}, - Order: dist.Order{{ - Group: []dist.BuildpackRef{{ - BuildpackInfo: dist.BuildpackInfo{ID: "bp.nested", Version: "2.3.4"}, - Optional: false, - }}, - }}, - } + fakeBlob := blob.NewBlob(filepath.Join("testdata", "empty-file")) + bpURL := fmt.Sprintf("https://example.com/bp.%s.tgz", h.RandString(12)) + mockDownloader.EXPECT().Download(gomock.Any(), bpURL).Return(fakeBlob, nil).AnyTimes() - tmpDir, err = ioutil.TempDir("", "package-buildpack") - h.AssertNil(t, err) + packagePath := filepath.Join(tmpDir, h.RandString(12)+"-test.cnb") + h.AssertNil(t, packClientWithExperimental.PackageBuildpack(context.TODO(), pack.PackageBuildpackOptions{ + Format: pack.FormatFile, + Name: packagePath, + OS: imageOS, + Config: pubbldpkg.Config{ + Buildpack: dist.BuildpackURI{URI: createBuildpack(dist.BuildpackDescriptor{ + API: api.MustParse("0.2"), + Info: dist.BuildpackInfo{ID: "bp.basic", Version: "2.3.4"}, + Stacks: []dist.Stack{{ID: "some.stack.id"}}, + })}, + }, + PullPolicy: pubcfg.PullNever, + })) + } + }) }) - it.After(func() { - h.AssertNil(t, os.RemoveAll(tmpDir)) - }) + when("nested package", func() { + var ( + nestedPackage *fakes.Image + childDescriptor dist.BuildpackDescriptor + packageDescriptor dist.BuildpackDescriptor + tmpDir string + err error + ) - when("dependencies are packaged buildpack image", func() { it.Before(func() { - nestedPackage = fakes.NewImage("nested/package-"+h.RandString(12), "", nil) - mockImageFactory.EXPECT().NewImage(nestedPackage.Name(), false).Return(nestedPackage, nil) + childDescriptor = dist.BuildpackDescriptor{ + API: api.MustParse("0.2"), + Info: dist.BuildpackInfo{ID: "bp.nested", Version: "2.3.4"}, + Stacks: []dist.Stack{{ID: "some.stack.id"}}, + } - h.AssertNil(t, subject.PackageBuildpack(context.TODO(), pack.PackageBuildpackOptions{ - Name: nestedPackage.Name(), - Config: pubbldpkg.Config{ - Buildpack: dist.BuildpackURI{URI: createBuildpack(childDescriptor)}, - }, - Publish: true, - PullPolicy: config.PullAlways, - })) + packageDescriptor = dist.BuildpackDescriptor{ + API: api.MustParse("0.2"), + Info: dist.BuildpackInfo{ID: "bp.1", Version: "1.2.3"}, + Order: dist.Order{{ + Group: []dist.BuildpackRef{{ + BuildpackInfo: dist.BuildpackInfo{ID: "bp.nested", Version: "2.3.4"}, + Optional: false, + }}, + }}, + } - mockImageFetcher.EXPECT().Fetch(gomock.Any(), nestedPackage.Name(), true, config.PullAlways).Return(nestedPackage, nil) + tmpDir, err = ioutil.TempDir("", "package-buildpack") + h.AssertNil(t, err) }) - it("should pull and use local nested package image", func() { - packagePath := filepath.Join(tmpDir, "test.cnb") - - h.AssertNil(t, subject.PackageBuildpack(context.TODO(), pack.PackageBuildpackOptions{ - Name: packagePath, - Config: pubbldpkg.Config{ - Buildpack: dist.BuildpackURI{URI: createBuildpack(packageDescriptor)}, - Dependencies: []dist.ImageOrURI{{ImageRef: dist.ImageRef{ImageName: nestedPackage.Name()}}}, - }, - Publish: false, - PullPolicy: config.PullAlways, - Format: pack.FormatFile, - })) - - assertPackageBPFileHasBuildpacks(t, packagePath, []dist.BuildpackDescriptor{packageDescriptor, childDescriptor}) + it.After(func() { + h.AssertNil(t, os.RemoveAll(tmpDir)) }) - }) - - when("dependencies are unpackaged buildpack", func() { - it("should work", func() { - packagePath := filepath.Join(tmpDir, "test.cnb") - h.AssertNil(t, subject.PackageBuildpack(context.TODO(), pack.PackageBuildpackOptions{ - Name: packagePath, - Config: pubbldpkg.Config{ - Buildpack: dist.BuildpackURI{URI: createBuildpack(packageDescriptor)}, - Dependencies: []dist.ImageOrURI{{BuildpackURI: dist.BuildpackURI{URI: createBuildpack(childDescriptor)}}}, - }, - Publish: false, - PullPolicy: config.PullAlways, - Format: pack.FormatFile, - })) + when("dependencies are packaged buildpack image", func() { + it.Before(func() { + nestedPackage = fakes.NewImage("nested/package-"+h.RandString(12), "", nil) + mockImageFactory.EXPECT().NewImage(nestedPackage.Name(), false).Return(nestedPackage, nil) - assertPackageBPFileHasBuildpacks(t, packagePath, []dist.BuildpackDescriptor{packageDescriptor, childDescriptor}) - }) + h.AssertNil(t, subject.PackageBuildpack(context.TODO(), pack.PackageBuildpackOptions{ + Name: nestedPackage.Name(), + Config: pubbldpkg.Config{ + Buildpack: dist.BuildpackURI{URI: createBuildpack(childDescriptor)}, + }, + Publish: true, + PullPolicy: pubcfg.PullAlways, + })) - when("dependency download fails", func() { - it("should error", func() { - bpURL := fmt.Sprintf("https://example.com/bp.%s.tgz", h.RandString(12)) - mockDownloader.EXPECT().Download(gomock.Any(), bpURL).Return(nil, image.ErrNotFound).AnyTimes() + mockImageFetcher.EXPECT().Fetch(gomock.Any(), nestedPackage.Name(), true, pubcfg.PullAlways).Return(nestedPackage, nil) + }) + it("should pull and use local nested package image", func() { packagePath := filepath.Join(tmpDir, "test.cnb") - err = subject.PackageBuildpack(context.TODO(), pack.PackageBuildpackOptions{ + h.AssertNil(t, subject.PackageBuildpack(context.TODO(), pack.PackageBuildpackOptions{ Name: packagePath, Config: pubbldpkg.Config{ Buildpack: dist.BuildpackURI{URI: createBuildpack(packageDescriptor)}, - Dependencies: []dist.ImageOrURI{{BuildpackURI: dist.BuildpackURI{URI: bpURL}}}, + Dependencies: []dist.ImageOrURI{{ImageRef: dist.ImageRef{ImageName: nestedPackage.Name()}}}, }, Publish: false, - PullPolicy: config.PullAlways, + PullPolicy: pubcfg.PullAlways, Format: pack.FormatFile, - }) - h.AssertError(t, err, "downloading buildpack") + })) + + assertPackageBPFileHasBuildpacks(t, packagePath, []dist.BuildpackDescriptor{packageDescriptor, childDescriptor}) }) }) - when("dependency isn't a valid buildpack", func() { - it("should error", func() { - fakeBlob := blob.NewBlob(filepath.Join("testdata", "empty-file")) - bpURL := fmt.Sprintf("https://example.com/bp.%s.tgz", h.RandString(12)) - mockDownloader.EXPECT().Download(gomock.Any(), bpURL).Return(fakeBlob, nil).AnyTimes() - + when("dependencies are unpackaged buildpack", func() { + it("should work", func() { packagePath := filepath.Join(tmpDir, "test.cnb") - err = subject.PackageBuildpack(context.TODO(), pack.PackageBuildpackOptions{ + h.AssertNil(t, subject.PackageBuildpack(context.TODO(), pack.PackageBuildpackOptions{ Name: packagePath, Config: pubbldpkg.Config{ Buildpack: dist.BuildpackURI{URI: createBuildpack(packageDescriptor)}, - Dependencies: []dist.ImageOrURI{{BuildpackURI: dist.BuildpackURI{URI: bpURL}}}, + Dependencies: []dist.ImageOrURI{{BuildpackURI: dist.BuildpackURI{URI: createBuildpack(childDescriptor)}}}, }, Publish: false, - PullPolicy: config.PullAlways, + PullPolicy: pubcfg.PullAlways, Format: pack.FormatFile, + })) + + assertPackageBPFileHasBuildpacks(t, packagePath, []dist.BuildpackDescriptor{packageDescriptor, childDescriptor}) + }) + + when("dependency download fails", func() { + it("should error", func() { + bpURL := fmt.Sprintf("https://example.com/bp.%s.tgz", h.RandString(12)) + mockDownloader.EXPECT().Download(gomock.Any(), bpURL).Return(nil, image.ErrNotFound).AnyTimes() + + packagePath := filepath.Join(tmpDir, "test.cnb") + + err = subject.PackageBuildpack(context.TODO(), pack.PackageBuildpackOptions{ + Name: packagePath, + Config: pubbldpkg.Config{ + Buildpack: dist.BuildpackURI{URI: createBuildpack(packageDescriptor)}, + Dependencies: []dist.ImageOrURI{{BuildpackURI: dist.BuildpackURI{URI: bpURL}}}, + }, + Publish: false, + PullPolicy: pubcfg.PullAlways, + Format: pack.FormatFile, + }) + h.AssertError(t, err, "downloading buildpack") + }) + }) + + when("dependency isn't a valid buildpack", func() { + it("should error", func() { + fakeBlob := blob.NewBlob(filepath.Join("testdata", "empty-file")) + bpURL := fmt.Sprintf("https://example.com/bp.%s.tgz", h.RandString(12)) + mockDownloader.EXPECT().Download(gomock.Any(), bpURL).Return(fakeBlob, nil).AnyTimes() + + packagePath := filepath.Join(tmpDir, "test.cnb") + + err = subject.PackageBuildpack(context.TODO(), pack.PackageBuildpackOptions{ + Name: packagePath, + Config: pubbldpkg.Config{ + Buildpack: dist.BuildpackURI{URI: createBuildpack(packageDescriptor)}, + Dependencies: []dist.ImageOrURI{{BuildpackURI: dist.BuildpackURI{URI: bpURL}}}, + }, + Publish: false, + PullPolicy: pubcfg.PullAlways, + Format: pack.FormatFile, + }) + h.AssertError(t, err, "creating buildpack") }) - h.AssertError(t, err, "creating buildpack") }) }) - }) - when("dependencies include packaged buildpack image and unpacked buildpack", func() { - var secondChildDescriptor dist.BuildpackDescriptor + when("dependencies include packaged buildpack image and unpacked buildpack", func() { + var secondChildDescriptor dist.BuildpackDescriptor - it.Before(func() { - secondChildDescriptor = dist.BuildpackDescriptor{ - API: api.MustParse("0.2"), - Info: dist.BuildpackInfo{ID: "bp.nested1", Version: "2.3.4"}, - Stacks: []dist.Stack{{ID: "some.stack.id"}}, - } + it.Before(func() { + secondChildDescriptor = dist.BuildpackDescriptor{ + API: api.MustParse("0.2"), + Info: dist.BuildpackInfo{ID: "bp.nested1", Version: "2.3.4"}, + Stacks: []dist.Stack{{ID: "some.stack.id"}}, + } - packageDescriptor.Order = append(packageDescriptor.Order, dist.OrderEntry{Group: []dist.BuildpackRef{{ - BuildpackInfo: dist.BuildpackInfo{ID: secondChildDescriptor.Info.ID, Version: secondChildDescriptor.Info.Version}, - Optional: false, - }}}) + packageDescriptor.Order = append(packageDescriptor.Order, dist.OrderEntry{Group: []dist.BuildpackRef{{ + BuildpackInfo: dist.BuildpackInfo{ID: secondChildDescriptor.Info.ID, Version: secondChildDescriptor.Info.Version}, + Optional: false, + }}}) - nestedPackage = fakes.NewImage("nested/package-"+h.RandString(12), "", nil) - mockImageFactory.EXPECT().NewImage(nestedPackage.Name(), false).Return(nestedPackage, nil) + nestedPackage = fakes.NewImage("nested/package-"+h.RandString(12), "", nil) + mockImageFactory.EXPECT().NewImage(nestedPackage.Name(), false).Return(nestedPackage, nil) - h.AssertNil(t, subject.PackageBuildpack(context.TODO(), pack.PackageBuildpackOptions{ - Name: nestedPackage.Name(), - Config: pubbldpkg.Config{ - Buildpack: dist.BuildpackURI{URI: createBuildpack(childDescriptor)}, - }, - Publish: true, - PullPolicy: config.PullAlways, - })) + h.AssertNil(t, subject.PackageBuildpack(context.TODO(), pack.PackageBuildpackOptions{ + Name: nestedPackage.Name(), + Config: pubbldpkg.Config{ + Buildpack: dist.BuildpackURI{URI: createBuildpack(childDescriptor)}, + }, + Publish: true, + PullPolicy: pubcfg.PullAlways, + })) - mockImageFetcher.EXPECT().Fetch(gomock.Any(), nestedPackage.Name(), true, config.PullAlways).Return(nestedPackage, nil) - }) + mockImageFetcher.EXPECT().Fetch(gomock.Any(), nestedPackage.Name(), true, pubcfg.PullAlways).Return(nestedPackage, nil) + }) - it("should include both of them", func() { - packagePath := filepath.Join(tmpDir, "test.cnb") + it("should include both of them", func() { + packagePath := filepath.Join(tmpDir, "test.cnb") - h.AssertNil(t, subject.PackageBuildpack(context.TODO(), pack.PackageBuildpackOptions{ - Name: packagePath, - Config: pubbldpkg.Config{ - Buildpack: dist.BuildpackURI{URI: createBuildpack(packageDescriptor)}, - Dependencies: []dist.ImageOrURI{{ImageRef: dist.ImageRef{ImageName: nestedPackage.Name()}}, - {BuildpackURI: dist.BuildpackURI{URI: createBuildpack(secondChildDescriptor)}}}, - }, - Publish: false, - PullPolicy: config.PullAlways, - Format: pack.FormatFile, - })) + h.AssertNil(t, subject.PackageBuildpack(context.TODO(), pack.PackageBuildpackOptions{ + Name: packagePath, + Config: pubbldpkg.Config{ + Buildpack: dist.BuildpackURI{URI: createBuildpack(packageDescriptor)}, + Dependencies: []dist.ImageOrURI{{ImageRef: dist.ImageRef{ImageName: nestedPackage.Name()}}, + {BuildpackURI: dist.BuildpackURI{URI: createBuildpack(secondChildDescriptor)}}}, + }, + Publish: false, + PullPolicy: pubcfg.PullAlways, + Format: pack.FormatFile, + })) - assertPackageBPFileHasBuildpacks(t, packagePath, []dist.BuildpackDescriptor{packageDescriptor, childDescriptor, secondChildDescriptor}) + assertPackageBPFileHasBuildpacks(t, packagePath, []dist.BuildpackDescriptor{packageDescriptor, childDescriptor, secondChildDescriptor}) + }) }) - }) - when("dependencies include a packaged buildpack file", func() { - var ( - dependencyPackagePath string - ) - it.Before(func() { - dependencyPackagePath = filepath.Join(tmpDir, "dep.cnb") + when("dependencies include a packaged buildpack file", func() { + var ( + dependencyPackagePath string + ) + it.Before(func() { + dependencyPackagePath = filepath.Join(tmpDir, "dep.cnb") - h.AssertNil(t, subject.PackageBuildpack(context.TODO(), pack.PackageBuildpackOptions{ - Name: dependencyPackagePath, - Config: pubbldpkg.Config{ - Buildpack: dist.BuildpackURI{URI: createBuildpack(childDescriptor)}, - }, - PullPolicy: config.PullAlways, - Format: pack.FormatFile, - })) + h.AssertNil(t, subject.PackageBuildpack(context.TODO(), pack.PackageBuildpackOptions{ + Name: dependencyPackagePath, + Config: pubbldpkg.Config{ + Buildpack: dist.BuildpackURI{URI: createBuildpack(childDescriptor)}, + }, + PullPolicy: pubcfg.PullAlways, + Format: pack.FormatFile, + })) - mockDownloader.EXPECT().Download(gomock.Any(), dependencyPackagePath).Return(blob.NewBlob(dependencyPackagePath), nil).AnyTimes() - }) + mockDownloader.EXPECT().Download(gomock.Any(), dependencyPackagePath).Return(blob.NewBlob(dependencyPackagePath), nil).AnyTimes() + }) - it("should open file and correctly add buildpacks", func() { - packagePath := filepath.Join(tmpDir, "test.cnb") + it("should open file and correctly add buildpacks", func() { + packagePath := filepath.Join(tmpDir, "test.cnb") - h.AssertNil(t, subject.PackageBuildpack(context.TODO(), pack.PackageBuildpackOptions{ - Name: packagePath, - Config: pubbldpkg.Config{ - Buildpack: dist.BuildpackURI{URI: createBuildpack(packageDescriptor)}, - Dependencies: []dist.ImageOrURI{{BuildpackURI: dist.BuildpackURI{URI: dependencyPackagePath}}}, - }, - Publish: false, - PullPolicy: config.PullAlways, - Format: pack.FormatFile, - })) + h.AssertNil(t, subject.PackageBuildpack(context.TODO(), pack.PackageBuildpackOptions{ + Name: packagePath, + Config: pubbldpkg.Config{ + Buildpack: dist.BuildpackURI{URI: createBuildpack(packageDescriptor)}, + Dependencies: []dist.ImageOrURI{{BuildpackURI: dist.BuildpackURI{URI: dependencyPackagePath}}}, + }, + Publish: false, + PullPolicy: pubcfg.PullAlways, + Format: pack.FormatFile, + })) - assertPackageBPFileHasBuildpacks(t, packagePath, []dist.BuildpackDescriptor{packageDescriptor, childDescriptor}) + assertPackageBPFileHasBuildpacks(t, packagePath, []dist.BuildpackDescriptor{packageDescriptor, childDescriptor}) + }) }) }) }) when("unknown format is provided", func() { it("should error", func() { + mockDockerClient.EXPECT().Info(context.TODO()).Return(types.Info{OSType: "linux"}, nil).AnyTimes() + err := subject.PackageBuildpack(context.TODO(), pack.PackageBuildpackOptions{ Name: "some-buildpack", Format: "invalid-format", @@ -557,7 +660,7 @@ func testPackageBuildpack(t *testing.T, when spec.G, it spec.S) { })}, }, Publish: false, - PullPolicy: config.PullAlways, + PullPolicy: pubcfg.PullAlways, }) h.AssertError(t, err, "unknown format: 'invalid-format'") }) From a4e10551fadeece43b857cba89e7c8ff0b1f68f7 Mon Sep 17 00:00:00 2001 From: Micah Young Date: Wed, 14 Oct 2020 06:35:54 -0400 Subject: [PATCH 10/14] Removes skips for windows package tests Signed-off-by: Micah Young --- acceptance/acceptance_test.go | 158 ++++++++---------- .../buildpacks/package_image_buildpack.go | 1 - .../pack_fixtures/builder-windows.toml | 40 ----- 3 files changed, 69 insertions(+), 130 deletions(-) delete mode 100644 acceptance/testdata/pack_fixtures/builder-windows.toml diff --git a/acceptance/acceptance_test.go b/acceptance/acceptance_test.go index b088a46de..2605007a1 100644 --- a/acceptance/acceptance_test.go +++ b/acceptance/acceptance_test.go @@ -544,6 +544,7 @@ func testWithoutSpecificBuilderRequirement( buildpacks.FolderSimpleLayersParent, buildpacks.FolderSimpleLayers, ), + buildpacks.WithOS(dockerHostOS()), ) buildpackManager.PrepareBuildpacks(tmpDir, packageFile) @@ -564,10 +565,6 @@ func testWithoutSpecificBuilderRequirement( }) when("buildpack image", func() { - it.Before(func() { - h.SkipIf(t, dockerHostOS() == "windows", "These tests are not yet compatible with Windows-based containers") - }) - when("inspect-buildpack", func() { it("succeeds", func() { packageImageName := registryConfig.RepoName("buildpack-" + h.RandString(8)) @@ -2126,70 +2123,68 @@ func createComplexBuilder(t *testing.T, "run_image_mirror": runImageMirror, } - if dockerHostOS() != "windows" { - packageImageName := registryConfig.RepoName("nested-level-1-buildpack-" + h.RandString(8)) - nestedLevelTwoBuildpackName := registryConfig.RepoName("nested-level-2-buildpack-" + h.RandString(8)) - simpleLayersBuildpackName := registryConfig.RepoName("simple-layers-buildpack-" + h.RandString(8)) - - templateMapping["package_id"] = "simple/nested-level-1" - templateMapping["package_image_name"] = packageImageName - templateMapping["nested_level_1_buildpack"] = packageImageName - templateMapping["nested_level_2_buildpack"] = nestedLevelTwoBuildpackName - templateMapping["simple_layers_buildpack"] = simpleLayersBuildpackName - - fixtureManager := pack.FixtureManager() - - nestedLevelOneConfigFile, err := ioutil.TempFile(tmpDir, "nested-level-1-package.toml") - assert.Nil(err) - fixtureManager.TemplateFixtureToFile( - "nested-level-1-buildpack_package.toml", - nestedLevelOneConfigFile, - templateMapping, - ) - err = nestedLevelOneConfigFile.Close() - assert.Nil(err) - - nestedLevelTwoConfigFile, err := ioutil.TempFile(tmpDir, "nested-level-2-package.toml") - assert.Nil(err) - fixtureManager.TemplateFixtureToFile( - "nested-level-2-buildpack_package.toml", - nestedLevelTwoConfigFile, - templateMapping, - ) - err = nestedLevelTwoConfigFile.Close() - assert.Nil(err) + packageImageName := registryConfig.RepoName("nested-level-1-buildpack-" + h.RandString(8)) + nestedLevelTwoBuildpackName := registryConfig.RepoName("nested-level-2-buildpack-" + h.RandString(8)) + simpleLayersBuildpackName := registryConfig.RepoName("simple-layers-buildpack-" + h.RandString(8)) - packageImageBuildpack := buildpacks.NewPackageImage( - t, - pack, - packageImageName, - nestedLevelOneConfigFile.Name(), - buildpacks.WithRequiredBuildpacks( - buildpacks.NestedLevelOne, - buildpacks.NewPackageImage( - t, - pack, - nestedLevelTwoBuildpackName, - nestedLevelTwoConfigFile.Name(), - buildpacks.WithRequiredBuildpacks( - buildpacks.NestedLevelTwo, - buildpacks.NewPackageImage( - t, - pack, - simpleLayersBuildpackName, - fixtureManager.FixtureLocation("simple-layers-buildpack_package.toml"), - buildpacks.WithRequiredBuildpacks(buildpacks.SimpleLayers), - ), + templateMapping["package_id"] = "simple/nested-level-1" + templateMapping["package_image_name"] = packageImageName + templateMapping["nested_level_1_buildpack"] = packageImageName + templateMapping["nested_level_2_buildpack"] = nestedLevelTwoBuildpackName + templateMapping["simple_layers_buildpack"] = simpleLayersBuildpackName + + fixtureManager := pack.FixtureManager() + + nestedLevelOneConfigFile, err := ioutil.TempFile(tmpDir, "nested-level-1-package.toml") + assert.Nil(err) + fixtureManager.TemplateFixtureToFile( + "nested-level-1-buildpack_package.toml", + nestedLevelOneConfigFile, + templateMapping, + ) + err = nestedLevelOneConfigFile.Close() + assert.Nil(err) + + nestedLevelTwoConfigFile, err := ioutil.TempFile(tmpDir, "nested-level-2-package.toml") + assert.Nil(err) + fixtureManager.TemplateFixtureToFile( + "nested-level-2-buildpack_package.toml", + nestedLevelTwoConfigFile, + templateMapping, + ) + err = nestedLevelTwoConfigFile.Close() + assert.Nil(err) + + packageImageBuildpack := buildpacks.NewPackageImage( + t, + pack, + packageImageName, + nestedLevelOneConfigFile.Name(), + buildpacks.WithRequiredBuildpacks( + buildpacks.NestedLevelOne, + buildpacks.NewPackageImage( + t, + pack, + nestedLevelTwoBuildpackName, + nestedLevelTwoConfigFile.Name(), + buildpacks.WithRequiredBuildpacks( + buildpacks.NestedLevelTwo, + buildpacks.NewPackageImage( + t, + pack, + simpleLayersBuildpackName, + fixtureManager.FixtureLocation("simple-layers-buildpack_package.toml"), + buildpacks.WithRequiredBuildpacks(buildpacks.SimpleLayers), ), ), ), - ) + ), + ) - builderBuildpacks = append( - builderBuildpacks, - packageImageBuildpack, - ) - } + builderBuildpacks = append( + builderBuildpacks, + packageImageBuildpack, + ) buildpackManager.PrepareBuildpacks(tmpDir, builderBuildpacks...) @@ -2260,30 +2255,20 @@ func createBuilder( buildpacks.ReadEnv, } - // NOTE: Windows-based packages are not yet supported, so we'll add this buildpack in the usual way for now. - // Remove this block once Windows-based packages are supported. - if dockerHostOS() == "windows" { - builderBuildpacks = append(builderBuildpacks, buildpacks.SimpleLayers) - } - - // NOTE: Windows-based packages are not yet supported, so we'll add this buildpack in the usual way for now (see above). - // Remove this guard once Windows-based packages are supported. - if dockerHostOS() != "windows" { - packageImageName := registryConfig.RepoName("simple-layers-package-image-buildpack-" + h.RandString(8)) + packageImageName := registryConfig.RepoName("simple-layers-package-image-buildpack-" + h.RandString(8)) - packageImageBuildpack := buildpacks.NewPackageImage( - t, - pack, - packageImageName, - pack.FixtureManager().FixtureLocation("package.toml"), - buildpacks.WithRequiredBuildpacks(buildpacks.SimpleLayers), - ) + packageImageBuildpack := buildpacks.NewPackageImage( + t, + pack, + packageImageName, + pack.FixtureManager().FixtureLocation("package.toml"), + buildpacks.WithRequiredBuildpacks(buildpacks.SimpleLayers), + ) - builderBuildpacks = append(builderBuildpacks, packageImageBuildpack) + builderBuildpacks = append(builderBuildpacks, packageImageBuildpack) - templateMapping["package_image_name"] = packageImageName - templateMapping["package_id"] = "simple/layers" - } + templateMapping["package_image_name"] = packageImageName + templateMapping["package_id"] = "simple/layers" buildpackManager.PrepareBuildpacks(tmpDir, builderBuildpacks...) @@ -2303,11 +2288,6 @@ func createBuilder( // RENDER builder.toml configFileName := "builder.toml" - // NOTE: Remove when Windows-based packages are supported (can use same toml at that point) - if dockerHostOS() == "windows" { - configFileName = "builder-windows.toml" - } - builderConfigFile, err := ioutil.TempFile(tmpDir, "builder.toml") assert.Nil(err) diff --git a/acceptance/buildpacks/package_image_buildpack.go b/acceptance/buildpacks/package_image_buildpack.go index e2302a49b..fc616176a 100644 --- a/acceptance/buildpacks/package_image_buildpack.go +++ b/acceptance/buildpacks/package_image_buildpack.go @@ -55,7 +55,6 @@ func NewPackageImage( for _, mod := range modifiers { mod(&p) } - return p } diff --git a/acceptance/testdata/pack_fixtures/builder-windows.toml b/acceptance/testdata/pack_fixtures/builder-windows.toml deleted file mode 100644 index 94a991981..000000000 --- a/acceptance/testdata/pack_fixtures/builder-windows.toml +++ /dev/null @@ -1,40 +0,0 @@ -[[buildpacks]] - id = "read/env" - version = "read-env-version" - uri = "read-env-buildpack.tgz" - -[[buildpacks]] - # intentionally missing id/version as they are optional - uri = "noop-buildpack.tgz" - -[[buildpacks]] - # noop-buildpack-2 has the same id but a different version compared to noop-buildpack - uri = "noop-buildpack-2.tgz" - -[[buildpacks]] - uri = "simple-layers-buildpack.tgz" - -[[order]] - -[[order.group]] - id = "simple/layers" - # intentionlly missing version to test support - -[[order.group]] - id = "read/env" - version = "read-env-version" - optional = true - -[stack] - id = "pack.test.stack" - build-image = "pack-test/build" - run-image = "pack-test/run" - run-image-mirrors = ["{{.run_image_mirror}}"] - -[lifecycle] -{{- if .lifecycle_uri}} - uri = "{{.lifecycle_uri}}" -{{- end}} -{{- if .lifecycle_version}} - version = "{{.lifecycle_version}}" -{{- end}} From 2d6765b8af493769f2a018eb006a0f6d0b3094cb Mon Sep 17 00:00:00 2001 From: Travis Date: Wed, 14 Oct 2020 09:59:27 -0600 Subject: [PATCH 11/14] perform minor clean-up on test and other misc Signed-off-by: Travis --- internal/commands/set_default_registry.go | 2 +- internal/commands/set_default_registry_test.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/commands/set_default_registry.go b/internal/commands/set_default_registry.go index 938a5cf41..6df33bd6a 100644 --- a/internal/commands/set_default_registry.go +++ b/internal/commands/set_default_registry.go @@ -18,6 +18,7 @@ func SetDefaultRegistry(logger logging.Logger, cfg config.Config, cfgPath string Use: "set-default-registry ", Args: cobra.ExactArgs(1), Short: "Set default registry", + Example: "pack set-default-registry myregistry", RunE: logError(logger, func(cmd *cobra.Command, args []string) error { registryName = args[0] if !containsRegistry(config.GetRegistries(cfg), registryName) { @@ -37,7 +38,6 @@ func SetDefaultRegistry(logger logging.Logger, cfg config.Config, cfgPath string return nil }), } - cmd.Example = "pack set-default-registry myregistry" AddHelpFlag(cmd, "set-default-registry") return cmd diff --git a/internal/commands/set_default_registry_test.go b/internal/commands/set_default_registry_test.go index 743abcf35..fcf497e27 100644 --- a/internal/commands/set_default_registry_test.go +++ b/internal/commands/set_default_registry_test.go @@ -21,7 +21,7 @@ func TestSetDefaultRegistry(t *testing.T) { color.Disable(true) defer color.Disable(false) - spec.Run(t, "Commands", testSetDefaultRegistryCommand, spec.Parallel(), spec.Report(report.Terminal{})) + spec.Run(t, "SetDefaultRegistryCommand", testSetDefaultRegistryCommand, spec.Parallel(), spec.Report(report.Terminal{})) } func testSetDefaultRegistryCommand(t *testing.T, when spec.G, it spec.S) { @@ -52,7 +52,7 @@ func testSetDefaultRegistryCommand(t *testing.T, when spec.G, it spec.S) { { Name: "myregistry", URL: "https://github.com/buildpacks/registry-index", - Type: "Github", + Type: "github", }, }, } From 3819f15e04c9c6854b4fe0c2c38131d424ee60a4 Mon Sep 17 00:00:00 2001 From: Travis Date: Tue, 20 Oct 2020 09:22:02 -0600 Subject: [PATCH 12/14] fix format Signed-off-by: Travis --- internal/commands/set_default_registry.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/commands/set_default_registry.go b/internal/commands/set_default_registry.go index 6df33bd6a..0ba927bca 100644 --- a/internal/commands/set_default_registry.go +++ b/internal/commands/set_default_registry.go @@ -15,9 +15,9 @@ func SetDefaultRegistry(logger logging.Logger, cfg config.Config, cfgPath string ) cmd := &cobra.Command{ - Use: "set-default-registry ", - Args: cobra.ExactArgs(1), - Short: "Set default registry", + Use: "set-default-registry ", + Args: cobra.ExactArgs(1), + Short: "Set default registry", Example: "pack set-default-registry myregistry", RunE: logError(logger, func(cmd *cobra.Command, args []string) error { registryName = args[0] From e22e666cf9e105d6c47e40ee0168c22d4a2af96d Mon Sep 17 00:00:00 2001 From: Travis Date: Tue, 6 Oct 2020 17:36:16 -0600 Subject: [PATCH 13/14] remove-registry command Signed-off-by: Travis --- cmd/cmd.go | 1 + internal/commands/remove_registry.go | 68 ++++++++++++ internal/commands/remove_registry_test.go | 126 ++++++++++++++++++++++ 3 files changed, 195 insertions(+) create mode 100644 internal/commands/remove_registry.go create mode 100644 internal/commands/remove_registry_test.go diff --git a/cmd/cmd.go b/cmd/cmd.go index e9dedb4f0..6bb3e29b6 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -87,6 +87,7 @@ func NewPackCommand(logger ConfigurableLogger) (*cobra.Command, error) { rootCmd.AddCommand(commands.ListBuildpackRegistries(logger, cfg)) rootCmd.AddCommand(commands.AddBuildpackRegistry(logger, cfg, cfgPath)) rootCmd.AddCommand(commands.RegisterBuildpack(logger, cfg, &packClient)) + rootCmd.AddCommand(commands.RemoveRegistry(logger, cfg, cfgPath)) rootCmd.AddCommand(commands.YankBuildpack(logger, cfg, &packClient)) } diff --git a/internal/commands/remove_registry.go b/internal/commands/remove_registry.go new file mode 100644 index 000000000..406b3dd25 --- /dev/null +++ b/internal/commands/remove_registry.go @@ -0,0 +1,68 @@ +package commands + +import ( + "github.com/pkg/errors" + "github.com/spf13/cobra" + + "github.com/buildpacks/pack/internal/config" + "github.com/buildpacks/pack/internal/style" + "github.com/buildpacks/pack/logging" +) + +func RemoveRegistry(logger logging.Logger, cfg config.Config, cfgPath string) *cobra.Command { + var ( + registryName string + ) + + cmd := &cobra.Command{ + Use: "remove-registry ", + Args: cobra.ExactArgs(1), + Short: "Remove registry", + Example: "pack remove-registry myregistry", + RunE: logError(logger, func(cmd *cobra.Command, args []string) error { + registryName = args[0] + + if registryName == config.OfficialRegistryName { + return errors.Errorf("%s is a reserved registry name, please provide a different registry", + style.Symbol(config.OfficialRegistryName)) + } + + index := findRegistryIndex(registryName, cfg.Registries) + if index < 0 { + return errors.Errorf("registry %s does not exist", style.Symbol(registryName)) + } + + updatedRegistries := removeRegistry(index, cfg.Registries) + cfg.Registries = updatedRegistries + + if cfg.DefaultRegistryName == registryName { + cfg.DefaultRegistryName = config.OfficialRegistryName + } + config.Write(cfg, cfgPath) + + logger.Infof("Successfully removed %s from registries", style.Symbol(registryName)) + + return nil + }), + } + + AddHelpFlag(cmd, "remove-registry") + + return cmd +} + +func findRegistryIndex(registryName string, registries []config.Registry) int { + for index, r := range registries { + if r.Name == registryName { + return index + } + } + + return -1 +} + +func removeRegistry(index int, registries []config.Registry) []config.Registry { + registries[index] = registries[len(registries)-1] + + return registries[:len(registries)-1] +} diff --git a/internal/commands/remove_registry_test.go b/internal/commands/remove_registry_test.go new file mode 100644 index 000000000..d575cf884 --- /dev/null +++ b/internal/commands/remove_registry_test.go @@ -0,0 +1,126 @@ +package commands_test + +import ( + "bytes" + "io/ioutil" + "os" + "path/filepath" + "testing" + + "github.com/heroku/color" + "github.com/sclevine/spec" + "github.com/sclevine/spec/report" + + "github.com/buildpacks/pack/internal/commands" + "github.com/buildpacks/pack/internal/config" + ilogging "github.com/buildpacks/pack/internal/logging" + h "github.com/buildpacks/pack/testhelpers" +) + +func TestRemoveRegistry(t *testing.T) { + color.Disable(true) + defer color.Disable(false) + + spec.Run(t, "RemoveRegistryCommand", testRemoveRegistryCommand, spec.Parallel(), spec.Report(report.Terminal{})) +} + +func testRemoveRegistryCommand(t *testing.T, when spec.G, it spec.S) { + when("#RemoveRegistry", func() { + var ( + outBuf bytes.Buffer + logger = ilogging.NewLogWithWriters(&outBuf, &outBuf) + tmpDir string + configFile string + cfg config.Config + assert = h.NewAssertionManager(t) + ) + + it.Before(func() { + var err error + tmpDir, err = ioutil.TempDir("", "pack-home-*") + assert.Nil(err) + + cfg = config.Config{ + DefaultRegistryName: "buildpack-registry", + Registries: []config.Registry{ + { + Name: "buildpack-registry", + URL: "https://github.com/buildpacks/registry-index", + Type: "github", + }, + { + Name: "elbandito-registry", + URL: "https://github.com/elbandito/registry-index", + Type: "github", + }, + }, + } + + configFile = filepath.Join(tmpDir, "config.toml") + err = config.Write(cfg, configFile) + assert.Nil(err) + }) + + it.After(func() { + _ = os.RemoveAll(tmpDir) + }) + + it("should remove the registry", func() { + command := commands.RemoveRegistry(logger, cfg, configFile) + command.SetArgs([]string{"elbandito-registry"}) + assert.Succeeds(command.Execute()) + + newCfg, err := config.Read(configFile) + assert.Nil(err) + + assert.Equal(newCfg, config.Config{ + DefaultRegistryName: "buildpack-registry", + Registries: []config.Registry{ + { + Name: "buildpack-registry", + URL: "https://github.com/buildpacks/registry-index", + Type: "github", + }, + }, + }) + }) + + it("should remove the registry and matching default registry name", func() { + command := commands.RemoveRegistry(logger, cfg, configFile) + command.SetArgs([]string{"buildpack-registry"}) + assert.Succeeds(command.Execute()) + + newCfg, err := config.Read(configFile) + assert.Nil(err) + + assert.Equal(newCfg, config.Config{ + DefaultRegistryName: config.OfficialRegistryName, + Registries: []config.Registry{ + { + Name: "elbandito-registry", + URL: "https://github.com/elbandito/registry-index", + Type: "github", + }, + }, + }) + }) + + it("should return error when registry does NOT already exist", func() { + command := commands.RemoveRegistry(logger, cfg, configFile) + command.SetArgs([]string{"missing-registry"}) + assert.Error(command.Execute()) + + output := outBuf.String() + h.AssertContains(t, output, "registry 'missing-registry' does not exist") + }) + + it("should throw error when registry name is official", func() { + command := commands.RemoveRegistry(logger, config.Config{}, configFile) + command.SetArgs([]string{"official"}) + assert.Error(command.Execute()) + + output := outBuf.String() + h.AssertContains(t, output, "'official' is a reserved registry name, please provide a different registry") + }) + }) +} From 4038526b282c8349e6e4015e270d1ea514feccd0 Mon Sep 17 00:00:00 2001 From: Javier Romero Date: Tue, 20 Oct 2020 13:41:20 -0500 Subject: [PATCH 14/14] gomega version bumped to 1.10.2 instead of 1.10.3 Signed-off-by: Javier Romero --- go.mod | 5 ++++- go.sum | 15 +++++++++------ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/go.mod b/go.mod index 77185a8dc..c62a44b77 100644 --- a/go.mod +++ b/go.mod @@ -22,7 +22,7 @@ require ( github.com/mattn/go-colorable v0.1.6 // indirect github.com/mitchellh/ioprogress v0.0.0-20180201004757-6a23b12fa88e github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect - github.com/onsi/gomega v1.10.3 + github.com/onsi/gomega v1.10.2 github.com/opencontainers/image-spec v1.0.1 github.com/opencontainers/runc v0.1.1 // indirect github.com/opencontainers/selinux v1.4.0 // indirect @@ -34,7 +34,10 @@ require ( golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 golang.org/x/mod v0.3.0 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 + golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6 // indirect + golang.org/x/text v0.3.3 // indirect golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect + golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect google.golang.org/genproto v0.0.0-20200313141609-30c55424f95d // indirect google.golang.org/grpc v1.28.0 // indirect gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect diff --git a/go.sum b/go.sum index ac271db8d..de4d15ac8 100644 --- a/go.sum +++ b/go.sum @@ -322,8 +322,8 @@ github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGV github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.10.3 h1:gph6h/qe9GSUw1NhH1gp+qb+h8rXD8Cy60Z32Qw3ELA= -github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc= +github.com/onsi/gomega v1.10.2 h1:aY/nuoWlKJud2J6U0E3NWsjlg+0GtwXxgEqthRdzlcs= +github.com/onsi/gomega v1.10.2/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= @@ -504,8 +504,8 @@ golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0 h1:wBouT66WTYFXdxfVdz9sVWARVd/2vfGcmI45D2gj45M= -golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7 h1:AeiKBIuRw3UomYXSbLy0Mc2dDLfdtbT/IVn4keq83P0= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0= @@ -546,8 +546,9 @@ golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6 h1:DvY3Zkh7KabQE/kfzMvYvKirSiguP9Q/veMtkYyf0o8= +golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -587,6 +588,8 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0= gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e/go.mod h1:kS+toOQn6AQKjmKJ7gzohV1XkqsFehRA2FbsbkopSuQ=