diff --git a/cmd/cmd.go b/cmd/cmd.go index 837c9c96f4..7108b81afd 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -12,6 +12,7 @@ import ( imagewriter "github.com/buildpacks/pack/internal/inspectimage/writer" "github.com/buildpacks/pack/internal/term" "github.com/buildpacks/pack/pkg/client" + "github.com/buildpacks/pack/pkg/image" "github.com/buildpacks/pack/pkg/logging" ) @@ -33,7 +34,9 @@ func NewPackCommand(logger ConfigurableLogger) (*cobra.Command, error) { return nil, err } - packClient, err := initClient(logger, cfg) + imagePullPolicyHandler := image.NewPullPolicyManager(logger) + + packClient, err := initClient(logger, cfg, imagePullPolicyHandler) if err != nil { return nil, err } @@ -75,14 +78,14 @@ func NewPackCommand(logger ConfigurableLogger) (*cobra.Command, error) { commands.AddHelpFlag(rootCmd, "pack") - rootCmd.AddCommand(commands.Build(logger, cfg, packClient)) - rootCmd.AddCommand(commands.NewBuilderCommand(logger, cfg, packClient)) - rootCmd.AddCommand(commands.NewBuildpackCommand(logger, cfg, packClient, buildpackage.NewConfigReader())) - rootCmd.AddCommand(commands.NewExtensionCommand(logger, cfg, packClient, buildpackage.NewConfigReader())) - rootCmd.AddCommand(commands.NewConfigCommand(logger, cfg, cfgPath, packClient)) + rootCmd.AddCommand(commands.Build(logger, cfg, packClient, imagePullPolicyHandler)) + rootCmd.AddCommand(commands.NewBuilderCommand(logger, cfg, packClient, imagePullPolicyHandler)) + rootCmd.AddCommand(commands.NewBuildpackCommand(logger, cfg, packClient, buildpackage.NewConfigReader(), imagePullPolicyHandler)) + rootCmd.AddCommand(commands.NewExtensionCommand(logger, cfg, packClient, buildpackage.NewConfigReader(), imagePullPolicyHandler)) + rootCmd.AddCommand(commands.NewConfigCommand(logger, cfg, cfgPath, packClient, imagePullPolicyHandler)) rootCmd.AddCommand(commands.InspectImage(logger, imagewriter.NewFactory(), cfg, packClient)) rootCmd.AddCommand(commands.NewStackCommand(logger)) - rootCmd.AddCommand(commands.Rebase(logger, cfg, packClient)) + rootCmd.AddCommand(commands.Rebase(logger, cfg, packClient, imagePullPolicyHandler)) rootCmd.AddCommand(commands.NewSBOMCommand(logger, cfg, packClient)) rootCmd.AddCommand(commands.InspectBuildpack(logger, cfg, packClient)) @@ -94,8 +97,8 @@ func NewPackCommand(logger ConfigurableLogger) (*cobra.Command, error) { rootCmd.AddCommand(commands.TrustBuilder(logger, cfg, cfgPath)) rootCmd.AddCommand(commands.UntrustBuilder(logger, cfg, cfgPath)) rootCmd.AddCommand(commands.ListTrustedBuilders(logger, cfg)) - rootCmd.AddCommand(commands.CreateBuilder(logger, cfg, packClient)) - rootCmd.AddCommand(commands.PackageBuildpack(logger, cfg, packClient, buildpackage.NewConfigReader())) + rootCmd.AddCommand(commands.CreateBuilder(logger, cfg, packClient, imagePullPolicyHandler)) + rootCmd.AddCommand(commands.PackageBuildpack(logger, cfg, packClient, buildpackage.NewConfigReader(), imagePullPolicyHandler)) if cfg.Experimental { rootCmd.AddCommand(commands.AddBuildpackRegistry(logger, cfg, cfgPath)) @@ -145,5 +148,5 @@ func initClient(logger logging.Logger, cfg config.Config) (*client.Client, error if err != nil { return nil, err } - return client.NewClient(client.WithLogger(logger), client.WithExperimental(cfg.Experimental), client.WithRegistryMirrors(cfg.RegistryMirrors), client.WithDockerClient(dc)) + return client.NewClient(client.WithLogger(logger), client.WithExperimental(cfg.Experimental), client.WithRegistryMirrors(cfg.RegistryMirrors), client.WithDockerClient(dc), client.WithImagePullChecker(imagePullPolicyHandler)) } diff --git a/go.mod b/go.mod index d89e014a75..019c2e0264 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/docker/docker v25.0.5+incompatible github.com/docker/go-connections v0.5.0 github.com/dustin/go-humanize v1.0.1 - github.com/gdamore/tcell/v2 v2.7.1 + github.com/gdamore/tcell/v2 v2.7.4 github.com/go-git/go-git/v5 v5.11.0 github.com/golang/mock v1.6.0 github.com/google/go-cmp v0.6.0 @@ -29,9 +29,9 @@ require ( github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06 github.com/sclevine/spec v1.4.0 github.com/spf13/cobra v1.8.0 - golang.org/x/crypto v0.20.0 - golang.org/x/mod v0.15.0 - golang.org/x/oauth2 v0.17.0 + golang.org/x/crypto v0.21.0 + golang.org/x/mod v0.16.0 + golang.org/x/oauth2 v0.18.0 golang.org/x/sync v0.6.0 golang.org/x/sys v0.18.0 golang.org/x/term v0.18.0 @@ -132,7 +132,7 @@ require ( go.opentelemetry.io/otel v1.22.0 // indirect go.opentelemetry.io/otel/metric v1.22.0 // indirect go.opentelemetry.io/otel/trace v1.22.0 // indirect - golang.org/x/net v0.21.0 // indirect + golang.org/x/net v0.22.0 // indirect golang.org/x/tools v0.18.0 // indirect google.golang.org/appengine v1.6.8 // indirect google.golang.org/protobuf v1.33.0 // indirect diff --git a/go.sum b/go.sum index 17ca08fc80..b78983320a 100644 --- a/go.sum +++ b/go.sum @@ -154,8 +154,8 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko= github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg= github.com/gdamore/tcell/v2 v2.4.1-0.20210905002822-f057f0a857a1/go.mod h1:Az6Jt+M5idSED2YPGtwnfJV0kXohgdCBPmHGSYc1r04= -github.com/gdamore/tcell/v2 v2.7.1 h1:TiCcmpWHiAU7F0rA2I3S2Y4mmLmO9KHxJ7E1QhYzQbc= -github.com/gdamore/tcell/v2 v2.7.1/go.mod h1:dSXtXTSK0VsW1biw65DZLZ2NKr7j0qP/0J7ONmsraWg= +github.com/gdamore/tcell/v2 v2.7.4 h1:sg6/UnTM9jGpZU+oFYAsDahfchWAFW8Xx2yFinNSAYU= +github.com/gdamore/tcell/v2 v2.7.4/go.mod h1:dSXtXTSK0VsW1biw65DZLZ2NKr7j0qP/0J7ONmsraWg= github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY= github.com/gliderlabs/ssh v0.3.5/go.mod h1:8XB4KraRrX39qHhT6yxPsHedjA08I/uBVwj4xC+/+z4= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= @@ -417,15 +417,15 @@ golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0 golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/crypto v0.20.0 h1:jmAMJJZXr5KiCw05dfYK9QnqaqKLYXijU23lsEdcQqg= -golang.org/x/crypto v0.20.0/go.mod h1:Xwo95rrVNIoSMx9wa1JroENMToLWn3RNVrTBpLHgZPQ= +golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= +golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8= -golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic= +golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -441,11 +441,11 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= -golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= +golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.17.0 h1:6m3ZPmLEFdVxKKWnKq4VqZ60gutO35zm+zrAHVmHyDQ= -golang.org/x/oauth2 v0.17.0/go.mod h1:OzPDGQiuQMguemayvdylqddI7qcD9lnSDb+1FiwQ5HA= +golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI= +golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= diff --git a/internal/commands/build.go b/internal/commands/build.go index d04c74ab54..5f3b9f302a 100644 --- a/internal/commands/build.go +++ b/internal/commands/build.go @@ -58,7 +58,7 @@ type BuildFlags struct { } // Build an image from source code -func Build(logger logging.Logger, cfg config.Config, packClient PackClient) *cobra.Command { +func Build(logger logging.Logger, cfg config.Config, packClient PackClient, imagePullPolicyHandler image.ImagePullPolicyHandler) *cobra.Command { var flags BuildFlags cmd := &cobra.Command{ @@ -128,7 +128,7 @@ func Build(logger logging.Logger, cfg config.Config, packClient PackClient) *cob if stringPolicy == "" { stringPolicy = cfg.PullPolicy } - pullPolicy, err := image.ParsePullPolicy(stringPolicy, logger) + pullPolicy, err := imagePullPolicyHandler.ParsePullPolicy(stringPolicy) if err != nil { return errors.Wrapf(err, "parsing pull policy %s", flags.Policy) } diff --git a/internal/commands/build_test.go b/internal/commands/build_test.go index 6a59810004..3644f70a83 100644 --- a/internal/commands/build_test.go +++ b/internal/commands/build_test.go @@ -26,6 +26,7 @@ import ( "github.com/buildpacks/pack/pkg/image" "github.com/buildpacks/pack/pkg/logging" projectTypes "github.com/buildpacks/pack/pkg/project/types" + fetcher_mock "github.com/buildpacks/pack/pkg/testmocks" h "github.com/buildpacks/pack/testhelpers" ) @@ -38,12 +39,13 @@ func TestBuildCommand(t *testing.T) { func testBuildCommand(t *testing.T, when spec.G, it spec.S) { var ( - command *cobra.Command - logger *logging.LogWithWriters - outBuf bytes.Buffer - mockController *gomock.Controller - mockClient *testmocks.MockPackClient - cfg config.Config + command *cobra.Command + logger *logging.LogWithWriters + outBuf bytes.Buffer + mockController *gomock.Controller + mockClient *testmocks.MockPackClient + cfg config.Config + imagePullPolicyHandler image.ImagePullPolicyHandler ) it.Before(func() { @@ -51,8 +53,9 @@ func testBuildCommand(t *testing.T, when spec.G, it spec.S) { cfg = config.Config{} mockController = gomock.NewController(t) mockClient = testmocks.NewMockPackClient(mockController) + imagePullPolicyHandler = fetcher_mock.NewMockPullPolicyManager(logger) - command = commands.Build(logger, cfg, mockClient) + command = commands.Build(logger, cfg, mockClient, imagePullPolicyHandler) }) when("#BuildCommand", func() { @@ -97,7 +100,7 @@ func testBuildCommand(t *testing.T, when spec.G, it spec.S) { Return(nil) cfg := config.Config{TrustedBuilders: []config.TrustedBuilder{{Name: "my-builder"}}} - command = commands.Build(logger, cfg, mockClient) + command = commands.Build(logger, cfg, mockClient, imagePullPolicyHandler) }) it("sets the trust builder option", func() { logger.WantVerbose(true) @@ -167,7 +170,7 @@ func testBuildCommand(t *testing.T, when spec.G, it spec.S) { Return(nil) cfg := config.Config{PullPolicy: "if-not-present"} - command := commands.Build(logger, cfg, mockClient) + command := commands.Build(logger, cfg, mockClient, imagePullPolicyHandler) logger.WantVerbose(true) command.SetArgs([]string{"image", "--builder", "my-builder", "--pull-policy", "never"}) @@ -193,7 +196,7 @@ func testBuildCommand(t *testing.T, when spec.G, it spec.S) { Return(nil) cfg := config.Config{PullPolicy: "never"} - command := commands.Build(logger, cfg, mockClient) + command := commands.Build(logger, cfg, mockClient, imagePullPolicyHandler) logger.WantVerbose(true) command.SetArgs([]string{"image", "--builder", "my-builder"}) @@ -455,7 +458,7 @@ func testBuildCommand(t *testing.T, when spec.G, it spec.S) { Return(nil) cfg := config.Config{LifecycleImage: "some-lifecycle-image"} - command := commands.Build(logger, cfg, mockClient) + command := commands.Build(logger, cfg, mockClient, imagePullPolicyHandler) logger.WantVerbose(true) command.SetArgs([]string{"image", "--builder", "my-builder"}) @@ -895,7 +898,7 @@ builder = "my-builder" Experimental: true, LayoutRepositoryDir: layoutDir, } - command = commands.Build(logger, cfg, mockClient) + command = commands.Build(logger, cfg, mockClient, imagePullPolicyHandler) }) when("path to save the image is provided", func() { diff --git a/internal/commands/builder.go b/internal/commands/builder.go index 50d5efdd1a..c226a597a5 100644 --- a/internal/commands/builder.go +++ b/internal/commands/builder.go @@ -5,10 +5,11 @@ import ( builderwriter "github.com/buildpacks/pack/internal/builder/writer" "github.com/buildpacks/pack/internal/config" + "github.com/buildpacks/pack/pkg/image" "github.com/buildpacks/pack/pkg/logging" ) -func NewBuilderCommand(logger logging.Logger, cfg config.Config, client PackClient) *cobra.Command { +func NewBuilderCommand(logger logging.Logger, cfg config.Config, client PackClient, imagePullPolicyHandler image.ImagePullPolicyHandler) *cobra.Command { cmd := &cobra.Command{ Use: "builder", Aliases: []string{"builders"}, @@ -16,7 +17,7 @@ func NewBuilderCommand(logger logging.Logger, cfg config.Config, client PackClie RunE: nil, } - cmd.AddCommand(BuilderCreate(logger, cfg, client)) + cmd.AddCommand(BuilderCreate(logger, cfg, client, imagePullPolicyHandler)) cmd.AddCommand(BuilderInspect(logger, cfg, client, builderwriter.NewFactory())) cmd.AddCommand(BuilderSuggest(logger, client)) AddHelpFlag(cmd, "builder") diff --git a/internal/commands/builder_create.go b/internal/commands/builder_create.go index d6604e3576..3e9ddd3388 100644 --- a/internal/commands/builder_create.go +++ b/internal/commands/builder_create.go @@ -27,7 +27,7 @@ type BuilderCreateFlags struct { } // CreateBuilder creates a builder image, based on a builder config -func BuilderCreate(logger logging.Logger, cfg config.Config, pack PackClient) *cobra.Command { +func BuilderCreate(logger logging.Logger, cfg config.Config, pack PackClient, imagePullPolicyHandler image.ImagePullPolicyHandler) *cobra.Command { var flags BuilderCreateFlags cmd := &cobra.Command{ @@ -50,7 +50,7 @@ Creating a custom builder allows you to control what buildpacks are used and wha if stringPolicy == "" { stringPolicy = cfg.PullPolicy } - pullPolicy, err := image.ParsePullPolicy(stringPolicy, logger) + pullPolicy, err := imagePullPolicyHandler.ParsePullPolicy(stringPolicy) if err != nil { return errors.Wrapf(err, "parsing pull policy %s", flags.Policy) } diff --git a/internal/commands/builder_create_test.go b/internal/commands/builder_create_test.go index b89e7ab534..97980b69fa 100644 --- a/internal/commands/builder_create_test.go +++ b/internal/commands/builder_create_test.go @@ -17,7 +17,9 @@ import ( "github.com/buildpacks/pack/internal/commands" "github.com/buildpacks/pack/internal/commands/testmocks" "github.com/buildpacks/pack/internal/config" + "github.com/buildpacks/pack/pkg/image" "github.com/buildpacks/pack/pkg/logging" + fetcher_mock "github.com/buildpacks/pack/pkg/testmocks" h "github.com/buildpacks/pack/testhelpers" ) @@ -160,14 +162,15 @@ func TestCreateCommand(t *testing.T) { func testCreateCommand(t *testing.T, when spec.G, it spec.S) { var ( - command *cobra.Command - logger logging.Logger - outBuf bytes.Buffer - mockController *gomock.Controller - mockClient *testmocks.MockPackClient - tmpDir string - builderConfigPath string - cfg config.Config + command *cobra.Command + logger logging.Logger + outBuf bytes.Buffer + mockController *gomock.Controller + mockClient *testmocks.MockPackClient + tmpDir string + builderConfigPath string + cfg config.Config + imagePullPolicyHandler image.ImagePullPolicyHandler ) it.Before(func() { @@ -180,7 +183,8 @@ func testCreateCommand(t *testing.T, when spec.G, it spec.S) { mockController = gomock.NewController(t) mockClient = testmocks.NewMockPackClient(mockController) logger = logging.NewLogWithWriters(&outBuf, &outBuf) - command = commands.BuilderCreate(logger, cfg, mockClient) + imagePullPolicyHandler = fetcher_mock.NewMockPullPolicyManager(logger) + command = commands.BuilderCreate(logger, cfg, mockClient, imagePullPolicyHandler) }) it.After(func() { @@ -218,7 +222,7 @@ func testCreateCommand(t *testing.T, when spec.G, it spec.S) { when("configured pull policy is invalid", func() { it("errors when config set with unknown policy", func() { cfg = config.Config{PullPolicy: "unknown-policy"} - command = commands.BuilderCreate(logger, cfg, mockClient) + command = commands.BuilderCreate(logger, cfg, mockClient, imagePullPolicyHandler) command.SetArgs([]string{ "some/builder", "--config", builderConfigPath, diff --git a/internal/commands/builder_test.go b/internal/commands/builder_test.go index 801bc873d6..8bf41d82f8 100644 --- a/internal/commands/builder_test.go +++ b/internal/commands/builder_test.go @@ -12,7 +12,9 @@ import ( "github.com/buildpacks/pack/internal/commands" "github.com/buildpacks/pack/internal/commands/testmocks" "github.com/buildpacks/pack/internal/config" + "github.com/buildpacks/pack/pkg/image" "github.com/buildpacks/pack/pkg/logging" + fetcher_mock "github.com/buildpacks/pack/pkg/testmocks" h "github.com/buildpacks/pack/testhelpers" ) @@ -22,16 +24,18 @@ func TestBuilderCommand(t *testing.T) { func testBuilderCommand(t *testing.T, when spec.G, it spec.S) { var ( - cmd *cobra.Command - logger logging.Logger - outBuf bytes.Buffer + cmd *cobra.Command + logger logging.Logger + outBuf bytes.Buffer + imagePullPolicyHandler image.ImagePullPolicyHandler ) it.Before(func() { logger = logging.NewLogWithWriters(&outBuf, &outBuf) + imagePullPolicyHandler = fetcher_mock.NewMockPullPolicyManager(logger) mockController := gomock.NewController(t) mockClient := testmocks.NewMockPackClient(mockController) - cmd = commands.NewBuilderCommand(logger, config.Config{}, mockClient) + cmd = commands.NewBuilderCommand(logger, config.Config{}, mockClient, imagePullPolicyHandler) cmd.SetOut(logging.GetWriterForLevel(logger, logging.InfoLevel)) }) diff --git a/internal/commands/buildpack.go b/internal/commands/buildpack.go index 93985be84f..3e5ad5d8f0 100644 --- a/internal/commands/buildpack.go +++ b/internal/commands/buildpack.go @@ -4,10 +4,11 @@ import ( "github.com/spf13/cobra" "github.com/buildpacks/pack/internal/config" + "github.com/buildpacks/pack/pkg/image" "github.com/buildpacks/pack/pkg/logging" ) -func NewBuildpackCommand(logger logging.Logger, cfg config.Config, client PackClient, packageConfigReader PackageConfigReader) *cobra.Command { +func NewBuildpackCommand(logger logging.Logger, cfg config.Config, client PackClient, packageConfigReader PackageConfigReader, imagePullPolicyHandler image.ImagePullPolicyHandler) *cobra.Command { cmd := &cobra.Command{ Use: "buildpack", Aliases: []string{"buildpacks"}, @@ -16,7 +17,7 @@ func NewBuildpackCommand(logger logging.Logger, cfg config.Config, client PackCl } cmd.AddCommand(BuildpackInspect(logger, cfg, client)) - cmd.AddCommand(BuildpackPackage(logger, cfg, client, packageConfigReader)) + cmd.AddCommand(BuildpackPackage(logger, cfg, client, packageConfigReader, imagePullPolicyHandler)) cmd.AddCommand(BuildpackNew(logger, client)) cmd.AddCommand(BuildpackPull(logger, cfg, client)) cmd.AddCommand(BuildpackRegister(logger, cfg, client)) diff --git a/internal/commands/buildpack_package.go b/internal/commands/buildpack_package.go index 35f99ffc98..633be947ba 100644 --- a/internal/commands/buildpack_package.go +++ b/internal/commands/buildpack_package.go @@ -40,7 +40,7 @@ type PackageConfigReader interface { } // BuildpackPackage packages (a) buildpack(s) into OCI format, based on a package config -func BuildpackPackage(logger logging.Logger, cfg config.Config, packager BuildpackPackager, packageConfigReader PackageConfigReader) *cobra.Command { +func BuildpackPackage(logger logging.Logger, cfg config.Config, packager BuildpackPackager, packageConfigReader PackageConfigReader, imagePullPolicyHandler image.ImagePullPolicyHandler) *cobra.Command { var flags BuildpackPackageFlags cmd := &cobra.Command{ Use: "package --config ", @@ -62,7 +62,7 @@ func BuildpackPackage(logger logging.Logger, cfg config.Config, packager Buildpa if stringPolicy == "" { stringPolicy = cfg.PullPolicy } - pullPolicy, err := image.ParsePullPolicy(stringPolicy, logger) + pullPolicy, err := imagePullPolicyHandler.ParsePullPolicy(stringPolicy) if err != nil { return errors.Wrap(err, "parsing pull policy") } diff --git a/internal/commands/buildpack_package_test.go b/internal/commands/buildpack_package_test.go index f527c01d08..641654a1af 100644 --- a/internal/commands/buildpack_package_test.go +++ b/internal/commands/buildpack_package_test.go @@ -19,6 +19,7 @@ import ( "github.com/buildpacks/pack/pkg/dist" "github.com/buildpacks/pack/pkg/image" "github.com/buildpacks/pack/pkg/logging" + fetcher_mock "github.com/buildpacks/pack/pkg/testmocks" h "github.com/buildpacks/pack/testhelpers" ) @@ -355,11 +356,13 @@ func packageCommand(ops ...packageCommandOption) *cobra.Command { configPath: "/path/to/some/file", } + imagePullPolicyHandler := fetcher_mock.NewMockPullPolicyManager(config.logger) + for _, op := range ops { op(config) } - cmd := commands.BuildpackPackage(config.logger, config.clientConfig, config.buildpackPackager, config.packageConfigReader) + cmd := commands.BuildpackPackage(config.logger, config.clientConfig, config.buildpackPackager, config.packageConfigReader, imagePullPolicyHandler) cmd.SetArgs([]string{config.imageName, "--config", config.configPath, "-p", config.path}) return cmd diff --git a/internal/commands/buildpack_test.go b/internal/commands/buildpack_test.go index 761486e494..ad0f479cce 100644 --- a/internal/commands/buildpack_test.go +++ b/internal/commands/buildpack_test.go @@ -13,7 +13,9 @@ import ( "github.com/buildpacks/pack/internal/commands/fakes" "github.com/buildpacks/pack/internal/commands/testmocks" "github.com/buildpacks/pack/internal/config" + "github.com/buildpacks/pack/pkg/image" "github.com/buildpacks/pack/pkg/logging" + fetcher_mock "github.com/buildpacks/pack/pkg/testmocks" h "github.com/buildpacks/pack/testhelpers" ) @@ -23,17 +25,19 @@ func TestBuildpackCommand(t *testing.T) { func testBuildpackCommand(t *testing.T, when spec.G, it spec.S) { var ( - cmd *cobra.Command - logger logging.Logger - outBuf bytes.Buffer - mockClient *testmocks.MockPackClient + cmd *cobra.Command + logger logging.Logger + outBuf bytes.Buffer + mockClient *testmocks.MockPackClient + imagePullPolicyHandler image.ImagePullPolicyHandler ) it.Before(func() { logger = logging.NewLogWithWriters(&outBuf, &outBuf) + imagePullPolicyHandler = fetcher_mock.NewMockPullPolicyManager(logger) mockController := gomock.NewController(t) mockClient = testmocks.NewMockPackClient(mockController) - cmd = commands.NewBuildpackCommand(logger, config.Config{}, mockClient, fakes.NewFakePackageConfigReader()) + cmd = commands.NewBuildpackCommand(logger, config.Config{}, mockClient, fakes.NewFakePackageConfigReader(), imagePullPolicyHandler) cmd.SetOut(logging.GetWriterForLevel(logger, logging.InfoLevel)) }) diff --git a/internal/commands/config.go b/internal/commands/config.go index 0d183bc9be..3073cf3443 100644 --- a/internal/commands/config.go +++ b/internal/commands/config.go @@ -6,10 +6,11 @@ import ( "github.com/spf13/cobra" "github.com/buildpacks/pack/internal/config" + "github.com/buildpacks/pack/pkg/image" "github.com/buildpacks/pack/pkg/logging" ) -func NewConfigCommand(logger logging.Logger, cfg config.Config, cfgPath string, client PackClient) *cobra.Command { +func NewConfigCommand(logger logging.Logger, cfg config.Config, cfgPath string, client PackClient, imagePullPolicyHandler image.ImagePullPolicyHandler) *cobra.Command { cmd := &cobra.Command{ Use: "config", Short: "Interact with your local pack config file", @@ -18,8 +19,8 @@ func NewConfigCommand(logger logging.Logger, cfg config.Config, cfgPath string, cmd.AddCommand(ConfigDefaultBuilder(logger, cfg, cfgPath, client)) cmd.AddCommand(ConfigExperimental(logger, cfg, cfgPath)) - cmd.AddCommand(ConfigPullPolicy(logger, cfg, cfgPath)) - cmd.AddCommand(ConfigPruneInterval(logger, cfg, cfgPath)) + cmd.AddCommand(ConfigPullPolicy(logger, cfg, cfgPath, imagePullPolicyHandler)) + cmd.AddCommand(ConfigPruneInterval(logger, cfg, cfgPath, imagePullPolicyHandler)) cmd.AddCommand(ConfigRegistries(logger, cfg, cfgPath)) cmd.AddCommand(ConfigRunImagesMirrors(logger, cfg, cfgPath)) cmd.AddCommand(ConfigTrustedBuilder(logger, cfg, cfgPath)) diff --git a/internal/commands/config_prune_interval.go b/internal/commands/config_prune_interval.go index eae27bb307..5e00527e59 100644 --- a/internal/commands/config_prune_interval.go +++ b/internal/commands/config_prune_interval.go @@ -13,10 +13,9 @@ import ( "github.com/buildpacks/pack/pkg/logging" ) -func ConfigPruneInterval(logger logging.Logger, cfg config.Config, cfgPath string) *cobra.Command { +func ConfigPruneInterval(logger logging.Logger, cfg config.Config, cfgPath string, imagePullPolicyHandler image.ImagePullPolicyHandler) *cobra.Command { var unset bool var intervalRegex = regexp.MustCompile(`^(\d+d)?(\d+h)?(\d+m)?$`) - pullPolicyManager := image.NewPullPolicyManager(logger) cmd := &cobra.Command{ Use: "prune-interval", @@ -38,21 +37,21 @@ func ConfigPruneInterval(logger logging.Logger, cfg config.Config, cfgPath strin if len(args) > 0 { return errors.Errorf("prune interval and --unset cannot be specified simultaneously") } - imageJSON, err := pullPolicyManager.Read(imageJSONPath) + imageJSON, err := imagePullPolicyHandler.Read(imageJSONPath) if err != nil { return err } oldPruneInterval := imageJSON.Interval.PruningInterval imageJSON.Interval.PruningInterval = "7d" - err = pullPolicyManager.Write(imageJSON, imageJSONPath) + err = imagePullPolicyHandler.Write(imageJSON, imageJSONPath) if err != nil { return err } logger.Infof("Successfully unset pruning interval %s", style.Symbol(oldPruneInterval)) logger.Infof("Pruning interval has been set to %s", style.Symbol(imageJSON.Interval.PruningInterval)) case len(args) == 0: // list - imageJSON, err := pullPolicyManager.Read(imageJSONPath) + imageJSON, err := imagePullPolicyHandler.Read(imageJSONPath) if err != nil { return err } @@ -65,7 +64,7 @@ func ConfigPruneInterval(logger logging.Logger, cfg config.Config, cfgPath strin default: // set newPruneInterval := args[0] - imageJSON, err := pullPolicyManager.Read(imageJSONPath) + imageJSON, err := imagePullPolicyHandler.Read(imageJSONPath) if err != nil { return err } @@ -86,7 +85,7 @@ func ConfigPruneInterval(logger logging.Logger, cfg config.Config, cfgPath strin imageJSON.Interval.PruningInterval = newPruneInterval - err = pullPolicyManager.Write(imageJSON, imageJSONPath) + err = imagePullPolicyHandler.Write(imageJSON, imageJSONPath) if err != nil { return err } diff --git a/internal/commands/config_prune_interval_test.go b/internal/commands/config_prune_interval_test.go index 4cedb231dc..0f0d7a4b82 100644 --- a/internal/commands/config_prune_interval_test.go +++ b/internal/commands/config_prune_interval_test.go @@ -12,31 +12,37 @@ import ( "github.com/buildpacks/pack/internal/commands" "github.com/buildpacks/pack/internal/config" + "github.com/buildpacks/pack/pkg/image" "github.com/buildpacks/pack/pkg/logging" + fetcher_mock "github.com/buildpacks/pack/pkg/testmocks" h "github.com/buildpacks/pack/testhelpers" ) +var imageJSON *image.ImageJSON + func TestConfigPruneInterval(t *testing.T) { spec.Run(t, "ConfigPruneIntervalCommand", testConfigPruneIntervalCommand, spec.Random(), spec.Report(report.Terminal{})) } func testConfigPruneIntervalCommand(t *testing.T, when spec.G, it spec.S) { var ( - command *cobra.Command - logger logging.Logger - outBuf bytes.Buffer - tempPackHome string - configFile string - assert = h.NewAssertionManager(t) - cfg = config.Config{} + command *cobra.Command + logger logging.Logger + outBuf bytes.Buffer + tempPackHome string + configFile string + assert = h.NewAssertionManager(t) + cfg = config.Config{} + imagePullPolicyHandler *fetcher_mock.MockImagePullPolicyHandler ) it.Before(func() { logger = logging.NewLogWithWriters(&outBuf, &outBuf) + imagePullPolicyHandler = fetcher_mock.NewMockPullPolicyManager(logger) tempPackHome, _ = os.MkdirTemp("", "pack-home") configFile = filepath.Join(tempPackHome, "config.toml") - command = commands.ConfigPruneInterval(logger, cfg, configFile) + command = commands.ConfigPruneInterval(logger, cfg, configFile, imagePullPolicyHandler) }) it.After(func() { @@ -45,6 +51,21 @@ func testConfigPruneIntervalCommand(t *testing.T, when spec.G, it spec.S) { when("#ConfigPruneInterval", func() { when("no arguments are provided", func() { + it.Before(func() { + interval := "5d" + command.SetArgs([]string{interval}) + + err := command.Execute() + assert.Nil(err) + }) + + it.After(func() { + command.SetArgs([]string{"--unset"}) + + err := command.Execute() + assert.Nil(err) + }) + it("lists the current pruning interval", func() { command.SetArgs([]string{}) @@ -57,6 +78,13 @@ func testConfigPruneIntervalCommand(t *testing.T, when spec.G, it spec.S) { when("an argument is provided", func() { when("argument is valid", func() { + it.After(func() { + command.SetArgs([]string{"--unset"}) + + err := command.Execute() + assert.Nil(err) + }) + it("sets the provided interval as the pruning interval", func() { interval := "5d" command.SetArgs([]string{interval}) @@ -79,6 +107,42 @@ func testConfigPruneIntervalCommand(t *testing.T, when spec.G, it spec.S) { assert.Contains(err.Error(), "invalid interval format") }) }) + + when("argument is valid and the same as the already set pruning interval", func() { + it.Before(func() { + imageJSON = &image.ImageJSON{ + Interval: &image.Interval{ + PullingInterval: "7d", + PruningInterval: "5d", + LastPrune: "2023-01-01T00:00:00Z", + }, + Image: &image.ImageData{ + ImageIDtoTIME: map[string]string{}, + }, + } + + imagePullPolicyHandler.MockRead = func(path string) (*image.ImageJSON, error) { + return imageJSON, nil + } + }) + + it.After(func() { + command.SetArgs([]string{"--unset"}) + + err := command.Execute() + assert.Nil(err) + imagePullPolicyHandler.MockRead = nil + }) + + it("sets the provided interval as the pruning interval", func() { + interval := "5d" + command.SetArgs([]string{interval}) + + err := command.Execute() + assert.Nil(err) + assert.Contains(outBuf.String(), "Prune Interval is already set to") + }) + }) }) when("--unset flag is provided", func() { diff --git a/internal/commands/config_pull_policy.go b/internal/commands/config_pull_policy.go index a5d1968b99..908059b0b1 100644 --- a/internal/commands/config_pull_policy.go +++ b/internal/commands/config_pull_policy.go @@ -12,7 +12,7 @@ import ( "github.com/buildpacks/pack/pkg/logging" ) -func ConfigPullPolicy(logger logging.Logger, cfg config.Config, cfgPath string) *cobra.Command { +func ConfigPullPolicy(logger logging.Logger, cfg config.Config, cfgPath string, imagePullPolicyHandler image.ImagePullPolicyHandler) *cobra.Command { var unset bool cmd := &cobra.Command{ @@ -36,7 +36,7 @@ func ConfigPullPolicy(logger logging.Logger, cfg config.Config, cfgPath string) return errors.Wrapf(err, "writing config to %s", cfgPath) } - pullPolicy, err := image.ParsePullPolicy(cfg.PullPolicy, logger) + pullPolicy, err := imagePullPolicyHandler.ParsePullPolicy(cfg.PullPolicy) if err != nil { return err } @@ -44,7 +44,7 @@ func ConfigPullPolicy(logger logging.Logger, cfg config.Config, cfgPath string) logger.Infof("Successfully unset pull policy %s", style.Symbol(oldPullPolicy)) logger.Infof("Pull policy has been set to %s", style.Symbol(pullPolicy.String())) case len(args) == 0: // list - pullPolicy, err := image.ParsePullPolicy(cfg.PullPolicy, logger) + pullPolicy, err := imagePullPolicyHandler.ParsePullPolicy(cfg.PullPolicy) if err != nil { return err } @@ -58,7 +58,7 @@ func ConfigPullPolicy(logger logging.Logger, cfg config.Config, cfgPath string) return nil } - pullPolicy, err := image.ParsePullPolicy(newPullPolicy, logger) + pullPolicy, err := imagePullPolicyHandler.ParsePullPolicy(newPullPolicy) if err != nil { return err } diff --git a/internal/commands/config_pull_policy_test.go b/internal/commands/config_pull_policy_test.go index b913bdf35b..87e62e7405 100644 --- a/internal/commands/config_pull_policy_test.go +++ b/internal/commands/config_pull_policy_test.go @@ -15,6 +15,7 @@ import ( "github.com/buildpacks/pack/internal/commands" "github.com/buildpacks/pack/internal/config" "github.com/buildpacks/pack/pkg/logging" + fetcher_mock "github.com/buildpacks/pack/pkg/testmocks" h "github.com/buildpacks/pack/testhelpers" ) @@ -26,27 +27,43 @@ func TestConfigPullPolicy(t *testing.T) { func testConfigPullPolicyCommand(t *testing.T, when spec.G, it spec.S) { var ( - command *cobra.Command - logger logging.Logger - outBuf bytes.Buffer - tempPackHome string - configFile string - assert = h.NewAssertionManager(t) - cfg = config.Config{} + command *cobra.Command + logger logging.Logger + outBuf bytes.Buffer + tempPackHome string + configFile string + imageJSONData string + assert = h.NewAssertionManager(t) + cfg = config.Config{} + imagePullPolicyHandler *fetcher_mock.MockImagePullPolicyHandler ) it.Before(func() { var err error logger = logging.NewLogWithWriters(&outBuf, &outBuf) + imagePullPolicyHandler = fetcher_mock.NewMockPullPolicyManager(logger) tempPackHome, err = os.MkdirTemp("", "pack-home") h.AssertNil(t, err) + h.AssertNil(t, os.Setenv("PACK_HOME", tempPackHome)) configFile = filepath.Join(tempPackHome, "config.toml") + jsonFilePath := filepath.Join("testdata", "example_image.json") + data, err := os.ReadFile(jsonFilePath) + h.AssertNil(t, err) + imageJSONData = string(data) + + // Create the .pack directory and image.json file + packDir := filepath.Join(tempPackHome, ".pack") + h.AssertNil(t, os.Mkdir(packDir, 0755)) + + imageJSONFile := filepath.Join(packDir, "image.json") + h.AssertNil(t, os.WriteFile(imageJSONFile, []byte(imageJSONData), 0644)) - command = commands.ConfigPullPolicy(logger, cfg, configFile) + command = commands.ConfigPullPolicy(logger, cfg, configFile, imagePullPolicyHandler) command.SetOut(logging.GetWriterForLevel(logger, logging.InfoLevel)) }) it.After(func() { + h.AssertNil(t, os.Unsetenv("PACK_HOME")) h.AssertNil(t, os.RemoveAll(tempPackHome)) }) @@ -64,7 +81,7 @@ func testConfigPullPolicyCommand(t *testing.T, when spec.G, it spec.S) { when("policy set to always in config", func() { it("lists always as pull policy", func() { cfg.PullPolicy = "always" - command = commands.ConfigPullPolicy(logger, cfg, configFile) + command = commands.ConfigPullPolicy(logger, cfg, configFile, imagePullPolicyHandler) command.SetArgs([]string{}) h.AssertNil(t, command.Execute()) @@ -76,7 +93,7 @@ func testConfigPullPolicyCommand(t *testing.T, when spec.G, it spec.S) { when("policy set to never in config", func() { it("lists never as pull policy", func() { cfg.PullPolicy = "never" - command = commands.ConfigPullPolicy(logger, cfg, configFile) + command = commands.ConfigPullPolicy(logger, cfg, configFile, imagePullPolicyHandler) command.SetArgs([]string{}) h.AssertNil(t, command.Execute()) @@ -88,7 +105,7 @@ func testConfigPullPolicyCommand(t *testing.T, when spec.G, it spec.S) { when("policy set to if-not-present in config", func() { it("lists if-not-present as pull policy", func() { cfg.PullPolicy = "if-not-present" - command = commands.ConfigPullPolicy(logger, cfg, configFile) + command = commands.ConfigPullPolicy(logger, cfg, configFile, imagePullPolicyHandler) command.SetArgs([]string{}) h.AssertNil(t, command.Execute()) @@ -100,7 +117,7 @@ func testConfigPullPolicyCommand(t *testing.T, when spec.G, it spec.S) { when("policy set to hourly in config", func() { it("lists hourly as pull policy", func() { cfg.PullPolicy = "hourly" - command = commands.ConfigPullPolicy(logger, cfg, configFile) + command = commands.ConfigPullPolicy(logger, cfg, configFile, imagePullPolicyHandler) command.SetArgs([]string{}) h.AssertNil(t, command.Execute()) @@ -112,7 +129,7 @@ func testConfigPullPolicyCommand(t *testing.T, when spec.G, it spec.S) { when("policy set to daily in config", func() { it("lists daily as pull policy", func() { cfg.PullPolicy = "daily" - command = commands.ConfigPullPolicy(logger, cfg, configFile) + command = commands.ConfigPullPolicy(logger, cfg, configFile, imagePullPolicyHandler) command.SetArgs([]string{}) h.AssertNil(t, command.Execute()) @@ -124,7 +141,7 @@ func testConfigPullPolicyCommand(t *testing.T, when spec.G, it spec.S) { when("policy set to weekly in config", func() { it("lists weekly as pull policy", func() { cfg.PullPolicy = "weekly" - command = commands.ConfigPullPolicy(logger, cfg, configFile) + command = commands.ConfigPullPolicy(logger, cfg, configFile, imagePullPolicyHandler) command.SetArgs([]string{}) h.AssertNil(t, command.Execute()) @@ -136,7 +153,7 @@ func testConfigPullPolicyCommand(t *testing.T, when spec.G, it spec.S) { when("policy set to interval=1d2h30m in config", func() { it("lists interval=1d2h30m as pull policy", func() { cfg.PullPolicy = "interval=1d2h30m" - command = commands.ConfigPullPolicy(logger, cfg, configFile) + command = commands.ConfigPullPolicy(logger, cfg, configFile, imagePullPolicyHandler) command.SetArgs([]string{}) h.AssertNil(t, command.Execute()) @@ -149,7 +166,7 @@ func testConfigPullPolicyCommand(t *testing.T, when spec.G, it spec.S) { when("policy provided is the same as configured pull policy", func() { it("provides a helpful message", func() { cfg.PullPolicy = "if-not-present" - command = commands.ConfigPullPolicy(logger, cfg, configFile) + command = commands.ConfigPullPolicy(logger, cfg, configFile, imagePullPolicyHandler) command.SetArgs([]string{"if-not-present"}) h.AssertNil(t, command.Execute()) @@ -158,7 +175,7 @@ func testConfigPullPolicyCommand(t *testing.T, when spec.G, it spec.S) { h.AssertEq(t, strings.TrimSpace(output), `Pull policy is already set to 'if-not-present'`) }) it("it does not change the configured policy", func() { - command = commands.ConfigPullPolicy(logger, cfg, configFile) + command = commands.ConfigPullPolicy(logger, cfg, configFile, imagePullPolicyHandler) command.SetArgs([]string{"never"}) assert.Succeeds(command.Execute()) @@ -166,7 +183,7 @@ func testConfigPullPolicyCommand(t *testing.T, when spec.G, it spec.S) { assert.Nil(err) assert.Equal(readCfg.PullPolicy, "never") - command = commands.ConfigPullPolicy(logger, cfg, configFile) + command = commands.ConfigPullPolicy(logger, cfg, configFile, imagePullPolicyHandler) command.SetArgs([]string{"never"}) assert.Succeeds(command.Execute()) @@ -205,7 +222,7 @@ func testConfigPullPolicyCommand(t *testing.T, when spec.G, it spec.S) { when("unset", func() { it("removes set policy and resets to default pull policy", func() { command.SetArgs([]string{"never"}) - command = commands.ConfigPullPolicy(logger, cfg, configFile) + command = commands.ConfigPullPolicy(logger, cfg, configFile, imagePullPolicyHandler) command.SetArgs([]string{"--unset"}) assert.Succeeds(command.Execute()) diff --git a/internal/commands/config_test.go b/internal/commands/config_test.go index 15f1bae8ad..b678586d00 100644 --- a/internal/commands/config_test.go +++ b/internal/commands/config_test.go @@ -15,7 +15,9 @@ import ( "github.com/buildpacks/pack/internal/commands" "github.com/buildpacks/pack/internal/commands/testmocks" "github.com/buildpacks/pack/internal/config" + "github.com/buildpacks/pack/pkg/image" "github.com/buildpacks/pack/pkg/logging" + fetcher_mock "github.com/buildpacks/pack/pkg/testmocks" h "github.com/buildpacks/pack/testhelpers" ) @@ -27,12 +29,13 @@ func TestConfigCommand(t *testing.T) { func testConfigCommand(t *testing.T, when spec.G, it spec.S) { var ( - command *cobra.Command - logger logging.Logger - outBuf bytes.Buffer - tempPackHome string - configPath string - mockClient *testmocks.MockPackClient + command *cobra.Command + logger logging.Logger + outBuf bytes.Buffer + tempPackHome string + configPath string + mockClient *testmocks.MockPackClient + imagePullPolicyHandler image.ImagePullPolicyHandler ) it.Before(func() { @@ -42,11 +45,12 @@ func testConfigCommand(t *testing.T, when spec.G, it spec.S) { mockClient = testmocks.NewMockPackClient(mockController) logger = logging.NewLogWithWriters(&outBuf, &outBuf) + imagePullPolicyHandler = fetcher_mock.NewMockPullPolicyManager(logger) tempPackHome, err = os.MkdirTemp("", "pack-home") h.AssertNil(t, err) configPath = filepath.Join(tempPackHome, "config.toml") - command = commands.NewConfigCommand(logger, config.Config{Experimental: true}, configPath, mockClient) + command = commands.NewConfigCommand(logger, config.Config{Experimental: true}, configPath, mockClient, imagePullPolicyHandler) command.SetOut(logging.GetWriterForLevel(logger, logging.InfoLevel)) }) diff --git a/internal/commands/create_builder.go b/internal/commands/create_builder.go index 4ac3f6a09a..fbca4a3b28 100644 --- a/internal/commands/create_builder.go +++ b/internal/commands/create_builder.go @@ -17,7 +17,7 @@ import ( // Deprecated: Use 'builder create' instead. // CreateBuilder creates a builder image, based on a builder config -func CreateBuilder(logger logging.Logger, cfg config.Config, pack PackClient) *cobra.Command { +func CreateBuilder(logger logging.Logger, cfg config.Config, pack PackClient, imagePullPolicyHandler image.ImagePullPolicyHandler) *cobra.Command { var flags BuilderCreateFlags cmd := &cobra.Command{ @@ -43,7 +43,7 @@ Creating a custom builder allows you to control what buildpacks are used and wha if stringPolicy == "" { stringPolicy = cfg.PullPolicy } - pullPolicy, err := image.ParsePullPolicy(stringPolicy, logger) + pullPolicy, err := imagePullPolicyHandler.ParsePullPolicy(stringPolicy) if err != nil { return errors.Wrapf(err, "parsing pull policy %s", flags.Policy) } diff --git a/internal/commands/create_builder_test.go b/internal/commands/create_builder_test.go index f960ebb2c1..bc1faede57 100644 --- a/internal/commands/create_builder_test.go +++ b/internal/commands/create_builder_test.go @@ -15,7 +15,9 @@ import ( "github.com/buildpacks/pack/internal/commands" "github.com/buildpacks/pack/internal/commands/testmocks" "github.com/buildpacks/pack/internal/config" + "github.com/buildpacks/pack/pkg/image" "github.com/buildpacks/pack/pkg/logging" + fetcher_mock "github.com/buildpacks/pack/pkg/testmocks" h "github.com/buildpacks/pack/testhelpers" ) @@ -27,14 +29,15 @@ func TestCreateBuilderCommand(t *testing.T) { func testCreateBuilderCommand(t *testing.T, when spec.G, it spec.S) { var ( - command *cobra.Command - logger logging.Logger - outBuf bytes.Buffer - mockController *gomock.Controller - mockClient *testmocks.MockPackClient - tmpDir string - builderConfigPath string - cfg config.Config + command *cobra.Command + logger logging.Logger + outBuf bytes.Buffer + mockController *gomock.Controller + mockClient *testmocks.MockPackClient + tmpDir string + builderConfigPath string + cfg config.Config + imagePullPolicyHandler image.ImagePullPolicyHandler ) it.Before(func() { @@ -47,7 +50,8 @@ func testCreateBuilderCommand(t *testing.T, when spec.G, it spec.S) { mockController = gomock.NewController(t) mockClient = testmocks.NewMockPackClient(mockController) logger = logging.NewLogWithWriters(&outBuf, &outBuf) - command = commands.CreateBuilder(logger, cfg, mockClient) + imagePullPolicyHandler = fetcher_mock.NewMockPullPolicyManager(logger) + command = commands.CreateBuilder(logger, cfg, mockClient, imagePullPolicyHandler) }) it.After(func() { @@ -98,7 +102,7 @@ func testCreateBuilderCommand(t *testing.T, when spec.G, it spec.S) { when("configured pull policy is invalid", func() { it("returns error for when config set with unknown policy", func() { cfg = config.Config{PullPolicy: "unknown-policy"} - command = commands.BuilderCreate(logger, cfg, mockClient) + command = commands.BuilderCreate(logger, cfg, mockClient, imagePullPolicyHandler) command.SetArgs([]string{ "some/builder", "--config", builderConfigPath, diff --git a/internal/commands/extension.go b/internal/commands/extension.go index bc4ab36476..54f4840710 100644 --- a/internal/commands/extension.go +++ b/internal/commands/extension.go @@ -4,10 +4,11 @@ import ( "github.com/spf13/cobra" "github.com/buildpacks/pack/internal/config" + "github.com/buildpacks/pack/pkg/image" "github.com/buildpacks/pack/pkg/logging" ) -func NewExtensionCommand(logger logging.Logger, cfg config.Config, client PackClient, packageConfigReader PackageConfigReader) *cobra.Command { +func NewExtensionCommand(logger logging.Logger, cfg config.Config, client PackClient, packageConfigReader PackageConfigReader, imagePullPolicyHandler image.ImagePullPolicyHandler) *cobra.Command { cmd := &cobra.Command{ Use: "extension", Aliases: []string{"extensions"}, @@ -17,7 +18,7 @@ func NewExtensionCommand(logger logging.Logger, cfg config.Config, client PackCl cmd.AddCommand(ExtensionInspect(logger, cfg, client)) // client and packageConfigReader to be passed later on - cmd.AddCommand(ExtensionPackage(logger, cfg, client, packageConfigReader)) + cmd.AddCommand(ExtensionPackage(logger, cfg, client, packageConfigReader, imagePullPolicyHandler)) // client to be passed later on cmd.AddCommand(ExtensionNew(logger)) cmd.AddCommand(ExtensionPull(logger, cfg, client)) diff --git a/internal/commands/extension_package.go b/internal/commands/extension_package.go index cea78a629a..c622867d44 100644 --- a/internal/commands/extension_package.go +++ b/internal/commands/extension_package.go @@ -29,7 +29,7 @@ type ExtensionPackager interface { } // ExtensionPackage packages (a) extension(s) into OCI format, based on a package config -func ExtensionPackage(logger logging.Logger, cfg config.Config, packager ExtensionPackager, packageConfigReader PackageConfigReader) *cobra.Command { +func ExtensionPackage(logger logging.Logger, cfg config.Config, packager ExtensionPackager, packageConfigReader PackageConfigReader, imagePullPolicyHandler image.ImagePullPolicyHandler) *cobra.Command { var flags ExtensionPackageFlags cmd := &cobra.Command{ Use: "package --config ", @@ -45,7 +45,7 @@ func ExtensionPackage(logger logging.Logger, cfg config.Config, packager Extensi stringPolicy = cfg.PullPolicy } - pullPolicy, err := image.ParsePullPolicy(stringPolicy, logger) + pullPolicy, err := imagePullPolicyHandler.ParsePullPolicy(stringPolicy) if err != nil { return errors.Wrap(err, "parsing pull policy") } diff --git a/internal/commands/extension_package_test.go b/internal/commands/extension_package_test.go index a46416e76e..9ed242fe01 100644 --- a/internal/commands/extension_package_test.go +++ b/internal/commands/extension_package_test.go @@ -18,6 +18,7 @@ import ( "github.com/buildpacks/pack/pkg/dist" "github.com/buildpacks/pack/pkg/image" "github.com/buildpacks/pack/pkg/logging" + fetcher_mock "github.com/buildpacks/pack/pkg/testmocks" h "github.com/buildpacks/pack/testhelpers" ) @@ -273,11 +274,13 @@ func packageExtensionCommand(ops ...packageExtensionCommandOption) *cobra.Comman configPath: "/path/to/some/file", } + imagePullPolicyHandler := fetcher_mock.NewMockPullPolicyManager(config.logger) + for _, op := range ops { op(config) } - cmd := commands.ExtensionPackage(config.logger, config.clientConfig, config.extensionPackager, config.packageConfigReader) + cmd := commands.ExtensionPackage(config.logger, config.clientConfig, config.extensionPackager, config.packageConfigReader, imagePullPolicyHandler) cmd.SetArgs([]string{config.imageName, "--config", config.configPath}) return cmd diff --git a/internal/commands/extension_test.go b/internal/commands/extension_test.go index 396d772905..fe2e66dd23 100644 --- a/internal/commands/extension_test.go +++ b/internal/commands/extension_test.go @@ -13,7 +13,9 @@ import ( "github.com/buildpacks/pack/internal/commands/fakes" "github.com/buildpacks/pack/internal/commands/testmocks" "github.com/buildpacks/pack/internal/config" + "github.com/buildpacks/pack/pkg/image" "github.com/buildpacks/pack/pkg/logging" + fetcher_mock "github.com/buildpacks/pack/pkg/testmocks" h "github.com/buildpacks/pack/testhelpers" ) @@ -23,17 +25,19 @@ func TestExtensionCommand(t *testing.T) { func testExtensionCommand(t *testing.T, when spec.G, it spec.S) { var ( - cmd *cobra.Command - logger logging.Logger - outBuf bytes.Buffer - mockClient *testmocks.MockPackClient + cmd *cobra.Command + logger logging.Logger + outBuf bytes.Buffer + mockClient *testmocks.MockPackClient + imagePullPolicyHandler image.ImagePullPolicyHandler ) it.Before(func() { logger = logging.NewLogWithWriters(&outBuf, &outBuf) + imagePullPolicyHandler = fetcher_mock.NewMockPullPolicyManager(logger) mockController := gomock.NewController(t) mockClient = testmocks.NewMockPackClient(mockController) - cmd = commands.NewExtensionCommand(logger, config.Config{}, mockClient, fakes.NewFakePackageConfigReader()) + cmd = commands.NewExtensionCommand(logger, config.Config{}, mockClient, fakes.NewFakePackageConfigReader(), imagePullPolicyHandler) cmd.SetOut(logging.GetWriterForLevel(logger, logging.InfoLevel)) }) diff --git a/internal/commands/package_buildpack.go b/internal/commands/package_buildpack.go index a5fc9b6da9..8757144ec6 100644 --- a/internal/commands/package_buildpack.go +++ b/internal/commands/package_buildpack.go @@ -16,7 +16,7 @@ import ( // Deprecated: use BuildpackPackage instead // PackageBuildpack packages (a) buildpack(s) into OCI format, based on a package config -func PackageBuildpack(logger logging.Logger, cfg config.Config, packager BuildpackPackager, packageConfigReader PackageConfigReader) *cobra.Command { +func PackageBuildpack(logger logging.Logger, cfg config.Config, packager BuildpackPackager, packageConfigReader PackageConfigReader, imagePullPolicyHandler image.ImagePullPolicyHandler) *cobra.Command { var flags BuildpackPackageFlags cmd := &cobra.Command{ @@ -41,7 +41,7 @@ func PackageBuildpack(logger logging.Logger, cfg config.Config, packager Buildpa if stringPolicy == "" { stringPolicy = cfg.PullPolicy } - pullPolicy, err := image.ParsePullPolicy(stringPolicy, logger) + pullPolicy, err := imagePullPolicyHandler.ParsePullPolicy(stringPolicy) if err != nil { return errors.Wrap(err, "parsing pull policy") } diff --git a/internal/commands/package_buildpack_test.go b/internal/commands/package_buildpack_test.go index 585d477edb..dfaeebe1d5 100644 --- a/internal/commands/package_buildpack_test.go +++ b/internal/commands/package_buildpack_test.go @@ -18,6 +18,7 @@ import ( "github.com/buildpacks/pack/pkg/dist" "github.com/buildpacks/pack/pkg/image" "github.com/buildpacks/pack/pkg/logging" + fetcher_mock "github.com/buildpacks/pack/pkg/testmocks" h "github.com/buildpacks/pack/testhelpers" ) @@ -131,11 +132,12 @@ func testPackageBuildpackCommand(t *testing.T, when spec.G, it spec.S) { }) it("takes precedence over a configured pull policy", func() { logger := logging.NewLogWithWriters(&bytes.Buffer{}, &bytes.Buffer{}) + imagePullPolicyHandler := fetcher_mock.NewMockPullPolicyManager(logger) configReader := fakes.NewFakePackageConfigReader() buildpackPackager := &fakes.FakeBuildpackPackager{} clientConfig := config.Config{PullPolicy: "if-not-present"} - command := commands.PackageBuildpack(logger, clientConfig, buildpackPackager, configReader) + command := commands.PackageBuildpack(logger, clientConfig, buildpackPackager, configReader, imagePullPolicyHandler) command.SetArgs([]string{ "some-image-name", "--config", "/path/to/some/file", @@ -153,11 +155,12 @@ func testPackageBuildpackCommand(t *testing.T, when spec.G, it spec.S) { when("configured pull policy", func() { it("uses the configured pull policy", func() { logger := logging.NewLogWithWriters(&bytes.Buffer{}, &bytes.Buffer{}) + imagePullChecker := fetcher_mock.NewMockPullPolicyManager(logger) configReader := fakes.NewFakePackageConfigReader() buildpackPackager := &fakes.FakeBuildpackPackager{} clientConfig := config.Config{PullPolicy: "never"} - command := commands.PackageBuildpack(logger, clientConfig, buildpackPackager, configReader) + command := commands.PackageBuildpack(logger, clientConfig, buildpackPackager, configReader, imagePullChecker) command.SetArgs([]string{ "some-image-name", "--config", "/path/to/some/file", @@ -177,11 +180,12 @@ func testPackageBuildpackCommand(t *testing.T, when spec.G, it spec.S) { 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{}) + imagePullChecker := fetcher_mock.NewMockPullPolicyManager(logger) configReader := fakes.NewFakePackageConfigReader() buildpackPackager := &fakes.FakeBuildpackPackager{} clientConfig := config.Config{} - command := commands.PackageBuildpack(logger, clientConfig, buildpackPackager, configReader) + command := commands.PackageBuildpack(logger, clientConfig, buildpackPackager, configReader, imagePullChecker) command.SetArgs([]string{ "some-image-name", "--config", "/path/to/some/file", @@ -226,7 +230,9 @@ func testPackageBuildpackCommand(t *testing.T, when spec.G, it spec.S) { configPath: "/path/to/some/file", } - cmd := commands.PackageBuildpack(config.logger, config.clientConfig, config.buildpackPackager, config.packageConfigReader) + imagePullPolicyHandler := fetcher_mock.NewMockPullPolicyManager(config.logger) + + cmd := commands.PackageBuildpack(config.logger, config.clientConfig, config.buildpackPackager, config.packageConfigReader, imagePullPolicyHandler) cmd.SetArgs([]string{config.imageName, "--package-config", config.configPath}) err := cmd.Execute() @@ -244,7 +250,9 @@ func testPackageBuildpackCommand(t *testing.T, when spec.G, it spec.S) { imageName: "some-image-name", } - cmd := commands.PackageBuildpack(config.logger, config.clientConfig, config.buildpackPackager, config.packageConfigReader) + imagePullChecker := fetcher_mock.NewMockPullPolicyManager(config.logger) + + cmd := commands.PackageBuildpack(config.logger, config.clientConfig, config.buildpackPackager, config.packageConfigReader, imagePullChecker) cmd.SetArgs([]string{config.imageName}) err := cmd.Execute() @@ -258,11 +266,12 @@ func testPackageBuildpackCommand(t *testing.T, when spec.G, it spec.S) { when("--pull-policy unknown-policy", func() { it("fails to run", func() { logger := logging.NewLogWithWriters(&bytes.Buffer{}, &bytes.Buffer{}) + imagePullChecker := fetcher_mock.NewMockPullPolicyManager(logger) configReader := fakes.NewFakePackageConfigReader() buildpackPackager := &fakes.FakeBuildpackPackager{} clientConfig := config.Config{} - command := commands.PackageBuildpack(logger, clientConfig, buildpackPackager, configReader) + command := commands.PackageBuildpack(logger, clientConfig, buildpackPackager, configReader, imagePullChecker) command.SetArgs([]string{ "some-image-name", "--config", "/path/to/some/file", @@ -287,11 +296,13 @@ func packageBuildpackCommand(ops ...packageCommandOption) *cobra.Command { configPath: "/path/to/some/file", } + imagePullChecker := fetcher_mock.NewMockPullPolicyManager(config.logger) + for _, op := range ops { op(config) } - cmd := commands.PackageBuildpack(config.logger, config.clientConfig, config.buildpackPackager, config.packageConfigReader) + cmd := commands.PackageBuildpack(config.logger, config.clientConfig, config.buildpackPackager, config.packageConfigReader, imagePullChecker) cmd.SetArgs([]string{config.imageName, "--config", config.configPath}) return cmd diff --git a/internal/commands/rebase.go b/internal/commands/rebase.go index f522163f54..ea61ffff21 100644 --- a/internal/commands/rebase.go +++ b/internal/commands/rebase.go @@ -13,7 +13,7 @@ import ( "github.com/buildpacks/pack/pkg/logging" ) -func Rebase(logger logging.Logger, cfg config.Config, pack PackClient) *cobra.Command { +func Rebase(logger logging.Logger, cfg config.Config, pack PackClient, imagePullPolicyHandler image.ImagePullPolicyHandler) *cobra.Command { var opts client.RebaseOptions var policy string @@ -33,7 +33,7 @@ func Rebase(logger logging.Logger, cfg config.Config, pack PackClient) *cobra.Co if stringPolicy == "" { stringPolicy = cfg.PullPolicy } - opts.PullPolicy, err = image.ParsePullPolicy(stringPolicy, logger) + opts.PullPolicy, err = imagePullPolicyHandler.ParsePullPolicy(stringPolicy) if err != nil { return errors.Wrapf(err, "parsing pull policy %s", stringPolicy) } diff --git a/internal/commands/rebase_test.go b/internal/commands/rebase_test.go index a3bdf05f5e..caf5821b49 100644 --- a/internal/commands/rebase_test.go +++ b/internal/commands/rebase_test.go @@ -18,6 +18,7 @@ import ( "github.com/buildpacks/pack/internal/commands/testmocks" "github.com/buildpacks/pack/internal/config" "github.com/buildpacks/pack/pkg/logging" + fetcher_mock "github.com/buildpacks/pack/pkg/testmocks" h "github.com/buildpacks/pack/testhelpers" ) @@ -30,21 +31,23 @@ func TestRebaseCommand(t *testing.T) { func testRebaseCommand(t *testing.T, when spec.G, it spec.S) { var ( - command *cobra.Command - logger logging.Logger - outBuf bytes.Buffer - mockController *gomock.Controller - mockClient *testmocks.MockPackClient - cfg config.Config + command *cobra.Command + logger logging.Logger + outBuf bytes.Buffer + mockController *gomock.Controller + mockClient *testmocks.MockPackClient + cfg config.Config + imagePullPolicyHandler image.ImagePullPolicyHandler ) it.Before(func() { logger = logging.NewLogWithWriters(&outBuf, &outBuf) + imagePullPolicyHandler = fetcher_mock.NewMockPullPolicyManager(logger) cfg = config.Config{} mockController = gomock.NewController(t) mockClient = testmocks.NewMockPackClient(mockController) - command = commands.Rebase(logger, cfg, mockClient) + command = commands.Rebase(logger, cfg, mockClient, imagePullPolicyHandler) }) when("#RebaseCommand", func() { @@ -69,7 +72,7 @@ func testRebaseCommand(t *testing.T, when spec.G, it spec.S) { Image: runImage, Mirrors: []string{testMirror1, testMirror2}, }} - command = commands.Rebase(logger, cfg, mockClient) + command = commands.Rebase(logger, cfg, mockClient, imagePullPolicyHandler) repoName = "test/repo-image" opts = client.RebaseOptions{ @@ -109,7 +112,7 @@ func testRebaseCommand(t *testing.T, when spec.G, it spec.S) { Return(nil) cfg.PullPolicy = "if-not-present" - command = commands.Rebase(logger, cfg, mockClient) + command = commands.Rebase(logger, cfg, mockClient, imagePullPolicyHandler) command.SetArgs([]string{repoName, "--pull-policy", "never"}) h.AssertNil(t, command.Execute()) @@ -142,7 +145,7 @@ func testRebaseCommand(t *testing.T, when spec.G, it spec.S) { Return(nil) cfg.PullPolicy = "if-not-present" - command = commands.Rebase(logger, cfg, mockClient) + command = commands.Rebase(logger, cfg, mockClient, imagePullPolicyHandler) command.SetArgs([]string{repoName}) h.AssertNil(t, command.Execute()) @@ -152,7 +155,7 @@ func testRebaseCommand(t *testing.T, when spec.G, it spec.S) { it("passes it through", func() { opts.Force = true mockClient.EXPECT().Rebase(gomock.Any(), opts).Return(nil) - command = commands.Rebase(logger, cfg, mockClient) + command = commands.Rebase(logger, cfg, mockClient, imagePullPolicyHandler) command.SetArgs([]string{repoName, "--force"}) h.AssertNil(t, command.Execute()) }) @@ -170,7 +173,7 @@ func testRebaseCommand(t *testing.T, when spec.G, it spec.S) { Image: runImage, Mirrors: []string{testMirror1, testMirror2}, }} - command = commands.Rebase(logger, cfg, mockClient) + command = commands.Rebase(logger, cfg, mockClient, imagePullPolicyHandler) repoName = "test/repo-image" previousImage := "example.com/previous-image:tag" // Example of previous image with tag diff --git a/internal/commands/testdata/example_image.json b/internal/commands/testdata/example_image.json new file mode 100644 index 0000000000..383c664a7e --- /dev/null +++ b/internal/commands/testdata/example_image.json @@ -0,0 +1,13 @@ +{ + "interval": { + "pulling_interval": "1d", + "pruning_interval": "5d", + "last_prune": "2024-03-13T11:31:58+05:30" + }, + "image": { + "ImageIDtoTIME": { + "gcr.io/buildpacks/builder:v1": "2024-03-13T11:32:00+05:30", + "gcr.io/buildpacks/gcp/run:v1": "2024-03-13T11:32:03+05:30" + } + } +} \ No newline at end of file diff --git a/pkg/client/client.go b/pkg/client/client.go index ad974cd44b..4e7996ceed 100644 --- a/pkg/client/client.go +++ b/pkg/client/client.go @@ -94,13 +94,14 @@ type Client struct { logger logging.Logger docker DockerClient - keychain authn.Keychain - imageFactory ImageFactory - imageFetcher ImageFetcher - accessChecker AccessChecker - downloader BlobDownloader - lifecycleExecutor LifecycleExecutor - buildpackDownloader BuildpackDownloader + keychain authn.Keychain + imageFactory ImageFactory + imageFetcher ImageFetcher + imagePullPolicyHandler image.ImagePullPolicyHandler + accessChecker AccessChecker + downloader BlobDownloader + lifecycleExecutor LifecycleExecutor + buildpackDownloader BuildpackDownloader experimental bool registryMirrors map[string]string @@ -133,6 +134,14 @@ func WithFetcher(f ImageFetcher) Option { } } +// WithImagePullChecker supply your own ImagePullChecker. +// An ImagePullChecker provides functionality to check and manage image pulling intervals. +func WithImagePullChecker(i image.ImagePullPolicyHandler) Option { + return func(c *Client) { + c.imagePullPolicyHandler = i + } +} + // WithAccessChecker supply your own AccessChecker. // A AccessChecker returns true if an image is accessible for reading. func WithAccessChecker(f AccessChecker) Option { @@ -231,8 +240,7 @@ func NewClient(opts ...Option) (*Client, error) { } if client.imageFetcher == nil { - imagePullChecker := image.NewPullPolicyManager(client.logger) - client.imageFetcher = image.NewFetcher(client.logger, client.docker, imagePullChecker, image.WithRegistryMirrors(client.registryMirrors), image.WithKeychain(client.keychain)) + client.imageFetcher = image.NewFetcher(client.logger, client.docker, client.imagePullPolicyHandler, image.WithRegistryMirrors(client.registryMirrors), image.WithKeychain(client.keychain)) } if client.imageFactory == nil { diff --git a/pkg/image/fetcher.go b/pkg/image/fetcher.go index 9f26c2921e..2afad2444c 100644 --- a/pkg/image/fetcher.go +++ b/pkg/image/fetcher.go @@ -36,11 +36,13 @@ type LayoutOption struct { Sparse bool } -type ImagePullChecker interface { +type ImagePullPolicyHandler interface { + ParsePullPolicy(policy string) (PullPolicy, error) CheckImagePullInterval(imageID string, path string) (bool, error) - Read(path string) (*ImageJSON, error) - PruneOldImages(f *Fetcher) error + PruneOldImages(docker DockerClient) error UpdateImagePullRecord(path string, imageID string, timestamp string) error + UpdateImageJSONDuration(intervalStr string) error + Read(path string) (*ImageJSON, error) Write(imageJSON *ImageJSON, path string) error } @@ -48,7 +50,7 @@ func intervalPolicy(options FetchOptions) bool { return options.PullPolicy == PullWithInterval || options.PullPolicy == PullHourly || options.PullPolicy == PullDaily || options.PullPolicy == PullWeekly } -func NewPullPolicyManager(logger logging.Logger) *ImagePullPolicyManager { +func NewPullPolicyManager(logger logging.Logger) ImagePullPolicyHandler { return &ImagePullPolicyManager{Logger: logger} } @@ -75,7 +77,7 @@ type Fetcher struct { logger logging.Logger registryMirrors map[string]string keychain authn.Keychain - imagePullChecker ImagePullChecker + imagePullChecker ImagePullPolicyHandler } type FetchOptions struct { @@ -85,7 +87,7 @@ type FetchOptions struct { LayoutOption LayoutOption } -func NewFetcher(logger logging.Logger, docker DockerClient, imagePullChecker ImagePullChecker, opts ...FetcherOption) *Fetcher { +func NewFetcher(logger logging.Logger, docker DockerClient, imagePullChecker ImagePullPolicyHandler, opts ...FetcherOption) *Fetcher { fetcher := &Fetcher{ logger: logger, docker: docker, @@ -148,7 +150,7 @@ func (f *Fetcher) Fetch(ctx context.Context, name string, options FetchOptions) return img, err } - err = f.imagePullChecker.PruneOldImages(f) + err = f.imagePullChecker.PruneOldImages(f.docker) if err != nil { f.logger.Warnf("Failed to prune images, %s", err) } diff --git a/pkg/image/fetcher_test.go b/pkg/image/fetcher_test.go index f20ba35ace..bedcba7015 100644 --- a/pkg/image/fetcher_test.go +++ b/pkg/image/fetcher_test.go @@ -22,6 +22,7 @@ import ( "github.com/buildpacks/pack/pkg/image" "github.com/buildpacks/pack/pkg/logging" + "github.com/buildpacks/pack/pkg/testmocks" h "github.com/buildpacks/pack/testhelpers" ) @@ -29,74 +30,7 @@ var docker client.CommonAPIClient var logger logging.Logger var registryConfig *h.TestRegistryConfig var imageJSON *image.ImageJSON -var mockImagePullChecker = NewMockImagePullChecker(logger) - -type MockPullChecker struct { - *image.ImagePullPolicyManager - MockCheckImagePullInterval func(imageID string, path string) (bool, error) - MockRead func(path string) (*image.ImageJSON, error) - MockPruneOldImages func(f *image.Fetcher) error - MockUpdateImagePullRecord func(path string, imageID string, timestamp string) error - MockWrite func(imageJSON *image.ImageJSON, path string) error -} - -func NewMockImagePullChecker(logger logging.Logger) *MockPullChecker { - return &MockPullChecker{ - ImagePullPolicyManager: image.NewPullPolicyManager(logger), - } -} - -func (m *MockPullChecker) CheckImagePullInterval(imageID string, path string) (bool, error) { - if m.MockCheckImagePullInterval != nil { - return m.MockCheckImagePullInterval(imageID, path) - } - return false, nil -} - -func (m *MockPullChecker) Write(imageJSON *image.ImageJSON, path string) error { - if m.MockWrite != nil { - return m.MockWrite(imageJSON, path) - } - return nil -} - -func (m *MockPullChecker) Read(path string) (*image.ImageJSON, error) { - if m.MockRead != nil { - return m.MockRead(path) - } - - imageJSON = &image.ImageJSON{ - Interval: &image.Interval{ - PullingInterval: "7d", - PruningInterval: "7d", - LastPrune: "2023-01-01T00:00:00Z", - }, - Image: &image.ImageData{ - ImageIDtoTIME: map[string]string{ - "repoName": "2023-01-01T00:00:00Z", - }, - }, - } - - return imageJSON, nil -} - -func (m *MockPullChecker) PruneOldImages(f *image.Fetcher) error { - if m.MockPruneOldImages != nil { - return m.MockPruneOldImages(f) - } - - return nil -} - -func (m *MockPullChecker) UpdateImagePullRecord(path string, imageID string, timestamp string) error { - if m.MockUpdateImagePullRecord != nil { - fmt.Printf("checking wheather its calling or not") - return m.MockUpdateImagePullRecord(path, imageID, timestamp) - } - - return nil -} +var mockImagePullPolicyHandler = testmocks.NewMockPullPolicyManager(logger) func TestFetcher(t *testing.T) { color.Disable(true) @@ -129,7 +63,7 @@ func testFetcher(t *testing.T, when spec.G, it spec.S) { repo = "some-org/" + h.RandString(10) repoName = registryConfig.RepoName(repo) logger = logging.NewLogWithWriters(&outBuf, &outBuf) - imageFetcher = image.NewFetcher(logger, docker, mockImagePullChecker) + imageFetcher = image.NewFetcher(logger, docker, mockImagePullPolicyHandler) info, err := docker.Info(context.TODO()) h.AssertNil(t, err) @@ -240,10 +174,10 @@ func testFetcher(t *testing.T, when spec.G, it spec.S) { var outCons *color.Console outCons, output = h.MockWriterAndOutput() logger = logging.NewLogWithWriters(outCons, outCons) - mockImagePullChecker.MockCheckImagePullInterval = func(imageID string, path string) (bool, error) { + mockImagePullPolicyHandler.MockCheckImagePullInterval = func(imageID string, path string) (bool, error) { return true, nil } - imageFetcher = image.NewFetcher(logger, docker, mockImagePullChecker) + imageFetcher = image.NewFetcher(logger, docker, mockImagePullPolicyHandler) }) it.After(func() { @@ -448,14 +382,14 @@ func testFetcher(t *testing.T, when spec.G, it spec.S) { when("there is no local image and CheckImagePullInterval returns true", func() { it.Before(func() { - mockImagePullChecker.MockCheckImagePullInterval = func(imageID string, path string) (bool, error) { + mockImagePullPolicyHandler.MockCheckImagePullInterval = func(imageID string, path string) (bool, error) { return true, nil } - imageFetcher = image.NewFetcher(logging.NewLogWithWriters(&outBuf, &outBuf), docker, mockImagePullChecker) + imageFetcher = image.NewFetcher(logging.NewLogWithWriters(&outBuf, &outBuf), docker, mockImagePullPolicyHandler) }) it.After(func() { - mockImagePullChecker.MockCheckImagePullInterval = nil + mockImagePullPolicyHandler.MockCheckImagePullInterval = nil }) it("pulls the remote image and returns it", func() { @@ -470,7 +404,7 @@ func testFetcher(t *testing.T, when spec.G, it spec.S) { when("there is no local image and CheckImagePullInterval returns false", func() { it.Before(func() { - mockImagePullChecker.MockCheckImagePullInterval = func(imageID string, path string) (bool, error) { + mockImagePullPolicyHandler.MockCheckImagePullInterval = func(imageID string, path string) (bool, error) { return false, nil } @@ -487,22 +421,22 @@ func testFetcher(t *testing.T, when spec.G, it spec.S) { }, } - imageFetcher = image.NewFetcher(logging.NewLogWithWriters(&outBuf, &outBuf), docker, mockImagePullChecker) + imageFetcher = image.NewFetcher(logging.NewLogWithWriters(&outBuf, &outBuf), docker, mockImagePullPolicyHandler) - mockImagePullChecker.MockRead = func(path string) (*image.ImageJSON, error) { + mockImagePullPolicyHandler.MockRead = func(path string) (*image.ImageJSON, error) { return imageJSON, nil } }) it.After(func() { - mockImagePullChecker.MockCheckImagePullInterval = nil - mockImagePullChecker.MockRead = nil + mockImagePullPolicyHandler.MockCheckImagePullInterval = nil + mockImagePullPolicyHandler.MockRead = nil }) it("returns an error and deletes the image record", func() { _, err := imageFetcher.Fetch(context.TODO(), repoName, image.FetchOptions{Daemon: true, PullPolicy: image.PullWeekly}) h.AssertError(t, err, fmt.Sprintf("image '%s' does not exist on the daemon", repoName)) - imageJSON, err = mockImagePullChecker.Read("") + imageJSON, err = mockImagePullPolicyHandler.Read("") h.AssertNil(t, err) _, exists := imageJSON.Image.ImageIDtoTIME[repoName] h.AssertEq(t, exists, false) @@ -515,7 +449,7 @@ func testFetcher(t *testing.T, when spec.G, it spec.S) { h.AssertNil(t, err) h.AssertNil(t, img.Save()) - mockImagePullChecker.MockCheckImagePullInterval = func(imageID string, path string) (bool, error) { + mockImagePullPolicyHandler.MockCheckImagePullInterval = func(imageID string, path string) (bool, error) { return true, nil } @@ -532,23 +466,23 @@ func testFetcher(t *testing.T, when spec.G, it spec.S) { }, } - mockImagePullChecker.MockRead = func(path string) (*image.ImageJSON, error) { + mockImagePullPolicyHandler.MockRead = func(path string) (*image.ImageJSON, error) { return imageJSON, nil } - mockImagePullChecker.MockUpdateImagePullRecord = func(path string, imageID string, timestamp string) error { - imageJSON, _ = mockImagePullChecker.Read("") + mockImagePullPolicyHandler.MockUpdateImagePullRecord = func(path string, imageID string, timestamp string) error { + imageJSON, _ = mockImagePullPolicyHandler.Read("") imageJSON.Image.ImageIDtoTIME[repoName] = timestamp return nil } - imageFetcher = image.NewFetcher(logging.NewLogWithWriters(&outBuf, &outBuf), docker, mockImagePullChecker) + imageFetcher = image.NewFetcher(logging.NewLogWithWriters(&outBuf, &outBuf), docker, mockImagePullPolicyHandler) }) it.After(func() { - mockImagePullChecker.MockCheckImagePullInterval = nil - mockImagePullChecker.MockRead = nil - mockImagePullChecker.MockUpdateImagePullRecord = nil + mockImagePullPolicyHandler.MockCheckImagePullInterval = nil + mockImagePullPolicyHandler.MockRead = nil + mockImagePullPolicyHandler.MockUpdateImagePullRecord = nil h.DockerRmi(docker, repoName) }) @@ -558,7 +492,7 @@ func testFetcher(t *testing.T, when spec.G, it spec.S) { _, err := imageFetcher.Fetch(context.TODO(), repoName, image.FetchOptions{Daemon: true, PullPolicy: image.PullWeekly}) h.AssertNil(t, err) - imageJSON, _ = mockImagePullChecker.Read("") + imageJSON, _ = mockImagePullPolicyHandler.Read("") afterFetch, _ := time.Parse(time.RFC3339, imageJSON.Image.ImageIDtoTIME[repoName]) fmt.Printf("after fetch: %v\n", imageJSON.Image.ImageIDtoTIME[repoName]) @@ -574,14 +508,14 @@ func testFetcher(t *testing.T, when spec.G, it spec.S) { h.AssertNil(t, localImg.SetLabel(label, "2")) h.AssertNil(t, localImg.Save()) - mockImagePullChecker.MockCheckImagePullInterval = func(imageID string, path string) (bool, error) { + mockImagePullPolicyHandler.MockCheckImagePullInterval = func(imageID string, path string) (bool, error) { return true, nil } - imageFetcher = image.NewFetcher(logging.NewLogWithWriters(&outBuf, &outBuf), docker, mockImagePullChecker) + imageFetcher = image.NewFetcher(logging.NewLogWithWriters(&outBuf, &outBuf), docker, mockImagePullPolicyHandler) }) it.After(func() { - mockImagePullChecker.MockCheckImagePullInterval = nil + mockImagePullPolicyHandler.MockCheckImagePullInterval = nil h.DockerRmi(docker, repoName) }) @@ -601,14 +535,14 @@ func testFetcher(t *testing.T, when spec.G, it spec.S) { when("there is no local image and CheckImagePullInterval returns true", func() { it.Before(func() { - mockImagePullChecker.MockCheckImagePullInterval = func(imageID string, path string) (bool, error) { + mockImagePullPolicyHandler.MockCheckImagePullInterval = func(imageID string, path string) (bool, error) { return true, nil } - imageFetcher = image.NewFetcher(logging.NewLogWithWriters(&outBuf, &outBuf), docker, mockImagePullChecker) + imageFetcher = image.NewFetcher(logging.NewLogWithWriters(&outBuf, &outBuf), docker, mockImagePullPolicyHandler) }) it.After(func() { - mockImagePullChecker.MockCheckImagePullInterval = nil + mockImagePullPolicyHandler.MockCheckImagePullInterval = nil }) it("try to pull the remote image and returns error", func() { @@ -619,7 +553,7 @@ func testFetcher(t *testing.T, when spec.G, it spec.S) { when("there is no local image and CheckImagePullInterval returns false", func() { it.Before(func() { - mockImagePullChecker.MockCheckImagePullInterval = func(imageID string, path string) (bool, error) { + mockImagePullPolicyHandler.MockCheckImagePullInterval = func(imageID string, path string) (bool, error) { return false, nil } @@ -636,21 +570,21 @@ func testFetcher(t *testing.T, when spec.G, it spec.S) { }, } - imageFetcher = image.NewFetcher(logging.NewLogWithWriters(&outBuf, &outBuf), docker, mockImagePullChecker) - mockImagePullChecker.MockRead = func(path string) (*image.ImageJSON, error) { + imageFetcher = image.NewFetcher(logging.NewLogWithWriters(&outBuf, &outBuf), docker, mockImagePullPolicyHandler) + mockImagePullPolicyHandler.MockRead = func(path string) (*image.ImageJSON, error) { return imageJSON, nil } }) it.After(func() { - mockImagePullChecker.MockCheckImagePullInterval = nil - mockImagePullChecker.MockRead = nil + mockImagePullPolicyHandler.MockCheckImagePullInterval = nil + mockImagePullPolicyHandler.MockRead = nil }) it("returns an error and deletes the image record", func() { _, err := imageFetcher.Fetch(context.TODO(), repoName, image.FetchOptions{Daemon: true, PullPolicy: image.PullWeekly}) h.AssertError(t, err, fmt.Sprintf("image '%s' does not exist on the daemon", repoName)) - imageJSON, err = mockImagePullChecker.Read("") + imageJSON, err = mockImagePullPolicyHandler.Read("") h.AssertNil(t, err) _, exists := imageJSON.Image.ImageIDtoTIME[repoName] h.AssertEq(t, exists, false) @@ -664,14 +598,14 @@ func testFetcher(t *testing.T, when spec.G, it spec.S) { h.AssertNil(t, localImg.SetLabel(label, "2")) h.AssertNil(t, localImg.Save()) - mockImagePullChecker.MockCheckImagePullInterval = func(imageID string, path string) (bool, error) { + mockImagePullPolicyHandler.MockCheckImagePullInterval = func(imageID string, path string) (bool, error) { return true, nil } - imageFetcher = image.NewFetcher(logging.NewLogWithWriters(&outBuf, &outBuf), docker, mockImagePullChecker) + imageFetcher = image.NewFetcher(logging.NewLogWithWriters(&outBuf, &outBuf), docker, mockImagePullPolicyHandler) }) it.After(func() { - mockImagePullChecker.MockCheckImagePullInterval = nil + mockImagePullPolicyHandler.MockCheckImagePullInterval = nil h.DockerRmi(docker, repoName) }) @@ -692,14 +626,14 @@ func testFetcher(t *testing.T, when spec.G, it spec.S) { h.AssertNil(t, localImg.SetLabel(label, "2")) h.AssertNil(t, localImg.Save()) - mockImagePullChecker.MockCheckImagePullInterval = func(imageID string, path string) (bool, error) { + mockImagePullPolicyHandler.MockCheckImagePullInterval = func(imageID string, path string) (bool, error) { return true, nil } - imageFetcher = image.NewFetcher(logging.NewLogWithWriters(&outBuf, &outBuf), docker, mockImagePullChecker) + imageFetcher = image.NewFetcher(logging.NewLogWithWriters(&outBuf, &outBuf), docker, mockImagePullPolicyHandler) }) it.After(func() { - mockImagePullChecker.MockCheckImagePullInterval = nil + mockImagePullPolicyHandler.MockCheckImagePullInterval = nil h.DockerRmi(docker, repoName) }) diff --git a/pkg/image/pull_policy.go b/pkg/image/pull_policy.go index bca560b85b..1d9a47bff4 100644 --- a/pkg/image/pull_policy.go +++ b/pkg/image/pull_policy.go @@ -12,6 +12,8 @@ import ( "github.com/pkg/errors" + "github.com/buildpacks/imgutil/local" + "github.com/buildpacks/pack/internal/config" "github.com/buildpacks/pack/pkg/logging" ) @@ -75,24 +77,22 @@ func DefaultImageJSONPath() (string, error) { var nameMap = map[string]PullPolicy{"always": PullAlways, "hourly": PullHourly, "daily": PullDaily, "weekly": PullWeekly, "never": PullNever, "if-not-present": PullIfNotPresent, "": PullAlways} // ParsePullPolicy from string with support for interval formats -func ParsePullPolicy(policy string, logger logging.Logger) (PullPolicy, error) { - pullPolicyManager := NewPullPolicyManager(logger) - +func (i *ImagePullPolicyManager) ParsePullPolicy(policy string) (PullPolicy, error) { if val, ok := nameMap[policy]; ok { if val == PullHourly { - err := pullPolicyManager.updateImageJSONDuration(hourly) + err := i.UpdateImageJSONDuration(hourly) if err != nil { return PullAlways, err } } if val == PullDaily { - err := pullPolicyManager.updateImageJSONDuration(daily) + err := i.UpdateImageJSONDuration(daily) if err != nil { return PullAlways, err } } if val == PullWeekly { - err := pullPolicyManager.updateImageJSONDuration(weekly) + err := i.UpdateImageJSONDuration(weekly) if err != nil { return PullAlways, err } @@ -109,7 +109,7 @@ func ParsePullPolicy(policy string, logger logging.Logger) (PullPolicy, error) { return PullAlways, errors.Errorf("invalid interval format: %s", intervalStr) } - err := pullPolicyManager.updateImageJSONDuration(intervalStr) + err := i.UpdateImageJSONDuration(intervalStr) if err != nil { return PullAlways, err } @@ -141,7 +141,7 @@ func (p PullPolicy) String() string { return "" } -func (i *ImagePullPolicyManager) updateImageJSONDuration(intervalStr string) error { +func (i *ImagePullPolicyManager) UpdateImageJSONDuration(intervalStr string) error { path, err := DefaultImageJSONPath() if err != nil { return err @@ -188,7 +188,7 @@ func parseDurationString(durationStr string) (time.Duration, error) { return time.Duration(totalMinutes) * time.Minute, nil } -func (i *ImagePullPolicyManager) PruneOldImages(f *Fetcher) error { +func (i *ImagePullPolicyManager) PruneOldImages(docker DockerClient) error { path, err := DefaultImageJSONPath() if err != nil { return err @@ -229,8 +229,11 @@ func (i *ImagePullPolicyManager) PruneOldImages(f *Fetcher) error { return errors.Wrap(err, "failed to parse image timestamp fron JSON") } - _, err = f.fetchDaemonImage(imageID) - if !errors.Is(err, ErrNotFound) { + image, err := local.NewImage(imageID, docker, local.FromBaseImage(imageID)) + if err != nil { + return err + } + if !image.Found() { delete(imageJSON.Image.ImageIDtoTIME, imageID) } diff --git a/pkg/image/pull_policy_test.go b/pkg/image/pull_policy_test.go index 41fde7fddf..6fe10fca6f 100644 --- a/pkg/image/pull_policy_test.go +++ b/pkg/image/pull_policy_test.go @@ -1,12 +1,15 @@ package image_test import ( + "bytes" "testing" "github.com/sclevine/spec" "github.com/sclevine/spec/report" "github.com/buildpacks/pack/pkg/image" + "github.com/buildpacks/pack/pkg/logging" + fetcher_mock "github.com/buildpacks/pack/pkg/testmocks" h "github.com/buildpacks/pack/testhelpers" ) @@ -16,55 +19,66 @@ func TestPullPolicy(t *testing.T) { func testPullPolicy(t *testing.T, when spec.G, it spec.S) { when("#ParsePullPolicy", func() { + var ( + outBuf bytes.Buffer + logger logging.Logger + imagePullChecker image.ImagePullPolicyHandler + ) + + it.Before(func() { + logger = logging.NewLogWithWriters(&outBuf, &outBuf) + imagePullChecker = fetcher_mock.NewMockPullPolicyManager(logger) + }) + it("returns PullNever for never", func() { - policy, err := image.ParsePullPolicy("never", logger) + policy, err := imagePullChecker.ParsePullPolicy("never") h.AssertNil(t, err) h.AssertEq(t, policy, image.PullNever) }) it("returns PullAlways for always", func() { - policy, err := image.ParsePullPolicy("always", logger) + policy, err := imagePullChecker.ParsePullPolicy("always") h.AssertNil(t, err) h.AssertEq(t, policy, image.PullAlways) }) it("returns PullIfNotPresent for if-not-present", func() { - policy, err := image.ParsePullPolicy("if-not-present", logger) + policy, err := imagePullChecker.ParsePullPolicy("if-not-present") h.AssertNil(t, err) h.AssertEq(t, policy, image.PullIfNotPresent) }) it("returns PullHourly for hourly", func() { - policy, err := image.ParsePullPolicy("hourly", logger) + policy, err := imagePullChecker.ParsePullPolicy("hourly") h.AssertNil(t, err) h.AssertEq(t, policy, image.PullHourly) }) it("returns PullDaily for daily", func() { - policy, err := image.ParsePullPolicy("daily", logger) + policy, err := imagePullChecker.ParsePullPolicy("daily") h.AssertNil(t, err) h.AssertEq(t, policy, image.PullDaily) }) it("returns PullWeekly for weekly", func() { - policy, err := image.ParsePullPolicy("weekly", logger) + policy, err := imagePullChecker.ParsePullPolicy("weekly") h.AssertNil(t, err) h.AssertEq(t, policy, image.PullWeekly) }) it("returns PullWithInterval for interval= format", func() { - policy, err := image.ParsePullPolicy("interval=4d", logger) + policy, err := imagePullChecker.ParsePullPolicy("interval=4d") h.AssertNil(t, err) h.AssertEq(t, policy, image.PullWithInterval) }) it("returns error for unknown string", func() { - _, err := image.ParsePullPolicy("fake-policy-here", logger) + _, err := imagePullChecker.ParsePullPolicy("fake-policy-here") h.AssertError(t, err, "invalid pull policy") }) it("returns error for invalid interval format", func() { - _, err := image.ParsePullPolicy("interval=invalid", logger) + _, err := imagePullChecker.ParsePullPolicy("interval=invalid") h.AssertError(t, err, "invalid interval format") }) }) diff --git a/pkg/testmocks/mock_image_fetcher.go b/pkg/testmocks/mock_image_fetcher.go index 281f28d04d..90225529e2 100644 --- a/pkg/testmocks/mock_image_fetcher.go +++ b/pkg/testmocks/mock_image_fetcher.go @@ -11,9 +11,13 @@ import ( imgutil "github.com/buildpacks/imgutil" gomock "github.com/golang/mock/gomock" + "github.com/buildpacks/pack/pkg/logging" + image "github.com/buildpacks/pack/pkg/image" ) +var imageJSON *image.ImageJSON + // MockImageFetcher is a mock of ImageFetcher interface. type MockImageFetcher struct { ctrl *gomock.Controller @@ -25,6 +29,17 @@ type MockImageFetcherMockRecorder struct { mock *MockImageFetcher } +type MockImagePullPolicyHandler struct { + *image.ImagePullPolicyManager + MockParsePullPolicy func(policy string, logger logging.Logger) (image.PullPolicy, error) + MockCheckImagePullInterval func(imageID string, path string) (bool, error) + MockPruneOldImages func(docker *image.DockerClient) error + MockUpdateImagePullRecord func(path string, imageID string, timestamp string) error + MockUpdateImageJSONDuration func(intervalStr string) error + MockRead func(path string) (*image.ImageJSON, error) + MockWrite func(imageJSON *image.ImageJSON, path string) error +} + // NewMockImageFetcher creates a new mock instance. func NewMockImageFetcher(ctrl *gomock.Controller) *MockImageFetcher { mock := &MockImageFetcher{ctrl: ctrl} @@ -51,3 +66,66 @@ func (mr *MockImageFetcherMockRecorder) Fetch(arg0, arg1, arg2 interface{}) *gom mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Fetch", reflect.TypeOf((*MockImageFetcher)(nil).Fetch), arg0, arg1, arg2) } + +func NewMockPullPolicyManager(logger logging.Logger) *MockImagePullPolicyHandler { + return &MockImagePullPolicyHandler{} +} + +func (m *MockImagePullPolicyHandler) CheckImagePullInterval(imageID string, path string) (bool, error) { + if m.MockCheckImagePullInterval != nil { + return m.MockCheckImagePullInterval(imageID, path) + } + return false, nil +} + +func (m *MockImagePullPolicyHandler) Write(imageJSON *image.ImageJSON, path string) error { + if m.MockWrite != nil { + return m.MockWrite(imageJSON, path) + } + return nil +} + +func (m *MockImagePullPolicyHandler) Read(path string) (*image.ImageJSON, error) { + if m.MockRead != nil { + return m.MockRead(path) + } + + imageJSON = &image.ImageJSON{ + Interval: &image.Interval{ + PullingInterval: "7d", + PruningInterval: "7d", + LastPrune: "2023-01-01T00:00:00Z", + }, + Image: &image.ImageData{ + ImageIDtoTIME: map[string]string{ + "repoName": "2023-01-01T00:00:00Z", + }, + }, + } + + return imageJSON, nil +} + +func (m *MockImagePullPolicyHandler) PruneOldImages(docker image.DockerClient) error { + if m.MockPruneOldImages != nil { + return m.MockPruneOldImages(&docker) + } + + return m.ImagePullPolicyManager.PruneOldImages(docker) +} + +func (m *MockImagePullPolicyHandler) UpdateImagePullRecord(path string, imageID string, timestamp string) error { + if m.MockUpdateImagePullRecord != nil { + return m.MockUpdateImagePullRecord(path, imageID, timestamp) + } + + return nil +} + +func (m *MockImagePullPolicyHandler) UpdateImageJSONDuration(intervalStr string) error { + if m.MockUpdateImageJSONDuration != nil { + return m.MockUpdateImageJSONDuration(intervalStr) + } + + return nil +}