Skip to content

Commit 6ad67aa

Browse files
committed
Add index annotation support
Signed-off-by: TiR <70480807+TIR44@users.noreply.github.com>
1 parent 73856e6 commit 6ad67aa

4 files changed

Lines changed: 175 additions & 1 deletion

File tree

cnb_index.go

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package imgutil
22

33
import (
4+
"encoding/json"
45
"fmt"
56
"os"
67
"path/filepath"
@@ -142,6 +143,11 @@ func (h *CNBIndex) SetAnnotations(digest name.Digest, annotations map[string]str
142143
})
143144
}
144145

146+
func (h *CNBIndex) SetIndexAnnotations(annotations map[string]string) (err error) {
147+
h.ImageIndex = mutate.Annotations(h.ImageIndex, annotations).(v1.ImageIndex)
148+
return nil
149+
}
150+
145151
func (h *CNBIndex) SetArchitecture(digest name.Digest, arch string) (err error) {
146152
return h.replaceDescriptor(digest, func(descriptor v1.Descriptor) (v1.Descriptor, error) {
147153
descriptor.Platform.Architecture = arch
@@ -256,7 +262,7 @@ func (h *CNBIndex) SaveDir() error {
256262
if len(errs.Errors) != 0 {
257263
return errs
258264
}
259-
return nil
265+
return writeIndexAnnotations(path, index.Annotations)
260266
}
261267

262268
func appendManifest(desc v1.Descriptor, path layout.Path, errs *SaveError) {
@@ -272,6 +278,31 @@ func appendManifest(desc v1.Descriptor, path layout.Path, errs *SaveError) {
272278
}
273279
}
274280

281+
func writeIndexAnnotations(path layout.Path, annotations map[string]string) error {
282+
if len(annotations) == 0 {
283+
return nil
284+
}
285+
286+
imageIndex, err := path.ImageIndex()
287+
if err != nil {
288+
return err
289+
}
290+
291+
index, err := imageIndex.IndexManifest()
292+
if err != nil {
293+
return err
294+
}
295+
296+
index.Annotations = annotations
297+
298+
rawIndex, err := json.MarshalIndent(index, "", " ")
299+
if err != nil {
300+
return err
301+
}
302+
303+
return path.WriteFile("index.json", rawIndex, os.ModePerm)
304+
}
305+
275306
func newEmptyLayoutPath(indexType types.MediaType, path string) (layout.Path, error) {
276307
if indexType == types.OCIImageIndex {
277308
return layout.Write(path, empty.Index)

cnb_index_test.go

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
package imgutil_test
2+
3+
import (
4+
"encoding/json"
5+
"os"
6+
"path/filepath"
7+
"testing"
8+
9+
"github.com/google/go-cmp/cmp"
10+
v1 "github.com/google/go-containerregistry/pkg/v1"
11+
"github.com/google/go-containerregistry/pkg/v1/random"
12+
"github.com/google/go-containerregistry/pkg/v1/types"
13+
14+
"github.com/buildpacks/imgutil"
15+
)
16+
17+
func TestCNBIndexSetIndexAnnotations(t *testing.T) {
18+
for _, test := range []struct {
19+
name string
20+
mediaType types.MediaType
21+
expectedMediaType types.MediaType
22+
}{
23+
{
24+
name: "oci index",
25+
expectedMediaType: types.OCIImageIndex,
26+
},
27+
{
28+
name: "docker index",
29+
mediaType: types.DockerManifestList,
30+
expectedMediaType: types.DockerManifestList,
31+
},
32+
} {
33+
t.Run(test.name, func(t *testing.T) {
34+
tmpDir := t.TempDir()
35+
repoName := "some/index"
36+
37+
index, err := imgutil.NewCNBIndex(repoName, imgutil.IndexOptions{
38+
MediaType: test.mediaType,
39+
LayoutIndexOptions: imgutil.LayoutIndexOptions{
40+
XdgPath: tmpDir,
41+
},
42+
})
43+
if err != nil {
44+
t.Fatal(err)
45+
}
46+
47+
image, err := random.Image(1024, 1)
48+
if err != nil {
49+
t.Fatal(err)
50+
}
51+
index.AddManifest(image)
52+
53+
existingAnnotations := map[string]string{
54+
"existing-key": "existing-value",
55+
"shared-key": "old-value",
56+
}
57+
if err := index.SetIndexAnnotations(existingAnnotations); err != nil {
58+
t.Fatal(err)
59+
}
60+
61+
newAnnotations := map[string]string{
62+
"some-index-key": "some-index-value",
63+
"shared-key": "new-value",
64+
}
65+
if err := index.SetIndexAnnotations(newAnnotations); err != nil {
66+
t.Fatal(err)
67+
}
68+
if err := index.SaveDir(); err != nil {
69+
t.Fatal(err)
70+
}
71+
72+
expectedAnnotations := map[string]string{
73+
"existing-key": "existing-value",
74+
"some-index-key": "some-index-value",
75+
"shared-key": "new-value",
76+
}
77+
indexManifest := readIndexManifest(t, tmpDir, repoName)
78+
if diff := cmp.Diff(expectedAnnotations, indexManifest.Annotations); diff != "" {
79+
t.Fatalf("unexpected index annotations (-want +got):\n%s", diff)
80+
}
81+
if diff := cmp.Diff(test.expectedMediaType, indexManifest.MediaType); diff != "" {
82+
t.Fatalf("unexpected index media type (-want +got):\n%s", diff)
83+
}
84+
if diff := cmp.Diff(1, len(indexManifest.Manifests)); diff != "" {
85+
t.Fatalf("unexpected manifest count (-want +got):\n%s", diff)
86+
}
87+
})
88+
}
89+
}
90+
91+
func TestCNBIndexSaveDirWithoutIndexAnnotations(t *testing.T) {
92+
tmpDir := t.TempDir()
93+
repoName := "some/index"
94+
95+
index, err := imgutil.NewCNBIndex(repoName, imgutil.IndexOptions{
96+
LayoutIndexOptions: imgutil.LayoutIndexOptions{
97+
XdgPath: tmpDir,
98+
},
99+
})
100+
if err != nil {
101+
t.Fatal(err)
102+
}
103+
104+
image, err := random.Image(1024, 1)
105+
if err != nil {
106+
t.Fatal(err)
107+
}
108+
index.AddManifest(image)
109+
110+
if err := index.SaveDir(); err != nil {
111+
t.Fatal(err)
112+
}
113+
114+
indexManifest := readIndexManifest(t, tmpDir, repoName)
115+
if diff := cmp.Diff(map[string]string(nil), indexManifest.Annotations); diff != "" {
116+
t.Fatalf("unexpected index annotations (-want +got):\n%s", diff)
117+
}
118+
if diff := cmp.Diff(1, len(indexManifest.Manifests)); diff != "" {
119+
t.Fatalf("unexpected manifest count (-want +got):\n%s", diff)
120+
}
121+
}
122+
123+
func readIndexManifest(t *testing.T, tmpDir, repoName string) v1.IndexManifest {
124+
t.Helper()
125+
126+
rawIndex, err := os.ReadFile(filepath.Join(tmpDir, imgutil.MakeFileSafeName(repoName), "index.json"))
127+
if err != nil {
128+
t.Fatal(err)
129+
}
130+
131+
var indexManifest v1.IndexManifest
132+
if err := json.Unmarshal(rawIndex, &indexManifest); err != nil {
133+
t.Fatal(err)
134+
}
135+
136+
return indexManifest
137+
}

fakes/image_index.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,11 @@ func (i ImageIndex) SetAnnotations(_ name.Digest, _ map[string]string) error {
7373
panic("unimplemented")
7474
}
7575

76+
// SetIndexAnnotations implements imgutil.ImageIndex.
77+
func (i ImageIndex) SetIndexAnnotations(_ map[string]string) error {
78+
panic("unimplemented")
79+
}
80+
7681
// SetArchitecture implements imgutil.ImageIndex.
7782
func (i ImageIndex) SetArchitecture(_ name.Digest, _ string) error {
7883
panic("unimplemented")

index.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ type ImageIndex interface {
1919
// setters
2020

2121
SetAnnotations(digest name.Digest, annotations map[string]string) (err error)
22+
SetIndexAnnotations(annotations map[string]string) (err error)
2223
SetArchitecture(digest name.Digest, arch string) (err error)
2324
SetOS(digest name.Digest, os string) (err error)
2425
SetVariant(digest name.Digest, osVariant string) (err error)

0 commit comments

Comments
 (0)