diff --git a/runkit/decorate.go b/runkit/decorate.go index b6d7085..268a9a8 100644 --- a/runkit/decorate.go +++ b/runkit/decorate.go @@ -17,28 +17,35 @@ import ( func Decorate(ctx context.Context, src, dest string, runxConfig, runxDoc []byte) error { var ( - index v1.ImageIndex - desc *remote.Descriptor - remoteOpts = registry.WithOptions(ctx, nil) - ref, _ = name.ParseReference(src) - destRef, _ = name.ParseReference(dest) - runxImage, runxDesc, err = Image(runxConfig, runxDoc) + err error + index v1.ImageIndex + desc *remote.Descriptor + remoteOpts = registry.WithOptions(ctx, nil) + ref, destRef name.Reference + runxImage v1.Image + runxDesc *v1.Descriptor ) - if err != nil { + if ref, err = name.ParseReference(src); err != nil { + return err + } + if destRef, err = name.ParseReference(dest); err != nil { + return err + } + if runxImage, runxDesc, err = Image(runxConfig, runxDoc); err != nil { return fmt.Errorf("could not create runx image: %w", err) } if src == "scratch" { index = // create a manifest - mutate.AppendManifests( - // as an index - mutate.IndexMediaType(empty.Index, types.OCIImageIndex), - // and the new runx image - mutate.IndexAddendum{ - Add: runxImage, - Descriptor: *runxDesc, - }) + mutate.AppendManifests( + // as an index + mutate.IndexMediaType(empty.Index, types.OCIImageIndex), + // and the new runx image + mutate.IndexAddendum{ + Add: runxImage, + Descriptor: *runxDesc, + }) } else { desc, err = remote.Get(ref, remoteOpts...) if err != nil { @@ -55,19 +62,19 @@ func Decorate(ctx context.Context, src, dest string, runxConfig, runxDoc []byte) imgDesc.Platform = configFile.Platform() index = // create a manifest - mutate.AppendManifests( - // as an index - mutate.IndexMediaType(empty.Index, types.OCIImageIndex), - // with the referenced image - mutate.IndexAddendum{ - Add: img, - Descriptor: imgDesc, - }, - // and the new runx image - mutate.IndexAddendum{ - Add: runxImage, - Descriptor: *runxDesc, - }) + mutate.AppendManifests( + // as an index + mutate.IndexMediaType(empty.Index, types.OCIImageIndex), + // with the referenced image + mutate.IndexAddendum{ + Add: img, + Descriptor: imgDesc, + }, + // and the new runx image + mutate.IndexAddendum{ + Add: runxImage, + Descriptor: *runxDesc, + }) } else if desc.MediaType.IsIndex() { index, err = remote.Index(ref, remoteOpts...) if err != nil { diff --git a/runkit/runkit_test.go b/runkit/runkit_test.go new file mode 100644 index 0000000..4f10ce8 --- /dev/null +++ b/runkit/runkit_test.go @@ -0,0 +1,82 @@ +package runkit + +import ( + "context" + "io" + "log" + "net/http/httptest" + "net/url" + "strings" + "testing" + + "github.com/google/go-containerregistry/pkg/registry" +) + +func TestDecorateReferences(t *testing.T) { + t.Run("wrong input source", func(t *testing.T) { + t.Parallel() + reg := newTestRegistry(t) + imgDest := reg + "/test-references:" + strings.ReplaceAll(t.Name(), "/", "_") + err := Decorate(context.TODO(), "not/a:valid/reference", imgDest, []byte("default: run"), nil) + if err == nil { + t.Error("should raise an error about invalid reference") + } else if !strings.Contains(err.Error(), "could not parse reference") { + t.Error("should raise an error about invalid reference") + } + }) + + t.Run("wrong input source", func(t *testing.T) { + t.Parallel() + err := Decorate(context.TODO(), "scratch", "not/a:valid/reference", nil, nil) + if err == nil { + t.Error("should raise an error about invalid reference") + } else if !strings.Contains(err.Error(), "could not parse reference") { + t.Error("should raise an error about invalid reference") + } + }) +} + +func TestDecorateFromScratch(t *testing.T) { + t.Run("readme only", func(t *testing.T) { + t.Parallel() + reg := newTestRegistry(t) + imgDest := reg + "/test-scratch:" + strings.ReplaceAll(t.Name(), "/", "_") + err := Decorate(context.TODO(), "scratch", imgDest, nil, []byte("# Docker Runx\n\n**Hello!**")) + if err != nil { + t.Error(err) + } + }) + + t.Run("config only", func(t *testing.T) { + t.Parallel() + reg := newTestRegistry(t) + imgDest := reg + "/test-scratch:" + strings.ReplaceAll(t.Name(), "/", "_") + err := Decorate(context.TODO(), "scratch", imgDest, []byte("default: run"), nil) + if err != nil { + t.Error(err) + } + }) + + t.Run("both", func(t *testing.T) { + t.Parallel() + reg := newTestRegistry(t) + imgDest := reg + "/test-scratch:" + strings.ReplaceAll(t.Name(), "/", "_") + err := Decorate(context.TODO(), "scratch", imgDest, []byte("default: run"), []byte("# Docker Runx\n\n**Hello!**")) + if err != nil { + t.Error(err) + } + }) +} + +func newTestRegistry(t *testing.T) string { + s := httptest.NewServer( + registry.New( + registry.WithBlobHandler(registry.NewInMemoryBlobHandler()), + registry.Logger(log.New(io.Discard, "", log.Ldate)))) + t.Cleanup(s.Close) + u, err := url.Parse(s.URL) + if err != nil { + t.Fatal(err) + } + return u.Host +}