diff --git a/cmd/buildah/bud.go b/cmd/buildah/bud.go index 4cd9043d7..0b44e66d5 100644 --- a/cmd/buildah/bud.go +++ b/cmd/buildah/bud.go @@ -185,6 +185,7 @@ func budCmd(c *cli.Context) error { IIDFile: c.String("iidfile"), Squash: c.Bool("squash"), Labels: c.StringSlice("label"), + Annotations: c.StringSlice("annotation"), } if !c.Bool("quiet") { diff --git a/commit.go b/commit.go index ec8c8b6de..75d2626f5 100644 --- a/commit.go +++ b/commit.go @@ -5,7 +5,6 @@ import ( "fmt" "io" "io/ioutil" - "strings" "time" cp "github.com/containers/image/copy" @@ -53,8 +52,6 @@ type CommitOptions struct { // Squash tells the builder to produce an image with a single layer // instead of with possibly more than one layer. Squash bool - // Labels metadata for an image - Labels []string } // PushOptions can be used to alter how an image is copied somewhere. @@ -89,15 +86,6 @@ type PushOptions struct { func (b *Builder) Commit(ctx context.Context, dest types.ImageReference, options CommitOptions) (string, error) { var imgID string - for _, labelSpec := range options.Labels { - label := strings.SplitN(labelSpec, "=", 2) - if len(label) > 1 { - b.SetLabel(label[0], label[1]) - } else { - b.SetLabel(label[0], "") - } - } - systemContext := getSystemContext(options.SystemContext, options.SignaturePolicyPath) policy, err := signature.DefaultPolicy(systemContext) if err != nil { diff --git a/contrib/completions/bash/buildah b/contrib/completions/bash/buildah index a18150825..b34d41c44 100644 --- a/contrib/completions/bash/buildah +++ b/contrib/completions/bash/buildah @@ -366,6 +366,7 @@ return 1 local options_with_args=" --add-host + --annotation --authfile --build-arg --cert-dir diff --git a/docs/buildah-bud.md b/docs/buildah-bud.md index c50330000..d8c0b30f7 100644 --- a/docs/buildah-bud.md +++ b/docs/buildah-bud.md @@ -26,6 +26,12 @@ Add a custom host-to-IP mapping (host:ip) Add a line to /etc/hosts. The format is hostname:ip. The **--add-host** option can be set multiple times. +**--annotation** *annotation* + +Add an image *annotation* (e.g. annotation=*value*) to the image metadata. Can be used multiple times. + +Note: this information is not present in Docker image formats, so it is discarded when writing images in Docker formats. + **--authfile** *path* Path of the authentication file. Default is ${XDG\_RUNTIME\_DIR}/containers/auth.json, which is set using `podman login`. diff --git a/imagebuildah/build.go b/imagebuildah/build.go index a18638c8c..5472c1db5 100644 --- a/imagebuildah/build.go +++ b/imagebuildah/build.go @@ -118,6 +118,8 @@ type BuildOptions struct { Squash bool // Labels metadata for an image Labels []string + // Annotation metadata for an image + Annotations []string } // Executor is a buildah-based implementation of the imagebuilder.Executor @@ -157,6 +159,7 @@ type Executor struct { iidfile string squash bool labels []string + annotations []string } // withName creates a new child executor that will be used whenever a COPY statement uses --from=NAME. @@ -490,7 +493,8 @@ func NewExecutor(store storage.Store, options BuildOptions) (*Executor, error) { defaultMountsFilePath: options.DefaultMountsFilePath, iidfile: options.IIDFile, squash: options.Squash, - labels: options.Labels, + labels: append([]string{}, options.Labels...), + annotations: append([]string{}, options.Annotations...), } if exec.err == nil { exec.err = os.Stderr @@ -682,6 +686,22 @@ func (b *Executor) Commit(ctx context.Context, ib *imagebuilder.Builder) (err er for k, v := range config.Labels { b.builder.SetLabel(k, v) } + for _, labelSpec := range b.labels { + label := strings.SplitN(labelSpec, "=", 2) + if len(label) > 1 { + b.builder.SetLabel(label[0], label[1]) + } else { + b.builder.SetLabel(label[0], "") + } + } + for _, annotationSpec := range b.annotations { + annotation := strings.SplitN(annotationSpec, "=", 2) + if len(annotation) > 1 { + b.builder.SetAnnotation(annotation[0], annotation[1]) + } else { + b.builder.SetAnnotation(annotation[0], "") + } + } if imageRef != nil { logName := transports.ImageName(imageRef) logrus.Debugf("COMMIT %q", logName) @@ -702,7 +722,6 @@ func (b *Executor) Commit(ctx context.Context, ib *imagebuilder.Builder) (err er PreferredManifestType: b.outputFormat, IIDFile: b.iidfile, Squash: b.squash, - Labels: b.labels, } imgID, err := b.builder.Commit(ctx, imageRef, options) if err != nil { diff --git a/pkg/cli/common.go b/pkg/cli/common.go index f622106fe..e65dba2bd 100644 --- a/pkg/cli/common.go +++ b/pkg/cli/common.go @@ -11,6 +11,10 @@ import ( var ( BudFlags = []cli.Flag{ + cli.StringSliceFlag{ + Name: "annotation", + Usage: "Set metadata for an image (default [])", + }, cli.StringFlag{ Name: "authfile", Usage: "path of the authentication file. Default is ${XDG_RUNTIME_DIR}/containers/auth.json", diff --git a/tests/bud.bats b/tests/bud.bats index 23442bbf8..928d0c558 100644 --- a/tests/bud.bats +++ b/tests/bud.bats @@ -37,6 +37,16 @@ load helpers buildah rmi ${target} } +@test "bud-from-scratch-annotation" { + target=scratch-image + buildah bud --annotation "test=annotation" --signature-policy ${TESTSDIR}/policy.json -t ${target} ${TESTSDIR}/bud/from-scratch + run buildah --debug=false inspect --format '{{printf "%q" .ImageAnnotations}}' ${target} + echo "$output" + [ "$status" -eq 0 ] + [ "$output" = 'map["test":"annotation"]' ] + buildah rmi ${target} +} + @test "bud-from-multiple-files-one-from" { target=scratch-image buildah bud --signature-policy ${TESTSDIR}/policy.json -t ${target} -f ${TESTSDIR}/bud/from-multiple-files/Dockerfile1.scratch -f ${TESTSDIR}/bud/from-multiple-files/Dockerfile2.nofrom