diff --git a/cmd/build.go b/cmd/build.go index 92ecf09a..605ac86c 100644 --- a/cmd/build.go +++ b/cmd/build.go @@ -27,6 +27,7 @@ NAME SYNOPSIS {{rootCmdUse}} build [-r|--registry] [--builder] [--builder-image] [--push] [--platform] [-p|--path] [-c|--confirm] [-v|--verbose] + [--build-timestamp] DESCRIPTION @@ -64,7 +65,7 @@ EXAMPLES `, SuggestFor: []string{"biuld", "buidl", "built"}, - PreRunE: bindEnv("image", "path", "builder", "registry", "confirm", "push", "builder-image", "platform", "verbose"), + PreRunE: bindEnv("image", "path", "builder", "registry", "confirm", "push", "builder-image", "platform", "verbose", "build-timestamp"), RunE: func(cmd *cobra.Command, args []string) error { return runBuild(cmd, args, newClient) }, @@ -105,6 +106,7 @@ EXAMPLES "Specify a custom builder image for use by the builder other than its default. ($FUNC_BUILDER_IMAGE)") cmd.Flags().StringP("image", "i", f.Image, "Full image name in the form [registry]/[namespace]/[name]:[tag] (optional). This option takes precedence over --registry ($FUNC_IMAGE)") + cmd.Flags().BoolP("build-timestamp", "", false, "Use the actual time as the created time for the docker image. This is only useful for buildpacks builder.") // Static Flags: // Options which have static defaults only (not globally configurable nor @@ -171,7 +173,9 @@ func runBuild(cmd *cobra.Command, _ []string, newClient ClientFactory) (err erro if f.Build.Builder == builders.Pack { builder = buildpacks.NewBuilder( buildpacks.WithName(builders.Pack), - buildpacks.WithVerbose(cfg.Verbose)) + buildpacks.WithVerbose(cfg.Verbose), + buildpacks.WithTimestamp(cfg.WithTimestamp), + ) } else if f.Build.Builder == builders.S2I { builder = s2i.NewBuilder( s2i.WithName(builders.S2I), @@ -220,6 +224,10 @@ type buildConfig struct { // Push the resulting image to the registry after building. Push bool + + // Build with the current timestamp as the created time for docker image. + // This is only useful for buildpacks builder. + WithTimestamp bool } // newBuildConfig gathers options into a single build request. @@ -231,11 +239,12 @@ func newBuildConfig() buildConfig { Registry: registry(), // deferred defaulting Verbose: viper.GetBool("verbose"), }, - BuilderImage: viper.GetString("builder-image"), - Image: viper.GetString("image"), - Path: viper.GetString("path"), - Platform: viper.GetString("platform"), - Push: viper.GetBool("push"), + BuilderImage: viper.GetString("builder-image"), + Image: viper.GetString("image"), + Path: viper.GetString("path"), + Platform: viper.GetString("platform"), + Push: viper.GetBool("push"), + WithTimestamp: viper.GetBool("build-timestamp"), } } diff --git a/cmd/deploy.go b/cmd/deploy.go index c4ce00af..ab9b2f7a 100644 --- a/cmd/deploy.go +++ b/cmd/deploy.go @@ -32,7 +32,7 @@ SYNOPSIS {{rootCmdUse}} deploy [-R|--remote] [-r|--registry] [-i|--image] [-n|--namespace] [-e|env] [-g|--git-url] [-t|git-branch] [-d|--git-dir] [-b|--build] [--builder] [--builder-image] [-p|--push] - [--platform] [-c|--confirm] [-v|--verbose] + [--platform] [-c|--confirm] [-v|--verbose] [--build-timestamp] DESCRIPTION @@ -116,7 +116,7 @@ EXAMPLES `, SuggestFor: []string{"delpoy", "deplyo"}, - PreRunE: bindEnv("confirm", "env", "git-url", "git-branch", "git-dir", "remote", "build", "builder", "builder-image", "image", "registry", "push", "platform", "namespace", "path", "verbose", "pvc-size"), + PreRunE: bindEnv("confirm", "env", "git-url", "git-branch", "git-dir", "remote", "build", "builder", "builder-image", "image", "registry", "push", "platform", "namespace", "path", "verbose", "pvc-size", "build-timestamp"), RunE: func(cmd *cobra.Command, args []string) error { return runDeploy(cmd, newClient) }, @@ -178,6 +178,7 @@ EXAMPLES "Push the function image to registry before deploying. ($FUNC_PUSH)") cmd.Flags().String("platform", "", "Optionally specify a specific platform to build for (e.g. linux/amd64). ($FUNC_PLATFORM)") + cmd.Flags().BoolP("build-timestamp", "", false, "Use the actual time as the created time for the docker image. This is only useful for buildpacks builder.") // Oft-shared flags: addConfirmFlag(cmd, cfg.Confirm) @@ -240,7 +241,9 @@ func runDeploy(cmd *cobra.Command, newClient ClientFactory) (err error) { if f.Build.Builder == builders.Pack { builder = buildpacks.NewBuilder( buildpacks.WithName(builders.Pack), - buildpacks.WithVerbose(cfg.Verbose)) + buildpacks.WithVerbose(cfg.Verbose), + buildpacks.WithTimestamp(cfg.WithTimestamp), + ) } else if f.Build.Builder == builders.S2I { builder = s2i.NewBuilder( s2i.WithName(builders.S2I), @@ -374,21 +377,26 @@ type deployConfig struct { // PVCSize configures the PVC size used by the pipeline if --remote flag is set. PVCSize string + + // Build with the current timestamp as the created time for docker image. + // This is only useful for buildpacks builder. + WithTimestamp bool } // newDeployConfig creates a buildConfig populated from command flags and // environment variables; in that precedence. func newDeployConfig(cmd *cobra.Command) (c deployConfig) { c = deployConfig{ - buildConfig: newBuildConfig(), - Build: viper.GetString("build"), - Env: viper.GetStringSlice("env"), - GitBranch: viper.GetString("git-branch"), - GitDir: viper.GetString("git-dir"), - GitURL: viper.GetString("git-url"), - Namespace: viper.GetString("namespace"), - Remote: viper.GetBool("remote"), - PVCSize: viper.GetString("pvc-size"), + buildConfig: newBuildConfig(), + Build: viper.GetString("build"), + Env: viper.GetStringSlice("env"), + GitBranch: viper.GetString("git-branch"), + GitDir: viper.GetString("git-dir"), + GitURL: viper.GetString("git-url"), + Namespace: viper.GetString("namespace"), + Remote: viper.GetBool("remote"), + PVCSize: viper.GetString("pvc-size"), + WithTimestamp: viper.GetBool("build-timestamp"), } // NOTE: .Env should be viper.GetStringSlice, but this returns unparsed // results and appears to be an open issue since 2017: diff --git a/pkg/builders/buildpacks/builder.go b/pkg/builders/buildpacks/builder.go index 901bdf01..86bff634 100644 --- a/pkg/builders/buildpacks/builder.go +++ b/pkg/builders/buildpacks/builder.go @@ -7,6 +7,7 @@ import ( "io" "runtime" "strings" + "time" "github.com/Masterminds/semver" pack "github.com/buildpacks/pack/pkg/client" @@ -50,9 +51,10 @@ type Builder struct { name string verbose bool // in non-verbose mode contains std[err,out], so it can be printed on error - outBuff bytes.Buffer - logger logging.Logger - impl Impl + outBuff bytes.Buffer + logger logging.Logger + impl Impl + withTimestamp bool } // Impl allows for the underlying implementation to be mocked for tests. @@ -97,6 +99,12 @@ func WithImpl(i Impl) Option { } } +func WithTimestamp(v bool) Option { + return func(b *Builder) { + b.withTimestamp = v + } +} + var DefaultLifecycleImage = "quay.io/boson/lifecycle@sha256:f53fea9ec9188b92cab0b8a298ff852d76a6c2aaf56f968a08637e13de0e0c59" // Build the Function at path. @@ -119,6 +127,10 @@ func (b *Builder) Build(ctx context.Context, f fn.Function) (err error) { Volumes []string }{Network: "", Volumes: nil}, } + if b.withTimestamp { + now := time.Now() + opts.CreationTime = &now + } if opts.Env, err = fn.Interpolate(f.Build.BuildEnvs); err != nil { return err }