Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow mutate.Annotations to annotate an Image or ImageIndex #1082

Merged
merged 3 commits into from
Jul 20, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Allow mutate.Annotations to annotate an Image or ImageIndex
  • Loading branch information
imjasonh committed Jul 16, 2021
commit 27df88a0a99918d33040ea17944b5c3a08d9868f
3 changes: 2 additions & 1 deletion cmd/crane/cmd/mutate.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (

"github.com/google/go-containerregistry/pkg/crane"
"github.com/google/go-containerregistry/pkg/name"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/mutate"
"github.com/spf13/cobra"
)
Expand Down Expand Up @@ -91,7 +92,7 @@ func NewCmdMutate(options *[]crane.Option) *cobra.Command {
log.Fatalf("mutating config: %v", err)
}

img = mutate.Annotations(img, annotations)
img = mutate.Annotations(img, annotations).(v1.Image)

// If the new ref isn't provided, write over the original image.
// If that ref was provided by digest (e.g., output from
Expand Down
22 changes: 16 additions & 6 deletions pkg/v1/mutate/index.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,13 @@ type index struct {
// remove is removed before adds
remove match.Matcher

computed bool
manifest *v1.IndexManifest
mediaType *types.MediaType
imageMap map[v1.Hash]v1.Image
indexMap map[v1.Hash]v1.ImageIndex
layerMap map[v1.Hash]v1.Layer
computed bool
manifest *v1.IndexManifest
annotations map[string]string
mediaType *types.MediaType
imageMap map[v1.Hash]v1.Image
indexMap map[v1.Hash]v1.ImageIndex
layerMap map[v1.Hash]v1.Layer
}

var _ v1.ImageIndex = (*index)(nil)
Expand Down Expand Up @@ -137,6 +138,15 @@ func (i *index) compute() error {
}
}

if i.annotations != nil {
if manifest.Annotations == nil {
manifest.Annotations = map[string]string{}
}
for k, v := range i.annotations {
manifest.Annotations[k] = v
}
}

i.manifest = manifest
i.computed = true
return nil
Expand Down
41 changes: 36 additions & 5 deletions pkg/v1/mutate/mutate.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/empty"
"github.com/google/go-containerregistry/pkg/v1/match"
"github.com/google/go-containerregistry/pkg/v1/partial"
"github.com/google/go-containerregistry/pkg/v1/tarball"
"github.com/google/go-containerregistry/pkg/v1/types"
)
Expand Down Expand Up @@ -113,12 +114,42 @@ func Config(base v1.Image, cfg v1.Config) (v1.Image, error) {
return ConfigFile(base, cf)
}

// Annotations mutates the provided v1.Image to have the provided annotations
func Annotations(base v1.Image, annotations map[string]string) v1.Image {
return &image{
base: base,
annotations: annotations,
// Annotateable represents a manifest that can carry annotations.
imjasonh marked this conversation as resolved.
Show resolved Hide resolved
type Annotateable interface {
partial.WithRawManifest
}

// Annotations mutates the annotations on an annotateable image or index manifest.
//
// The annotateable input is expected to be a v1.Image or v1.ImageIndex, and
// returns the same type. You can type-assert the result like so:
//
// img := Annotations(empty.Image, map[string]string{
// "foo": "bar",
// }).(v1.Image)
//
// Or for an index:
//
// idx := Annotations(empty.Index, map[string]string{
// "foo": "bar",
// }).(v1.ImageIndex)
//
// If the input Annotateable is not an Image or ImageIndex, it is simply
// returned without modification.
func Annotations(f Annotateable, anns map[string]string) Annotateable {
if img, ok := f.(v1.Image); ok {
return &image{
base: img,
annotations: anns,
}
}
if idx, ok := f.(v1.ImageIndex); ok {
return &index{
base: idx,
annotations: anns,
}
}
return f
imjasonh marked this conversation as resolved.
Show resolved Hide resolved
}

// ConfigFile mutates the provided v1.Image to have the provided v1.ConfigFile
Expand Down
2 changes: 1 addition & 1 deletion pkg/v1/mutate/mutate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ func TestAnnotations(t *testing.T) {
"im.the.first.annotation": "hello world",
}

result := mutate.Annotations(source, newAnnotations)
result := mutate.Annotations(source, newAnnotations).(v1.Image)

if configDigestsAreEqual(t, source, result) {
t.Errorf("mutating the manifest annotations MUST mutate the config digest")
Expand Down