From c76a2ed6ff3402451bf5a741ca8e1676e8381ab2 Mon Sep 17 00:00:00 2001 From: Gergely Brautigam <182850+Skarlso@users.noreply.github.com> Date: Thu, 24 Oct 2024 12:28:16 +0200 Subject: [PATCH 01/58] Revert "feat: replace docker with oras (#904)" (#1005) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 3cfa228726daebb061989b27b620698d24c555d2. #### What this PR does / why we need it #### Which issue(s) this PR fixes --------- Co-authored-by: Jakob Möller --- .../extensions/repositories/ocireg/blobs.go | 109 +++ .../repositories/ocireg/namespace.go | 178 ++--- .../repositories/ocireg/repository.go | 107 ++- .../extensions/repositories/ocireg/utils.go | 60 +- .../pubsub/providers/ocireg/provider.go | 14 +- api/tech/docker/README.md | 4 + api/tech/docker/errors/errors.go | 58 ++ api/tech/docker/fetcher.go | 202 ++++++ api/tech/docker/handler.go | 136 ++++ api/tech/docker/httpreadseeker.go | 157 +++++ api/tech/docker/lister.go | 130 ++++ api/tech/docker/orig.go | 44 ++ api/tech/docker/pusher.go | 433 ++++++++++++ api/tech/docker/registry.go | 234 +++++++ api/tech/docker/resolve/interface.go | 75 ++ api/tech/docker/resolver.go | 656 ++++++++++++++++++ go.mod | 4 +- go.sum | 2 - 18 files changed, 2414 insertions(+), 189 deletions(-) create mode 100644 api/oci/extensions/repositories/ocireg/blobs.go create mode 100644 api/tech/docker/README.md create mode 100644 api/tech/docker/errors/errors.go create mode 100644 api/tech/docker/fetcher.go create mode 100644 api/tech/docker/handler.go create mode 100644 api/tech/docker/httpreadseeker.go create mode 100644 api/tech/docker/lister.go create mode 100644 api/tech/docker/orig.go create mode 100644 api/tech/docker/pusher.go create mode 100644 api/tech/docker/registry.go create mode 100644 api/tech/docker/resolve/interface.go create mode 100644 api/tech/docker/resolver.go diff --git a/api/oci/extensions/repositories/ocireg/blobs.go b/api/oci/extensions/repositories/ocireg/blobs.go new file mode 100644 index 0000000000..0ecf1b299d --- /dev/null +++ b/api/oci/extensions/repositories/ocireg/blobs.go @@ -0,0 +1,109 @@ +package ocireg + +import ( + "sync" + + "github.com/containerd/containerd/remotes" + "github.com/mandelsoft/goutils/errors" + "github.com/opencontainers/go-digest" + "github.com/sirupsen/logrus" + + "ocm.software/ocm/api/oci/cpi" + "ocm.software/ocm/api/oci/extensions/attrs/cacheattr" + "ocm.software/ocm/api/tech/docker/resolve" + "ocm.software/ocm/api/utils/accessio" + "ocm.software/ocm/api/utils/blobaccess/blobaccess" +) + +type BlobContainer interface { + GetBlobData(digest digest.Digest) (int64, cpi.DataAccess, error) + AddBlob(blob cpi.BlobAccess) (int64, digest.Digest, error) + Unref() error +} + +type blobContainer struct { + accessio.StaticAllocatable + fetcher resolve.Fetcher + pusher resolve.Pusher + mime string +} + +type BlobContainers struct { + lock sync.Mutex + cache accessio.BlobCache + fetcher resolve.Fetcher + pusher resolve.Pusher + mimes map[string]BlobContainer +} + +func NewBlobContainers(ctx cpi.Context, fetcher remotes.Fetcher, pusher resolve.Pusher) *BlobContainers { + return &BlobContainers{ + cache: cacheattr.Get(ctx), + fetcher: fetcher, + pusher: pusher, + mimes: map[string]BlobContainer{}, + } +} + +func (c *BlobContainers) Get(mime string) (BlobContainer, error) { + c.lock.Lock() + defer c.lock.Unlock() + + found := c.mimes[mime] + if found == nil { + container, err := NewBlobContainer(c.cache, mime, c.fetcher, c.pusher) + if err != nil { + return nil, err + } + c.mimes[mime] = container + + return container, nil + } + + return found, nil +} + +func (c *BlobContainers) Release() error { + c.lock.Lock() + defer c.lock.Unlock() + list := errors.ErrListf("releasing mime block caches") + for _, b := range c.mimes { + list.Add(b.Unref()) + } + return list.Result() +} + +func newBlobContainer(mime string, fetcher resolve.Fetcher, pusher resolve.Pusher) *blobContainer { + return &blobContainer{ + mime: mime, + fetcher: fetcher, + pusher: pusher, + } +} + +func NewBlobContainer(cache accessio.BlobCache, mime string, fetcher resolve.Fetcher, pusher resolve.Pusher) (BlobContainer, error) { + c := newBlobContainer(mime, fetcher, pusher) + + if cache == nil { + return c, nil + } + r, err := accessio.CachedAccess(c, c, cache) + if err != nil { + return nil, err + } + return r, nil +} + +func (n *blobContainer) GetBlobData(digest digest.Digest) (int64, cpi.DataAccess, error) { + logrus.Debugf("orig get %s %s\n", n.mime, digest) + acc, err := NewDataAccess(n.fetcher, digest, n.mime, false) + return blobaccess.BLOB_UNKNOWN_SIZE, acc, err +} + +func (n *blobContainer) AddBlob(blob cpi.BlobAccess) (int64, digest.Digest, error) { + err := push(dummyContext, n.pusher, blob) + if err != nil { + return blobaccess.BLOB_UNKNOWN_SIZE, blobaccess.BLOB_UNKNOWN_DIGEST, err + } + return blob.Size(), blob.Digest(), err +} diff --git a/api/oci/extensions/repositories/ocireg/namespace.go b/api/oci/extensions/repositories/ocireg/namespace.go index cd46662e7c..9ef8239979 100644 --- a/api/oci/extensions/repositories/ocireg/namespace.go +++ b/api/oci/extensions/repositories/ocireg/namespace.go @@ -4,15 +4,15 @@ import ( "context" "fmt" + "github.com/containerd/errdefs" "github.com/mandelsoft/goutils/errors" "github.com/opencontainers/go-digest" - "oras.land/oras-go/v2/errdef" - "oras.land/oras-go/v2/registry" "ocm.software/ocm/api/oci/artdesc" "ocm.software/ocm/api/oci/cpi" "ocm.software/ocm/api/oci/cpi/support" "ocm.software/ocm/api/oci/extensions/actions/oci-repository-prepare" + "ocm.software/ocm/api/tech/docker/resolve" "ocm.software/ocm/api/utils/accessio" "ocm.software/ocm/api/utils/blobaccess/blobaccess" "ocm.software/ocm/api/utils/logging" @@ -20,108 +20,153 @@ import ( ) type NamespaceContainer struct { - impl support.NamespaceAccessImpl - repo *RepositoryImpl - checked bool - ociRepo registry.Repository + impl support.NamespaceAccessImpl + repo *RepositoryImpl + resolver resolve.Resolver + lister resolve.Lister + fetcher resolve.Fetcher + pusher resolve.Pusher + blobs *BlobContainers + checked bool } var _ support.NamespaceContainer = (*NamespaceContainer)(nil) func NewNamespace(repo *RepositoryImpl, name string) (cpi.NamespaceAccess, error) { ref := repo.GetRef(name, "") - ociRepo, err := repo.getResolver(ref, name) + resolver, err := repo.getResolver(name) + if err != nil { + return nil, err + } + fetcher, err := resolver.Fetcher(context.Background(), ref) + if err != nil { + return nil, err + } + pusher, err := resolver.Pusher(context.Background(), ref) + if err != nil { + return nil, err + } + lister, err := resolver.Lister(context.Background(), ref) if err != nil { return nil, err } - c := &NamespaceContainer{ - repo: repo, - ociRepo: ociRepo, + repo: repo, + resolver: resolver, + lister: lister, + fetcher: fetcher, + pusher: pusher, + blobs: NewBlobContainers(repo.GetContext(), fetcher, pusher), } return support.NewNamespaceAccess(name, c, repo) } func (n *NamespaceContainer) Close() error { - return n.repo.Close() + return n.blobs.Release() } func (n *NamespaceContainer) SetImplementation(impl support.NamespaceAccessImpl) { n.impl = impl } +func (n *NamespaceContainer) getPusher(vers string) (resolve.Pusher, error) { + err := n.assureCreated() + if err != nil { + return nil, err + } + + ref := n.repo.GetRef(n.impl.GetNamespace(), vers) + resolver := n.resolver + + n.repo.GetContext().Logger().Trace("get pusher", "ref", ref) + if ok, _ := artdesc.IsDigest(vers); !ok { + var err error + + resolver, err = n.repo.getResolver(n.impl.GetNamespace()) + if err != nil { + return nil, fmt.Errorf("unable get resolver: %w", err) + } + } + + return resolver.Pusher(dummyContext, ref) +} + +func (n *NamespaceContainer) push(vers string, blob cpi.BlobAccess) error { + p, err := n.getPusher(vers) + if err != nil { + return fmt.Errorf("unable to get pusher: %w", err) + } + n.repo.GetContext().Logger().Trace("pushing", "version", vers) + return push(dummyContext, p, blob) +} + func (n *NamespaceContainer) IsReadOnly() bool { return n.repo.IsReadOnly() } func (n *NamespaceContainer) GetBlobData(digest digest.Digest) (int64, cpi.DataAccess, error) { n.repo.GetContext().Logger().Debug("getting blob", "digest", digest) - - acc, err := NewDataAccess(n.ociRepo, digest, false) + blob, err := n.blobs.Get("") if err != nil { - return -1, nil, fmt.Errorf("failed to construct data access: %w", err) + return -1, nil, fmt.Errorf("failed to retrieve blob data: %w", err) } - - n.repo.GetContext().Logger().Debug("getting blob done", "digest", digest, "size", blobaccess.BLOB_UNKNOWN_SIZE, "error", logging.ErrorMessage(err)) - return blobaccess.BLOB_UNKNOWN_SIZE, acc, err + size, acc, err := blob.GetBlobData(digest) + n.repo.GetContext().Logger().Debug("getting blob done", "digest", digest, "size", size, "error", logging.ErrorMessage(err)) + return size, acc, err } func (n *NamespaceContainer) AddBlob(blob cpi.BlobAccess) error { log := n.repo.GetContext().Logger() log.Debug("adding blob", "digest", blob.Digest()) - - if err := n.assureCreated(); err != nil { - return err + blobData, err := n.blobs.Get("") + if err != nil { + return fmt.Errorf("failed to retrieve blob data: %w", err) } - - if err := push(dummyContext, n.ociRepo, blob); err != nil { + err = n.assureCreated() + if err != nil { return err } - + if _, _, err := blobData.AddBlob(blob); err != nil { + log.Debug("adding blob failed", "digest", blob.Digest(), "error", err.Error()) + return fmt.Errorf("unable to add blob (OCI repository %s): %w", n.impl.GetNamespace(), err) + } log.Debug("adding blob done", "digest", blob.Digest()) return nil } func (n *NamespaceContainer) ListTags() ([]string, error) { - var result []string - if err := n.ociRepo.Tags(dummyContext, "", func(tags []string) error { - result = append(result, tags...) - - return nil - }); err != nil { - return nil, err - } - - return result, nil + return n.lister.List(dummyContext) } func (n *NamespaceContainer) GetArtifact(i support.NamespaceAccessImpl, vers string) (cpi.ArtifactAccess, error) { ref := n.repo.GetRef(n.impl.GetNamespace(), vers) n.repo.GetContext().Logger().Debug("get artifact", "ref", ref) - desc, err := n.ociRepo.Resolve(context.Background(), ref) + _, desc, err := n.resolver.Resolve(context.Background(), ref) n.repo.GetContext().Logger().Debug("done", "digest", desc.Digest, "size", desc.Size, "mimetype", desc.MediaType, "error", logging.ErrorMessage(err)) if err != nil { - if errors.Is(err, errdef.ErrNotFound) { + if errdefs.IsNotFound(err) { return nil, errors.ErrNotFound(cpi.KIND_OCIARTIFACT, ref, n.impl.GetNamespace()) } return nil, err } - - acc, err := NewDataAccess(n.ociRepo, desc.Digest, false) + blobData, err := n.blobs.Get(desc.MediaType) if err != nil { - return nil, fmt.Errorf("failed to construct data access: %w", err) + return nil, fmt.Errorf("failed to retrieve blob data, blob data was empty: %w", err) + } + _, acc, err := blobData.GetBlobData(desc.Digest) + if err != nil { + return nil, err } - return support.NewArtifactForBlob(i, blobaccess.ForDataAccess(desc.Digest, desc.Size, desc.MediaType, acc)) } func (n *NamespaceContainer) HasArtifact(vers string) (bool, error) { ref := n.repo.GetRef(n.impl.GetNamespace(), vers) n.repo.GetContext().Logger().Debug("check artifact", "ref", ref) - desc, err := n.ociRepo.Resolve(context.Background(), ref) + _, desc, err := n.resolver.Resolve(context.Background(), ref) n.repo.GetContext().Logger().Debug("done", "digest", desc.Digest, "size", desc.Size, "mimetype", desc.MediaType, "error", logging.ErrorMessage(err)) if err != nil { - if errors.Is(err, errdef.ErrNotFound) { + if errdefs.IsNotFound(err) { return false, nil } return false, err @@ -159,15 +204,20 @@ func (n *NamespaceContainer) AddArtifact(artifact cpi.Artifact, tags ...string) } n.repo.GetContext().Logger().Debug("adding artifact", "digest", blob.Digest(), "mimetype", blob.MimeType()) + blobData, err := n.blobs.Get(blob.MimeType()) + if err != nil { + return nil, fmt.Errorf("failed to retrieve blob data: %w", err) + } - if err := n.assureCreated(); err != nil { + _, _, err = blobData.AddBlob(blob) + if err != nil { return nil, err } if len(tags) > 0 { for _, tag := range tags { - if err := n.pushTag(blob, tag); err != nil { - return nil, fmt.Errorf("failed to push tag %s: %w", tag, err) + if err := n.push(tag, blob); err != nil { + return nil, err } } } @@ -175,52 +225,22 @@ func (n *NamespaceContainer) AddArtifact(artifact cpi.Artifact, tags ...string) return blob, err } -func (n *NamespaceContainer) pushTag(blob blobaccess.BlobAccess, tag string) error { - reader, err := blob.Reader() - if err != nil { - return err - } - - expectedDescriptor := *artdesc.DefaultBlobDescriptor(blob) - // If the descriptor exists, we are adding the blob to the descriptor as is. - if err := n.ociRepo.PushReference(context.Background(), expectedDescriptor, reader, tag); err != nil { - // If the manifest is unknown to the registry, which can occur with Docker, - // we might be able to push the entire blob instead of a reference. - // We can't assert the error because docker returns Manifest Unknown, - // while ghcr.io or quay work with PushReference out of the box. - // Meanwhile, we need to get the reader again, because PushReference exhausted it. - reader, err = blob.Reader() - if err != nil { - return err - } - - // If any other error arises, pushing the blob would also fail. - return n.ociRepo.Blobs().Push(context.Background(), expectedDescriptor, reader) - } - - return nil -} - func (n *NamespaceContainer) AddTags(digest digest.Digest, tags ...string) error { - ref := n.repo.GetRef(n.impl.GetNamespace(), digest.String()) - desc, err := n.ociRepo.Resolve(context.Background(), ref) + _, desc, err := n.resolver.Resolve(context.Background(), n.repo.GetRef(n.impl.GetNamespace(), digest.String())) if err != nil { return fmt.Errorf("unable to resolve: %w", err) } - acc, err := NewDataAccess(n.ociRepo, desc.Digest, false) + acc, err := NewDataAccess(n.fetcher, desc.Digest, desc.MediaType, false) if err != nil { return fmt.Errorf("error creating new data access: %w", err) } - if err := n.assureCreated(); err != nil { - return err - } - blob := blobaccess.ForDataAccess(desc.Digest, desc.Size, desc.MediaType, acc) for _, tag := range tags { - if err := n.pushTag(blob, tag); err != nil { - return fmt.Errorf("failed to push tag %s: %w", tag, err) + err := n.push(tag, blob) + if err != nil { + return fmt.Errorf("unable to push: %w", err) } } diff --git a/api/oci/extensions/repositories/ocireg/repository.go b/api/oci/extensions/repositories/ocireg/repository.go index 061879a0d2..1bae127a71 100644 --- a/api/oci/extensions/repositories/ocireg/repository.go +++ b/api/oci/extensions/repositories/ocireg/repository.go @@ -4,23 +4,20 @@ import ( "context" "crypto/tls" "crypto/x509" - "fmt" - "net/http" "path" "strings" + "github.com/containerd/containerd/remotes/docker/config" + "github.com/containerd/errdefs" "github.com/mandelsoft/goutils/errors" "github.com/mandelsoft/logging" - "oras.land/oras-go/v2/errdef" - "oras.land/oras-go/v2/registry" - "oras.land/oras-go/v2/registry/remote" - "oras.land/oras-go/v2/registry/remote/auth" - "oras.land/oras-go/v2/registry/remote/retry" "ocm.software/ocm/api/credentials" "ocm.software/ocm/api/datacontext/attrs/rootcertsattr" "ocm.software/ocm/api/oci/artdesc" "ocm.software/ocm/api/oci/cpi" + "ocm.software/ocm/api/tech/docker" + "ocm.software/ocm/api/tech/docker/resolve" "ocm.software/ocm/api/tech/oci/identity" "ocm.software/ocm/api/utils" ocmlog "ocm.software/ocm/api/utils/logging" @@ -115,7 +112,7 @@ func (r *RepositoryImpl) getCreds(comp string) (credentials.Credentials, error) return identity.GetCredentials(r.GetContext(), r.info.Locator, comp) } -func (r *RepositoryImpl) getResolver(ref string, comp string) (registry.Repository, error) { +func (r *RepositoryImpl) getResolver(comp string) (resolve.Resolver, error) { creds, err := r.getCreds(comp) if err != nil { if !errors.IsErrUnknownKind(err, credentials.KIND_CONSUMER) { @@ -126,59 +123,53 @@ func (r *RepositoryImpl) getResolver(ref string, comp string) (registry.Reposito if creds == nil { logger.Trace("no credentials") } - repo, err := remote.NewRepository(ref) - if err != nil { - return nil, fmt.Errorf("error creating oci repository: %w", err) - } - - authCreds := auth.Credential{} - if creds != nil { - pass := creds.GetProperty(credentials.ATTR_IDENTITY_TOKEN) - if pass == "" { - pass = creds.GetProperty(credentials.ATTR_PASSWORD) - } - authCreds.Username = creds.GetProperty(credentials.ATTR_USERNAME) - authCreds.Password = pass - } - client := http.DefaultClient - if r.info.Scheme == "https" { - // set up TLS - //nolint:gosec // used like the default, there are OCI servers (quay.io) not working with min version. - conf := &tls.Config{ - // MinVersion: tls.VersionTLS13, - RootCAs: func() *x509.CertPool { - var rootCAs *x509.CertPool + opts := docker.ResolverOptions{ + Hosts: docker.ConvertHosts(config.ConfigureHosts(context.Background(), config.HostOptions{ + Credentials: func(host string) (string, string, error) { if creds != nil { - c := creds.GetProperty(credentials.ATTR_CERTIFICATE_AUTHORITY) - if c != "" { - rootCAs = x509.NewCertPool() - rootCAs.AppendCertsFromPEM([]byte(c)) + p := creds.GetProperty(credentials.ATTR_IDENTITY_TOKEN) + if p == "" { + p = creds.GetProperty(credentials.ATTR_PASSWORD) } + pw := "" + if p != "" { + pw = "***" + } + logger.Trace("query credentials", ocmlog.ATTR_USER, creds.GetProperty(credentials.ATTR_USERNAME), "pass", pw) + return creds.GetProperty(credentials.ATTR_USERNAME), p, nil + } + logger.Trace("no credentials") + return "", "", nil + }, + DefaultScheme: r.info.Scheme, + //nolint:gosec // used like the default, there are OCI servers (quay.io) not working with min version. + DefaultTLS: func() *tls.Config { + if r.info.Scheme == "http" { + return nil } - if rootCAs == nil { - rootCAs = rootcertsattr.Get(r.GetContext()).GetRootCertPool(true) + return &tls.Config{ + // MinVersion: tls.VersionTLS13, + RootCAs: func() *x509.CertPool { + var rootCAs *x509.CertPool + if creds != nil { + c := creds.GetProperty(credentials.ATTR_CERTIFICATE_AUTHORITY) + if c != "" { + rootCAs = x509.NewCertPool() + rootCAs.AppendCertsFromPEM([]byte(c)) + } + } + if rootCAs == nil { + rootCAs = rootcertsattr.Get(r.GetContext()).GetRootCertPool(true) + } + return rootCAs + }(), } - return rootCAs }(), - } - - client = &http.Client{ - Transport: retry.NewTransport(&http.Transport{ - TLSClientConfig: conf, - }), - } - } else { - repo.PlainHTTP = true - } - - repo.Client = &auth.Client{ - Client: client, - Cache: auth.NewCache(), - Credential: auth.StaticCredential(r.info.HostPort(), authCreds), + })), } - return repo, nil + return docker.NewResolver(opts), nil } func (r *RepositoryImpl) GetRef(comp, vers string) string { @@ -197,14 +188,14 @@ func (r *RepositoryImpl) GetBaseURL() string { } func (r *RepositoryImpl) ExistsArtifact(name string, version string) (bool, error) { - ref := r.GetRef(name, version) - res, err := r.getResolver(ref, name) + res, err := r.getResolver(name) if err != nil { return false, err } - - if _, err = res.Resolve(context.Background(), ref); err != nil { - if errors.Is(err, errdef.ErrNotFound) { + ref := r.GetRef(name, version) + _, _, err = res.Resolve(context.Background(), ref) + if err != nil { + if errdefs.IsNotFound(err) { return false, nil } return false, err diff --git a/api/oci/extensions/repositories/ocireg/utils.go b/api/oci/extensions/repositories/ocireg/utils.go index 828582f064..17a96f040a 100644 --- a/api/oci/extensions/repositories/ocireg/utils.go +++ b/api/oci/extensions/repositories/ocireg/utils.go @@ -2,21 +2,19 @@ package ocireg import ( "context" - "errors" "fmt" "io" "sync" "github.com/containerd/containerd/remotes" + "github.com/containerd/errdefs" "github.com/containerd/log" "github.com/opencontainers/go-digest" "github.com/sirupsen/logrus" - "oras.land/oras-go/v2/content" - "oras.land/oras-go/v2/errdef" - "oras.land/oras-go/v2/registry" "ocm.software/ocm/api/oci/artdesc" "ocm.software/ocm/api/oci/cpi" + "ocm.software/ocm/api/tech/docker/resolve" "ocm.software/ocm/api/utils/accessio" "ocm.software/ocm/api/utils/blobaccess/blobaccess" "ocm.software/ocm/api/utils/logging" @@ -26,40 +24,32 @@ import ( type dataAccess struct { accessio.NopCloser - lock sync.Mutex - repo registry.Repository - desc artdesc.Descriptor - reader io.ReadCloser + lock sync.Mutex + fetcher remotes.Fetcher + desc artdesc.Descriptor + reader io.ReadCloser } var _ cpi.DataAccess = (*dataAccess)(nil) -func NewDataAccess(repo registry.Repository, digest digest.Digest, delayed bool) (*dataAccess, error) { +func NewDataAccess(fetcher remotes.Fetcher, digest digest.Digest, mimeType string, delayed bool) (*dataAccess, error) { var reader io.ReadCloser - // First, we try to resolve a blob if a blob was already provided, this will work. - desc, err := repo.Blobs().Resolve(dummyContext, digest.String()) - if err != nil { - if errors.Is(err, errdef.ErrNotFound) { - // If the provided digest was that of a manifest, the second try will find - // the manifest, because the first one didn't find the blob. - desc, err = repo.Resolve(dummyContext, digest.String()) - if err != nil { - return nil, err - } - } else { - return nil, fmt.Errorf("failed to resolve descriptor with digest %s: %w", digest.String(), err) - } + var err error + desc := artdesc.Descriptor{ + MediaType: mimeType, + Digest: digest, + Size: blobaccess.BLOB_UNKNOWN_SIZE, } if !delayed { - reader, err = repo.Fetch(dummyContext, desc) + reader, err = fetcher.Fetch(dummyContext, desc) if err != nil { - return nil, fmt.Errorf("failed to fetch descriptor: %w", err) + return nil, err } } return &dataAccess{ - repo: repo, - desc: desc, - reader: reader, + fetcher: fetcher, + desc: desc, + reader: reader, }, nil } @@ -75,7 +65,7 @@ func (d *dataAccess) Reader() (io.ReadCloser, error) { if reader != nil { return reader, nil } - return d.repo.Fetch(dummyContext, d.desc) + return d.fetcher.Fetch(dummyContext, d.desc) } func readAll(reader io.ReadCloser, err error) ([]byte, error) { @@ -91,32 +81,28 @@ func readAll(reader io.ReadCloser, err error) ([]byte, error) { return data, nil } -func push(ctx context.Context, p content.Pusher, blob blobaccess.BlobAccess) error { +func push(ctx context.Context, p resolve.Pusher, blob blobaccess.BlobAccess) error { desc := *artdesc.DefaultBlobDescriptor(blob) return pushData(ctx, p, desc, blob) } -func pushData(ctx context.Context, p content.Pusher, desc artdesc.Descriptor, data blobaccess.DataAccess) error { +func pushData(ctx context.Context, p resolve.Pusher, desc artdesc.Descriptor, data blobaccess.DataAccess) error { key := remotes.MakeRefKey(ctx, desc) if desc.Size == 0 { desc.Size = -1 } logging.Logger().Debug("*** push blob", "mediatype", desc.MediaType, "digest", desc.Digest, "key", key) - reader, err := data.Reader() + req, err := p.Push(ctx, desc, data) if err != nil { - return err - } - - if err := p.Push(ctx, desc, reader); err != nil { - if errors.Is(err, errdef.ErrAlreadyExists) { + if errdefs.IsAlreadyExists(err) { logging.Logger().Debug("blob already exists", "mediatype", desc.MediaType, "digest", desc.Digest) return nil } return fmt.Errorf("failed to push: %w", err) } - return nil + return req.Commit(ctx, desc.Size, desc.Digest) } var dummyContext = nologger() diff --git a/api/ocm/extensions/pubsub/providers/ocireg/provider.go b/api/ocm/extensions/pubsub/providers/ocireg/provider.go index d2e0e99b25..58c5b435b3 100644 --- a/api/ocm/extensions/pubsub/providers/ocireg/provider.go +++ b/api/ocm/extensions/pubsub/providers/ocireg/provider.go @@ -5,8 +5,8 @@ import ( "fmt" "path" + containererr "github.com/containerd/containerd/remotes/errors" "github.com/mandelsoft/goutils/errors" - "oras.land/oras-go/v2/registry/remote/errcode" "ocm.software/ocm/api/ocm/cpi" "ocm.software/ocm/api/ocm/cpi/repocpi" @@ -45,18 +45,10 @@ func (p *Provider) GetPubSubSpec(repo repocpi.Repository) (pubsub.PubSubSpec, er ocirepo := path.Join(gen.Meta().SubPath, componentmapping.ComponentDescriptorNamespace) acc, err := gen.OCIRepository().LookupArtifact(ocirepo, META) - - // Dirty workaround until fix is ready for https://github.com/open-component-model/ocm/issues/872 - errCode := errcode.Error{} - if errors.As(err, &errCode) { - if errCode.Code == errcode.ErrorCodeDenied { - return nil, nil - } - } - - if errors.IsErrNotFound(err) || errors.IsErrUnknown(err) { + if errors.IsErrNotFound(err) || errors.IsErrUnknown(err) || errors.IsA(err, containererr.ErrUnexpectedStatus{}) { return nil, nil } + if err != nil { return nil, errors.Wrapf(err, "cannot access meta data manifest version") } diff --git a/api/tech/docker/README.md b/api/tech/docker/README.md new file mode 100644 index 0000000000..096a9c1e18 --- /dev/null +++ b/api/tech/docker/README.md @@ -0,0 +1,4 @@ +# containerd + +Taken from github.com/containerd/containerd remotes/docker to add list endpoints +Fix retry of requests with ResendBuffer diff --git a/api/tech/docker/errors/errors.go b/api/tech/docker/errors/errors.go new file mode 100644 index 0000000000..a158f75b5a --- /dev/null +++ b/api/tech/docker/errors/errors.go @@ -0,0 +1,58 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package errors + +import ( + "fmt" + "io" + "net/http" +) + +var _ error = ErrUnexpectedStatus{} + +// ErrUnexpectedStatus is returned if a registry API request returned with unexpected HTTP status +type ErrUnexpectedStatus struct { + Status string + StatusCode int + Body []byte + RequestURL, RequestMethod string +} + +func (e ErrUnexpectedStatus) Error() string { + if len(e.Body) > 0 { + return fmt.Sprintf("unexpected status from %s request to %s: %s: %s", e.RequestMethod, e.RequestURL, e.Status, string(e.Body)) + } + return fmt.Sprintf("unexpected status from %s request to %s: %s", e.RequestMethod, e.RequestURL, e.Status) +} + +// NewUnexpectedStatusErr creates an ErrUnexpectedStatus from HTTP response +func NewUnexpectedStatusErr(resp *http.Response) error { + var b []byte + if resp.Body != nil { + b, _ = io.ReadAll(io.LimitReader(resp.Body, 64000)) // 64KB + } + err := ErrUnexpectedStatus{ + Body: b, + Status: resp.Status, + StatusCode: resp.StatusCode, + RequestMethod: resp.Request.Method, + } + if resp.Request.URL != nil { + err.RequestURL = resp.Request.URL.String() + } + return err +} diff --git a/api/tech/docker/fetcher.go b/api/tech/docker/fetcher.go new file mode 100644 index 0000000000..4a2eec584e --- /dev/null +++ b/api/tech/docker/fetcher.go @@ -0,0 +1,202 @@ +package docker + +import ( + "context" + "encoding/json" + "fmt" + "io" + "net/http" + "net/url" + "strings" + + "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/images" + "github.com/containerd/containerd/log" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/pkg/errors" + + "ocm.software/ocm/api/utils/accessio" +) + +type dockerFetcher struct { + *dockerBase +} + +func (r dockerFetcher) Fetch(ctx context.Context, desc ocispec.Descriptor) (io.ReadCloser, error) { + ctx = log.WithLogger(ctx, log.G(ctx).WithField("digest", desc.Digest)) + + hosts := r.filterHosts(HostCapabilityPull) + if len(hosts) == 0 { + return nil, errors.Wrap(errdefs.ErrNotFound, "no pull hosts") + } + + ctx, err := ContextWithRepositoryScope(ctx, r.refspec, false) + if err != nil { + return nil, err + } + + return newHTTPReadSeeker(desc.Size, func(offset int64) (io.ReadCloser, error) { + // firstly try fetch via external urls + for _, us := range desc.URLs { + ctx = log.WithLogger(ctx, log.G(ctx).WithField("url", us)) + + u, err := url.Parse(us) + if err != nil { + log.G(ctx).WithError(err).Debug("failed to parse") + continue + } + if u.Scheme != "http" && u.Scheme != "https" { + log.G(ctx).Debug("non-http(s) alternative url is unsupported") + continue + } + log.G(ctx).Debug("trying alternative url") + + // Try this first, parse it + host := RegistryHost{ + Client: http.DefaultClient, + Host: u.Host, + Scheme: u.Scheme, + Path: u.Path, + Capabilities: HostCapabilityPull, + } + req := r.request(host, http.MethodGet) + // Strip namespace from base + req.path = u.Path + if u.RawQuery != "" { + req.path = req.path + "?" + u.RawQuery + } + + rc, err := r.open(ctx, req, desc.MediaType, offset) + if err != nil { + if errdefs.IsNotFound(err) { + continue // try one of the other urls. + } + + return nil, err + } + + return rc, nil + } + + // Try manifests endpoints for manifests types + switch desc.MediaType { + case images.MediaTypeDockerSchema2Manifest, images.MediaTypeDockerSchema2ManifestList, + images.MediaTypeDockerSchema1Manifest, + ocispec.MediaTypeImageManifest, ocispec.MediaTypeImageIndex: + + var firstErr error + for _, host := range r.hosts { + req := r.request(host, http.MethodGet, "manifests", desc.Digest.String()) + if err := req.addNamespace(r.refspec.Hostname()); err != nil { + return nil, err + } + + rc, err := r.open(ctx, req, desc.MediaType, offset) + if err != nil { + // Store the error for referencing later + if firstErr == nil { + firstErr = err + } + continue // try another host + } + + return rc, nil + } + + return nil, firstErr + } + + // Finally use blobs endpoints + var firstErr error + for _, host := range r.hosts { + req := r.request(host, http.MethodGet, "blobs", desc.Digest.String()) + if err := req.addNamespace(r.refspec.Hostname()); err != nil { + return nil, err + } + + rc, err := r.open(ctx, req, desc.MediaType, offset) + if err != nil { + // Store the error for referencing later + if firstErr == nil { + firstErr = err + } + continue // try another host + } + + return rc, nil + } + + if errdefs.IsNotFound(firstErr) { + firstErr = errors.Wrapf(errdefs.ErrNotFound, + "could not fetch content descriptor %v (%v) from remote", + desc.Digest, desc.MediaType) + } + + return nil, firstErr + }) +} + +func (r dockerFetcher) open(ctx context.Context, req *request, mediatype string, offset int64) (_ io.ReadCloser, retErr error) { + mt := "*/*" + if mediatype != "" { + mt = mediatype + ", " + mt + } + req.header.Set("Accept", mt) + + if offset > 0 { + // Note: "Accept-Ranges: bytes" cannot be trusted as some endpoints + // will return the header without supporting the range. The content + // range must always be checked. + req.header.Set("Range", fmt.Sprintf("bytes=%d-", offset)) + } + + resp, err := req.doWithRetries(ctx, nil) + if err != nil { + return nil, accessio.RetriableError(err) + } + defer func() { + if retErr != nil { + resp.Body.Close() + } + }() + + if resp.StatusCode > 299 { + // TODO(stevvooe): When doing a offset specific request, we should + // really distinguish between a 206 and a 200. In the case of 200, we + // can discard the bytes, hiding the seek behavior from the + // implementation. + + if resp.StatusCode == http.StatusNotFound { + return nil, errors.Wrapf(errdefs.ErrNotFound, "content at %v not found", req.String()) + } + var registryErr Errors + if err := json.NewDecoder(resp.Body).Decode(®istryErr); err != nil || registryErr.Len() < 1 { + return nil, errors.Errorf("unexpected status code %v: %v", req.String(), resp.Status) + } + return nil, errors.Errorf("unexpected status code %v: %s - Server message: %s", req.String(), resp.Status, registryErr.Error()) + } + if offset > 0 { + cr := resp.Header.Get("content-range") + if cr != "" { + if !strings.HasPrefix(cr, fmt.Sprintf("bytes %d-", offset)) { + return nil, errors.Errorf("unhandled content range in response: %v", cr) + } + } else { + // TODO: Should any cases where use of content range + // without the proper header be considered? + // 206 responses? + + // Discard up to offset + // Could use buffer pool here but this case should be rare + n, err := io.Copy(io.Discard, io.LimitReader(resp.Body, offset)) + if err != nil { + return nil, errors.Wrap(err, "failed to discard to offset") + } + if n != offset { + return nil, errors.Errorf("unable to discard to offset") + } + } + } + + return resp.Body, nil +} diff --git a/api/tech/docker/handler.go b/api/tech/docker/handler.go new file mode 100644 index 0000000000..0ff9959ad3 --- /dev/null +++ b/api/tech/docker/handler.go @@ -0,0 +1,136 @@ +package docker + +import ( + "context" + "fmt" + "net/url" + "strings" + + "github.com/containerd/containerd/content" + "github.com/containerd/containerd/images" + "github.com/containerd/containerd/labels" + "github.com/containerd/containerd/log" + "github.com/containerd/containerd/reference" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" +) + +// labelDistributionSource describes the source blob comes from. +var labelDistributionSource = "containerd.io/distribution.source" + +// AppendDistributionSourceLabel updates the label of blob with distribution source. +func AppendDistributionSourceLabel(manager content.Manager, ref string) (images.HandlerFunc, error) { + refspec, err := reference.Parse(ref) + if err != nil { + return nil, err + } + + u, err := url.Parse("dummy://" + refspec.Locator) + if err != nil { + return nil, err + } + + source, repo := u.Hostname(), strings.TrimPrefix(u.Path, "/") + return func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) { + info, err := manager.Info(ctx, desc.Digest) + if err != nil { + return nil, err + } + + key := distributionSourceLabelKey(source) + + originLabel := "" + if info.Labels != nil { + originLabel = info.Labels[key] + } + value := appendDistributionSourceLabel(originLabel, repo) + + // The repo name has been limited under 256 and the distribution + // label might hit the limitation of label size, when blob data + // is used as the very, very common layer. + if err := labels.Validate(key, value); err != nil { + log.G(ctx).Warnf("skip to append distribution label: %s", err) + return nil, nil + } + + info = content.Info{ + Digest: desc.Digest, + Labels: map[string]string{ + key: value, + }, + } + _, err = manager.Update(ctx, info, fmt.Sprintf("labels.%s", key)) + return nil, err + }, nil +} + +func appendDistributionSourceLabel(originLabel, repo string) string { + repos := []string{} + if originLabel != "" { + repos = strings.Split(originLabel, ",") + } + repos = append(repos, repo) + + // use empty string to present duplicate items + for i := 1; i < len(repos); i++ { + tmp, j := repos[i], i-1 + for ; j >= 0 && repos[j] >= tmp; j-- { + if repos[j] == tmp { + tmp = "" + } + repos[j+1] = repos[j] + } + repos[j+1] = tmp + } + + i := 0 + for ; i < len(repos) && repos[i] == ""; i++ { + } + + return strings.Join(repos[i:], ",") +} + +func distributionSourceLabelKey(source string) string { + return fmt.Sprintf("%s.%s", labelDistributionSource, source) +} + +// selectRepositoryMountCandidate will select the repo which has longest +// common prefix components as the candidate. +func selectRepositoryMountCandidate(refspec reference.Spec, sources map[string]string) string { + u, err := url.Parse("dummy://" + refspec.Locator) + if err != nil { + // NOTE: basically, it won't be error here + return "" + } + + source, target := u.Hostname(), strings.TrimPrefix(u.Path, "/") + repoLabel, ok := sources[distributionSourceLabelKey(source)] + if !ok || repoLabel == "" { + return "" + } + + n, match := 0, "" + components := strings.Split(target, "/") + for _, repo := range strings.Split(repoLabel, ",") { + // the target repo is not a candidate + if repo == target { + continue + } + + if l := commonPrefixComponents(components, repo); l >= n { + n, match = l, repo + } + } + return match +} + +func commonPrefixComponents(components []string, target string) int { + targetComponents := strings.Split(target, "/") + + i := 0 + for ; i < len(components) && i < len(targetComponents); i++ { + if components[i] != targetComponents[i] { + break + } + } + return i +} diff --git a/api/tech/docker/httpreadseeker.go b/api/tech/docker/httpreadseeker.go new file mode 100644 index 0000000000..c6b803810b --- /dev/null +++ b/api/tech/docker/httpreadseeker.go @@ -0,0 +1,157 @@ +package docker + +import ( + "bytes" + "io" + + "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/log" + "github.com/pkg/errors" +) + +const maxRetry = 3 + +type httpReadSeeker struct { + size int64 + offset int64 + rc io.ReadCloser + open func(offset int64) (io.ReadCloser, error) + closed bool + + errsWithNoProgress int +} + +func newHTTPReadSeeker(size int64, open func(offset int64) (io.ReadCloser, error)) (io.ReadCloser, error) { + return &httpReadSeeker{ + size: size, + open: open, + }, nil +} + +func (hrs *httpReadSeeker) Read(p []byte) (n int, err error) { + if hrs.closed { + return 0, io.EOF + } + + rd, err := hrs.reader() + if err != nil { + return 0, err + } + + n, err = rd.Read(p) + hrs.offset += int64(n) + if n > 0 || err == nil { + hrs.errsWithNoProgress = 0 + } + + if !errors.Is(err, io.ErrUnexpectedEOF) { + return + } + // connection closed unexpectedly. try reconnecting. + if n == 0 { + hrs.errsWithNoProgress++ + if hrs.errsWithNoProgress > maxRetry { + return // too many retries for this offset with no progress + } + } + + if hrs.rc != nil { + if clsErr := hrs.rc.Close(); clsErr != nil { + log.L.WithError(clsErr).Errorf("httpReadSeeker: failed to close ReadCloser") + } + hrs.rc = nil + } + + if _, err2 := hrs.reader(); err2 == nil { + return n, nil + } + + return n, err +} + +func (hrs *httpReadSeeker) Close() error { + if hrs.closed { + return nil + } + hrs.closed = true + if hrs.rc != nil { + return hrs.rc.Close() + } + + return nil +} + +func (hrs *httpReadSeeker) Seek(offset int64, whence int) (int64, error) { + if hrs.closed { + return 0, errors.Wrap(errdefs.ErrUnavailable, "Fetcher.Seek: closed") + } + + abs := hrs.offset + switch whence { + case io.SeekStart: + abs = offset + case io.SeekCurrent: + abs += offset + case io.SeekEnd: + if hrs.size == -1 { + return 0, errors.Wrap(errdefs.ErrUnavailable, "Fetcher.Seek: unknown size, cannot seek from end") + } + abs = hrs.size + offset + default: + return 0, errors.Wrap(errdefs.ErrInvalidArgument, "Fetcher.Seek: invalid whence") + } + + if abs < 0 { + return 0, errors.Wrapf(errdefs.ErrInvalidArgument, "Fetcher.Seek: negative offset") + } + + if abs != hrs.offset { + if hrs.rc != nil { + if err := hrs.rc.Close(); err != nil { + log.L.WithError(err).Errorf("Fetcher.Seek: failed to close ReadCloser") + } + + hrs.rc = nil + } + + hrs.offset = abs + } + + return hrs.offset, nil +} + +func (hrs *httpReadSeeker) reader() (io.Reader, error) { + if hrs.rc != nil { + return hrs.rc, nil + } + + if hrs.size == -1 || hrs.offset < hrs.size { + // only try to reopen the body request if we are seeking to a value + // less than the actual size. + if hrs.open == nil { + return nil, errors.Wrapf(errdefs.ErrNotImplemented, "cannot open") + } + + rc, err := hrs.open(hrs.offset) + if err != nil { + return nil, errors.Wrapf(err, "httpReadSeeker: failed open") + } + + if hrs.rc != nil { + if err := hrs.rc.Close(); err != nil { + log.L.WithError(err).Errorf("httpReadSeeker: failed to close ReadCloser") + } + } + hrs.rc = rc + } else { + // There is an edge case here where offset == size of the content. If + // we seek, we will probably get an error for content that cannot be + // sought (?). In that case, we should err on committing the content, + // as the length is already satisfied but we just return the empty + // reader instead. + + hrs.rc = io.NopCloser(bytes.NewReader([]byte{})) + } + + return hrs.rc, nil +} diff --git a/api/tech/docker/lister.go b/api/tech/docker/lister.go new file mode 100644 index 0000000000..efd3b8e1e2 --- /dev/null +++ b/api/tech/docker/lister.go @@ -0,0 +1,130 @@ +package docker + +import ( + "context" + "encoding/json" + "io" + "net/http" + + "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/log" + "github.com/pkg/errors" + + "ocm.software/ocm/api/tech/docker/resolve" +) + +var ErrObjectNotRequired = errors.New("object not required") + +type TagList struct { + Name string `json:"name"` + Tags []string `json:"tags"` +} + +type dockerLister struct { + dockerBase *dockerBase +} + +func (r *dockerResolver) Lister(ctx context.Context, ref string) (resolve.Lister, error) { + base, err := r.resolveDockerBase(ref) + if err != nil { + return nil, err + } + if base.refspec.Object != "" { + return nil, ErrObjectNotRequired + } + + return &dockerLister{ + dockerBase: base, + }, nil +} + +func (r *dockerLister) List(ctx context.Context) ([]string, error) { + refspec := r.dockerBase.refspec + base := r.dockerBase + var ( + firstErr error + paths [][]string + caps = HostCapabilityPull + ) + + // turns out, we have a valid digest, make a url. + paths = append(paths, []string{"tags/list"}) + caps |= HostCapabilityResolve + + hosts := base.filterHosts(caps) + if len(hosts) == 0 { + return nil, errors.Wrap(errdefs.ErrNotFound, "no list hosts") + } + + ctx, err := ContextWithRepositoryScope(ctx, refspec, false) + if err != nil { + return nil, err + } + + for _, u := range paths { + for _, host := range hosts { + ctxWithLogger := log.WithLogger(ctx, log.G(ctx).WithField("host", host.Host)) + + req := base.request(host, http.MethodGet, u...) + if err := req.addNamespace(base.refspec.Hostname()); err != nil { + return nil, err + } + + req.header["Accept"] = []string{"application/json"} + + log.G(ctxWithLogger).Debug("listing") + resp, err := req.doWithRetries(ctxWithLogger, nil) + if err != nil { + if errors.Is(err, ErrInvalidAuthorization) { + err = errors.Wrapf(err, "pull access denied, repository does not exist or may require authorization") + } + // Store the error for referencing later + if firstErr == nil { + firstErr = err + } + log.G(ctxWithLogger).WithError(err).Info("trying next host") + continue // try another host + } + + if resp.StatusCode > 299 { + resp.Body.Close() + if resp.StatusCode == http.StatusNotFound { + log.G(ctxWithLogger).Info("trying next host - response was http.StatusNotFound") + continue + } + if resp.StatusCode > 399 { + // Set firstErr when encountering the first non-404 status code. + if firstErr == nil { + firstErr = errors.Errorf("pulling from host %s failed with status code %v: %v", host.Host, u, resp.Status) + } + continue // try another host + } + return nil, errors.Errorf("taglist from host %s failed with unexpected status code %v: %v", host.Host, u, resp.Status) + } + + data, err := io.ReadAll(resp.Body) + resp.Body.Close() + if err != nil { + return nil, err + } + + tags := &TagList{} + + err = json.Unmarshal(data, tags) + if err != nil { + return nil, err + } + return tags.Tags, nil + } + } + + // If above loop terminates without return, then there was an error. + // "firstErr" contains the first non-404 error. That is, "firstErr == nil" + // means that either no registries were given or each registry returned 404. + + if firstErr == nil { + firstErr = errors.Wrap(errdefs.ErrNotFound, base.refspec.Locator) + } + + return nil, firstErr +} diff --git a/api/tech/docker/orig.go b/api/tech/docker/orig.go new file mode 100644 index 0000000000..c9b2468fba --- /dev/null +++ b/api/tech/docker/orig.go @@ -0,0 +1,44 @@ +package docker + +import ( + "github.com/containerd/containerd/remotes/docker" +) + +var ( + ContextWithRepositoryScope = docker.ContextWithRepositoryScope + ContextWithAppendPullRepositoryScope = docker.ContextWithAppendPullRepositoryScope + NewInMemoryTracker = docker.NewInMemoryTracker + NewDockerAuthorizer = docker.NewDockerAuthorizer + WithAuthClient = docker.WithAuthClient + WithAuthHeader = docker.WithAuthHeader + WithAuthCreds = docker.WithAuthCreds +) + +type ( + Errors = docker.Errors + StatusTracker = docker.StatusTracker + Status = docker.Status + StatusTrackLocker = docker.StatusTrackLocker +) + +func ConvertHosts(hosts docker.RegistryHosts) RegistryHosts { + return func(host string) ([]RegistryHost, error) { + list, err := hosts(host) + if err != nil { + return nil, err + } + result := make([]RegistryHost, len(list)) + for i, v := range list { + result[i] = RegistryHost{ + Client: v.Client, + Authorizer: v.Authorizer, + Host: v.Host, + Scheme: v.Scheme, + Path: v.Path, + Capabilities: HostCapabilities(v.Capabilities), + Header: v.Header, + } + } + return result, nil + } +} diff --git a/api/tech/docker/pusher.go b/api/tech/docker/pusher.go new file mode 100644 index 0000000000..708ad0f349 --- /dev/null +++ b/api/tech/docker/pusher.go @@ -0,0 +1,433 @@ +package docker + +import ( + "context" + "io" + "net/http" + "net/url" + "strings" + "time" + + "github.com/containerd/containerd/content" + "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/images" + "github.com/containerd/containerd/log" + "github.com/containerd/containerd/remotes" + "github.com/opencontainers/go-digest" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" + + remoteserrors "ocm.software/ocm/api/tech/docker/errors" + "ocm.software/ocm/api/tech/docker/resolve" + "ocm.software/ocm/api/utils/accessio" +) + +func init() { + l := logrus.New() + l.Level = logrus.WarnLevel + log.L = logrus.NewEntry(l) +} + +type dockerPusher struct { + *dockerBase + object string + + // TODO: namespace tracker + tracker StatusTracker +} + +func (p dockerPusher) Push(ctx context.Context, desc ocispec.Descriptor, src resolve.Source) (resolve.PushRequest, error) { + return p.push(ctx, desc, src, remotes.MakeRefKey(ctx, desc), false) +} + +func (p dockerPusher) push(ctx context.Context, desc ocispec.Descriptor, src resolve.Source, ref string, unavailableOnFail bool) (resolve.PushRequest, error) { + if l, ok := p.tracker.(StatusTrackLocker); ok { + l.Lock(ref) + defer l.Unlock(ref) + } + ctx, err := ContextWithRepositoryScope(ctx, p.refspec, true) + if err != nil { + return nil, err + } + status, err := p.tracker.GetStatus(ref) + if err == nil { + if status.Committed && status.Offset == status.Total { + return nil, errors.Wrapf(errdefs.ErrAlreadyExists, "ref %v", ref) + } + if unavailableOnFail { + // Another push of this ref is happening elsewhere. The rest of function + // will continue only when `errdefs.IsNotFound(err) == true` (i.e. there + // is no actively-tracked ref already). + return nil, errors.Wrap(errdefs.ErrUnavailable, "push is on-going") + } + // TODO: Handle incomplete status + } else if !errdefs.IsNotFound(err) { + return nil, errors.Wrap(err, "failed to get status") + } + + hosts := p.filterHosts(HostCapabilityPush) + if len(hosts) == 0 { + return nil, errors.Wrap(errdefs.ErrNotFound, "no push hosts") + } + + var ( + isManifest bool + existCheck []string + host = hosts[0] + ) + + switch desc.MediaType { + case images.MediaTypeDockerSchema2Manifest, images.MediaTypeDockerSchema2ManifestList, + ocispec.MediaTypeImageManifest, ocispec.MediaTypeImageIndex: + isManifest = true + existCheck = getManifestPath(p.object, desc.Digest) + default: + existCheck = []string{"blobs", desc.Digest.String()} + } + + req := p.request(host, http.MethodHead, existCheck...) + req.header.Set("Accept", strings.Join([]string{desc.MediaType, `*/*`}, ", ")) + + log.G(ctx).WithField("url", req.String()).Debugf("checking and pushing to") + + headResp, err := req.doWithRetries(ctx, nil) + if err != nil { + if !errors.Is(err, ErrInvalidAuthorization) { + return nil, err + } + log.G(ctx).WithError(err).Debugf("Unable to check existence, continuing with push") + } else { + defer headResp.Body.Close() + + if headResp.StatusCode == http.StatusOK { + var exists bool + if isManifest && existCheck[1] != desc.Digest.String() { + dgstHeader := digest.Digest(headResp.Header.Get("Docker-Content-Digest")) + if dgstHeader == desc.Digest { + exists = true + } + } else { + exists = true + } + + if exists { + p.tracker.SetStatus(ref, Status{ + Committed: true, + Status: content.Status{ + Ref: ref, + Total: desc.Size, + Offset: desc.Size, + // TODO: Set updated time? + }, + }) + + return nil, errors.Wrapf(errdefs.ErrAlreadyExists, "content %v on remote", desc.Digest) + } + } else if headResp.StatusCode != http.StatusNotFound { + err := remoteserrors.NewUnexpectedStatusErr(headResp) + + var statusError remoteserrors.ErrUnexpectedStatus + if errors.As(err, &statusError) { + log.G(ctx). + WithField("resp", headResp). + WithField("body", string(statusError.Body)). + Debug("unexpected response") + } + + return nil, accessio.RetriableError(err) + } + } + + if isManifest { + putPath := getManifestPath(p.object, desc.Digest) + req = p.request(host, http.MethodPut, putPath...) + req.header.Add("Content-Type", desc.MediaType) + } else { + // Start upload request + req = p.request(host, http.MethodPost, "blobs", "uploads/") + + var resp *http.Response + if fromRepo := selectRepositoryMountCandidate(p.refspec, desc.Annotations); fromRepo != "" { + preq := requestWithMountFrom(req, desc.Digest.String(), fromRepo) + pctx := ContextWithAppendPullRepositoryScope(ctx, fromRepo) + + // NOTE: the fromRepo might be private repo and + // auth service still can grant token without error. + // but the post request will fail because of 401. + // + // for the private repo, we should remove mount-from + // query and send the request again. + resp, err = preq.doWithRetries(pctx, nil) + if err != nil { + return nil, accessio.RetriableError(err) + } + + if resp.StatusCode == http.StatusUnauthorized { + log.G(ctx).Debugf("failed to mount from repository %s", fromRepo) + + resp.Body.Close() + resp = nil + } + } + + if resp == nil { + resp, err = req.doWithRetries(ctx, nil) + if err != nil { + return nil, accessio.RetriableError(err) + } + } + defer resp.Body.Close() + + switch resp.StatusCode { + case http.StatusOK, http.StatusAccepted, http.StatusNoContent: + case http.StatusCreated: + p.tracker.SetStatus(ref, Status{ + Committed: true, + Status: content.Status{ + Ref: ref, + Total: desc.Size, + Offset: desc.Size, + }, + }) + return nil, errors.Wrapf(errdefs.ErrAlreadyExists, "content %v on remote", desc.Digest) + default: + err := remoteserrors.NewUnexpectedStatusErr(resp) + + var statusError remoteserrors.ErrUnexpectedStatus + if errors.As(err, &statusError) { + log.G(ctx). + WithField("resp", resp). + WithField("body", string(statusError.Body)). + Debug("unexpected response") + } + + return nil, err + } + + var ( + location = resp.Header.Get("Location") + lurl *url.URL + lhost = host + ) + // Support paths without host in location + if strings.HasPrefix(location, "/") { + lurl, err = url.Parse(lhost.Scheme + "://" + lhost.Host + location) + if err != nil { + return nil, errors.Wrapf(err, "unable to parse location %v", location) + } + } else { + if !strings.Contains(location, "://") { + location = lhost.Scheme + "://" + location + } + lurl, err = url.Parse(location) + if err != nil { + return nil, errors.Wrapf(err, "unable to parse location %v", location) + } + + if lurl.Host != lhost.Host || lhost.Scheme != lurl.Scheme { + lhost.Scheme = lurl.Scheme + lhost.Host = lurl.Host + log.G(ctx).WithField("host", lhost.Host).WithField("scheme", lhost.Scheme).Debug("upload changed destination") + + // Strip authorizer if change to host or scheme + lhost.Authorizer = nil + } + } + q := lurl.Query() + q.Add("digest", desc.Digest.String()) + + req = p.request(lhost, http.MethodPut) + req.header.Set("Content-Type", "application/octet-stream") + req.path = lurl.Path + "?" + q.Encode() + } + p.tracker.SetStatus(ref, Status{ + Status: content.Status{ + Ref: ref, + Total: desc.Size, + Expected: desc.Digest, + StartedAt: time.Now(), + }, + }) + + // TODO: Support chunked upload + + respC := make(chan response, 1) + + preq := &pushRequest{ + base: p.dockerBase, + ref: ref, + responseC: respC, + source: src, + isManifest: isManifest, + expected: desc.Digest, + tracker: p.tracker, + } + + req.body = preq.Reader + req.size = desc.Size + + go func() { + defer close(respC) + resp, err := req.doWithRetries(ctx, nil) + if err != nil { + respC <- response{err: err} + return + } + + switch resp.StatusCode { + case http.StatusOK, http.StatusCreated, http.StatusNoContent: + default: + err := remoteserrors.NewUnexpectedStatusErr(resp) + + var statusError remoteserrors.ErrUnexpectedStatus + if errors.As(err, &statusError) { + log.G(ctx). + WithField("resp", resp). + WithField("body", string(statusError.Body)). + Debug("unexpected response") + } + } + respC <- response{Response: resp} + }() + + return preq, nil +} + +func getManifestPath(object string, dgst digest.Digest) []string { + if i := strings.IndexByte(object, '@'); i >= 0 { + if object[i+1:] != dgst.String() { + // use digest, not tag + object = "" + } else { + // strip @ for registry path to make tag + object = object[:i] + } + } + + if object == "" { + return []string{"manifests", dgst.String()} + } + + return []string{"manifests", object} +} + +type response struct { + *http.Response + err error +} + +type pushRequest struct { + base *dockerBase + ref string + + responseC <-chan response + source resolve.Source + isManifest bool + + expected digest.Digest + tracker StatusTracker +} + +func (pw *pushRequest) Status() (content.Status, error) { + status, err := pw.tracker.GetStatus(pw.ref) + if err != nil { + return content.Status{}, err + } + return status.Status, nil +} + +func (pw *pushRequest) Commit(ctx context.Context, size int64, expected digest.Digest, opts ...content.Opt) error { + // TODO: timeout waiting for response + resp := <-pw.responseC + if resp.err != nil { + return resp.err + } + defer resp.Response.Body.Close() + + // 201 is specified return status, some registries return + // 200, 202 or 204. + switch resp.StatusCode { + case http.StatusOK, http.StatusCreated, http.StatusNoContent, http.StatusAccepted: + default: + return remoteserrors.NewUnexpectedStatusErr(resp.Response) + } + + status, err := pw.tracker.GetStatus(pw.ref) + if err != nil { + return errors.Wrap(err, "failed to get status") + } + + if size > 0 && size != status.Offset { + return errors.Errorf("unexpected size %d, expected %d", status.Offset, size) + } + + if expected == "" { + expected = status.Expected + } + + actual, err := digest.Parse(resp.Header.Get("Docker-Content-Digest")) + if err != nil { + return errors.Wrap(err, "invalid content digest in response") + } + + if actual != expected { + return errors.Errorf("got digest %s, expected %s", actual, expected) + } + + status.Committed = true + status.UpdatedAt = time.Now() + pw.tracker.SetStatus(pw.ref, status) + + return nil +} + +func (pw *pushRequest) Reader() (io.ReadCloser, error) { + status, err := pw.tracker.GetStatus(pw.ref) + if err != nil { + return nil, err + } + status.Offset = 0 + status.UpdatedAt = time.Now() + pw.tracker.SetStatus(pw.ref, status) + + r, err := pw.source.Reader() + if err != nil { + return nil, err + } + return &sizeTrackingReader{pw, r}, nil +} + +type sizeTrackingReader struct { + pw *pushRequest + io.ReadCloser +} + +func (t *sizeTrackingReader) Read(in []byte) (int, error) { + // fmt.Printf("reading next...\n") + n, err := t.ReadCloser.Read(in) + if n > 0 { + status, err := t.pw.tracker.GetStatus(t.pw.ref) + // fmt.Printf("read %d[%d] bytes\n", n, status.Offset) + if err != nil { + return n, err + } + status.Offset += int64(n) + status.UpdatedAt = time.Now() + t.pw.tracker.SetStatus(t.pw.ref, status) + } + return n, err +} + +func requestWithMountFrom(req *request, mount, from string) *request { + creq := *req + + sep := "?" + if strings.Contains(creq.path, sep) { + sep = "&" + } + + creq.path = creq.path + sep + "mount=" + mount + "&from=" + from + + return &creq +} diff --git a/api/tech/docker/registry.go b/api/tech/docker/registry.go new file mode 100644 index 0000000000..795dd6e244 --- /dev/null +++ b/api/tech/docker/registry.go @@ -0,0 +1,234 @@ +package docker + +import ( + "net" + "net/http" + + "github.com/pkg/errors" +) + +// HostCapabilities represent the capabilities of the registry +// host. This also represents the set of operations for which +// the registry host may be trusted to perform. +// +// For example pushing is a capability which should only be +// performed on an upstream source, not a mirror. +// Resolving (the process of converting a name into a digest) +// must be considered a trusted operation and only done by +// a host which is trusted (or more preferably by secure process +// which can prove the provenance of the mapping). A public +// mirror should never be trusted to do a resolve action. +// +// | Registry Type | Pull | Resolve | Push | +// |------------------|------|---------|------| +// | Public Registry | yes | yes | yes | +// | Private Registry | yes | yes | yes | +// | Public Mirror | yes | no | no | +// | Private Mirror | yes | yes | no |. +type HostCapabilities uint8 + +const ( + // HostCapabilityPull represents the capability to fetch manifests + // and blobs by digest. + HostCapabilityPull HostCapabilities = 1 << iota + + // HostCapabilityResolve represents the capability to fetch manifests + // by name. + HostCapabilityResolve + + // HostCapabilityPush represents the capability to push blobs and + // manifests. + HostCapabilityPush + + // Reserved for future capabilities (i.e. search, catalog, remove). +) + +// Has checks whether the capabilities list has the provide capability. +func (c HostCapabilities) Has(t HostCapabilities) bool { + return c&t == t +} + +// RegistryHost represents a complete configuration for a registry +// host, representing the capabilities, authorizations, connection +// configuration, and location. +type RegistryHost struct { + Client *http.Client + Authorizer Authorizer + Host string + Scheme string + Path string + Capabilities HostCapabilities + Header http.Header +} + +const ( + dockerHostname = "docker.io" + dockerRegistryHostname = "registry-1.docker.io" +) + +func (h RegistryHost) isProxy(refhost string) bool { + if refhost != h.Host { + if refhost != dockerHostname || h.Host != dockerRegistryHostname { + return true + } + } + return false +} + +// RegistryHosts fetches the registry hosts for a given namespace, +// provided by the host component of an distribution image reference. +type RegistryHosts func(string) ([]RegistryHost, error) + +// Registries joins multiple registry configuration functions, using the same +// order as provided within the arguments. When an empty registry configuration +// is returned with a nil error, the next function will be called. +// NOTE: This function will not join configurations, as soon as a non-empty +// configuration is returned from a configuration function, it will be returned +// to the caller. +func Registries(registries ...RegistryHosts) RegistryHosts { + return func(host string) ([]RegistryHost, error) { + for _, registry := range registries { + config, err := registry(host) + if err != nil { + return config, err + } + if len(config) > 0 { + return config, nil + } + } + return nil, nil + } +} + +type registryOpts struct { + authorizer Authorizer + plainHTTP func(string) (bool, error) + host func(string) (string, error) + client *http.Client +} + +// RegistryOpt defines a registry default option. +type RegistryOpt func(*registryOpts) + +// WithPlainHTTP configures registries to use plaintext http scheme +// for the provided host match function. +func WithPlainHTTP(f func(string) (bool, error)) RegistryOpt { + return func(opts *registryOpts) { + opts.plainHTTP = f + } +} + +// WithAuthorizer configures the default authorizer for a registry. +func WithAuthorizer(a Authorizer) RegistryOpt { + return func(opts *registryOpts) { + opts.authorizer = a + } +} + +// WithHostTranslator defines the default translator to use for registry hosts. +func WithHostTranslator(h func(string) (string, error)) RegistryOpt { + return func(opts *registryOpts) { + opts.host = h + } +} + +// WithClient configures the default http client for a registry. +func WithClient(c *http.Client) RegistryOpt { + return func(opts *registryOpts) { + opts.client = c + } +} + +// ConfigureDefaultRegistries is used to create a default configuration for +// registries. For more advanced configurations or per-domain setups, +// the RegistryHosts interface should be used directly. +// NOTE: This function will always return a non-empty value or error. +func ConfigureDefaultRegistries(ropts ...RegistryOpt) RegistryHosts { + var opts registryOpts + for _, opt := range ropts { + opt(&opts) + } + + return func(host string) ([]RegistryHost, error) { + config := RegistryHost{ + Client: opts.client, + Authorizer: opts.authorizer, + Host: host, + Scheme: "https", + Path: "/v2", + Capabilities: HostCapabilityPull | HostCapabilityResolve | HostCapabilityPush, + } + + if config.Client == nil { + config.Client = http.DefaultClient + } + + if opts.plainHTTP != nil { + match, err := opts.plainHTTP(host) + if err != nil { + return nil, err + } + if match { + config.Scheme = "http" + } + } + + if opts.host != nil { + var err error + config.Host, err = opts.host(config.Host) + if err != nil { + return nil, err + } + } else if host == dockerHostname { + config.Host = dockerRegistryHostname + } + + return []RegistryHost{config}, nil + } +} + +// MatchAllHosts is a host match function which is always true. +func MatchAllHosts(string) (bool, error) { + return true, nil +} + +// MatchLocalhost is a host match function which returns true for +// localhost. +// +// Note: this does not handle matching of ip addresses in octal, +// decimal or hex form. +func MatchLocalhost(host string) (bool, error) { + switch { + case host == "::1": + return true, nil + case host == "[::1]": + return true, nil + } + h, p, err := net.SplitHostPort(host) + + // addrError helps distinguish between errors of form + // "no colon in address" and "too many colons in address". + // The former is fine as the host string need not have a + // port. Latter needs to be handled. + addrError := &net.AddrError{ + Err: "missing port in address", + Addr: host, + } + if err != nil { + if err.Error() != addrError.Error() { + return false, err + } + // host string without any port specified + h = host + } else if len(p) == 0 { + return false, errors.New("invalid host name format") + } + + // use ipv4 dotted decimal for further checking + if h == "localhost" { + h = "127.0.0.1" + } + ip := net.ParseIP(h) + + return ip.IsLoopback(), nil +} diff --git a/api/tech/docker/resolve/interface.go b/api/tech/docker/resolve/interface.go new file mode 100644 index 0000000000..8476000012 --- /dev/null +++ b/api/tech/docker/resolve/interface.go @@ -0,0 +1,75 @@ +package resolve + +import ( + "context" + "io" + + "github.com/containerd/containerd/content" + "github.com/opencontainers/go-digest" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" +) + +// all new and modified + +type Source interface { + Reader() (io.ReadCloser, error) +} + +// Resolver provides remotes based on a locator. +type Resolver interface { + // Resolve attempts to resolve the reference into a name and descriptor. + // + // The argument `ref` should be a scheme-less URI representing the remote. + // Structurally, it has a host and path. The "host" can be used to directly + // reference a specific host or be matched against a specific handler. + // + // The returned name should be used to identify the referenced entity. + // Dependending on the remote namespace, this may be immutable or mutable. + // While the name may differ from ref, it should itself be a valid ref. + // + // If the resolution fails, an error will be returned. + Resolve(ctx context.Context, ref string) (name string, desc ocispec.Descriptor, err error) + + // Fetcher returns a new fetcher for the provided reference. + // All content fetched from the returned fetcher will be + // from the namespace referred to by ref. + Fetcher(ctx context.Context, ref string) (Fetcher, error) + + // Pusher returns a new pusher for the provided reference + // The returned Pusher should satisfy content.Ingester and concurrent attempts + // to push the same blob using the Ingester API should result in ErrUnavailable. + Pusher(ctx context.Context, ref string) (Pusher, error) + + Lister(ctx context.Context, ref string) (Lister, error) +} + +// Fetcher fetches content. +type Fetcher interface { + // Fetch the resource identified by the descriptor. + Fetch(ctx context.Context, desc ocispec.Descriptor) (io.ReadCloser, error) +} + +// Pusher pushes content +// don't use write interface of containerd remotes.Pusher. +type Pusher interface { + // Push returns a push request for the given resource identified + // by the descriptor and the given data source. + Push(ctx context.Context, d ocispec.Descriptor, src Source) (PushRequest, error) +} + +type Lister interface { + List(context.Context) ([]string, error) +} + +// PushRequest handles the result of a push request +// replaces containerd content.Writer. +type PushRequest interface { + // Commit commits the blob (but no roll-back is guaranteed on an error). + // size and expected can be zero-value when unknown. + // Commit always closes the writer, even on error. + // ErrAlreadyExists aborts the writer. + Commit(ctx context.Context, size int64, expected digest.Digest, opts ...content.Opt) error + + // Status returns the current state of write + Status() (content.Status, error) +} diff --git a/api/tech/docker/resolver.go b/api/tech/docker/resolver.go new file mode 100644 index 0000000000..292df03ae3 --- /dev/null +++ b/api/tech/docker/resolver.go @@ -0,0 +1,656 @@ +package docker + +import ( + "context" + "fmt" + "io" + "net/http" + "net/url" + "path" + "strings" + + "github.com/containerd/containerd/errdefs" + "github.com/containerd/containerd/images" + "github.com/containerd/containerd/log" + "github.com/containerd/containerd/reference" + "github.com/containerd/containerd/remotes/docker/schema1" + "github.com/containerd/containerd/version" + "github.com/opencontainers/go-digest" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" + "golang.org/x/net/context/ctxhttp" + + "ocm.software/ocm/api/tech/docker/resolve" + "ocm.software/ocm/api/utils/accessio" +) + +var ( + // ErrInvalidAuthorization is used when credentials are passed to a server but + // those credentials are rejected. + ErrInvalidAuthorization = errors.New("authorization failed") + + // MaxManifestSize represents the largest size accepted from a registry + // during resolution. Larger manifests may be accepted using a + // resolution method other than the registry. + // + // NOTE: The max supported layers by some runtimes is 128 and individual + // layers will not contribute more than 256 bytes, making a + // reasonable limit for a large image manifests of 32K bytes. + // 4M bytes represents a much larger upper bound for images which may + // contain large annotations or be non-images. A proper manifest + // design puts large metadata in subobjects, as is consistent the + // intent of the manifest design. + MaxManifestSize int64 = 4 * 1048 * 1048 +) + +// Authorizer is used to authorize HTTP requests based on 401 HTTP responses. +// An Authorizer is responsible for caching tokens or credentials used by +// requests. +type Authorizer interface { + // Authorize sets the appropriate `Authorization` header on the given + // request. + // + // If no authorization is found for the request, the request remains + // unmodified. It may also add an `Authorization` header as + // "bearer " + // "basic " + Authorize(context.Context, *http.Request) error + + // AddResponses adds a 401 response for the authorizer to consider when + // authorizing requests. The last response should be unauthorized and + // the previous requests are used to consider redirects and retries + // that may have led to the 401. + // + // If response is not handled, returns `ErrNotImplemented` + AddResponses(context.Context, []*http.Response) error +} + +// ResolverOptions are used to configured a new Docker register resolver. +type ResolverOptions struct { + // Hosts returns registry host configurations for a namespace. + Hosts RegistryHosts + + // Headers are the HTTP request header fields sent by the resolver + Headers http.Header + + // Tracker is used to track uploads to the registry. This is used + // since the registry does not have upload tracking and the existing + // mechanism for getting blob upload status is expensive. + Tracker StatusTracker + + // Authorizer is used to authorize registry requests + // Deprecated: use Hosts + Authorizer Authorizer + + // Credentials provides username and secret given a host. + // If username is empty but a secret is given, that secret + // is interpreted as a long lived token. + // Deprecated: use Hosts + Credentials func(string) (string, string, error) + + // Host provides the hostname given a namespace. + // Deprecated: use Hosts + Host func(string) (string, error) + + // PlainHTTP specifies to use plain http and not https + // Deprecated: use Hosts + PlainHTTP bool + + // Client is the http client to used when making registry requests + // Deprecated: use Hosts + Client *http.Client +} + +// DefaultHost is the default host function. +func DefaultHost(ns string) (string, error) { + if ns == "docker.io" { + return "registry-1.docker.io", nil + } + return ns, nil +} + +type dockerResolver struct { + hosts RegistryHosts + header http.Header + resolveHeader http.Header + tracker StatusTracker +} + +// NewResolver returns a new resolver to a Docker registry. +func NewResolver(options ResolverOptions) resolve.Resolver { + if options.Tracker == nil { + options.Tracker = NewInMemoryTracker() + } + + if options.Headers == nil { + options.Headers = make(http.Header) + } + if _, ok := options.Headers["User-Agent"]; !ok { + options.Headers.Set("User-Agent", "containerd/"+version.Version) + } + + resolveHeader := http.Header{} + if _, ok := options.Headers["Accept"]; !ok { + // set headers for all the types we support for resolution. + resolveHeader.Set("Accept", strings.Join([]string{ + images.MediaTypeDockerSchema2Manifest, + images.MediaTypeDockerSchema2ManifestList, + ocispec.MediaTypeImageManifest, + ocispec.MediaTypeImageIndex, "*/*", + }, ", ")) + } else { + resolveHeader["Accept"] = options.Headers["Accept"] + delete(options.Headers, "Accept") + } + + if options.Hosts == nil { + opts := []RegistryOpt{} + if options.Host != nil { + opts = append(opts, WithHostTranslator(options.Host)) + } + + if options.Authorizer == nil { + options.Authorizer = NewDockerAuthorizer( + WithAuthClient(options.Client), + WithAuthHeader(options.Headers), + WithAuthCreds(options.Credentials)) + } + opts = append(opts, WithAuthorizer(options.Authorizer)) + + if options.Client != nil { + opts = append(opts, WithClient(options.Client)) + } + if options.PlainHTTP { + opts = append(opts, WithPlainHTTP(MatchAllHosts)) + } else { + opts = append(opts, WithPlainHTTP(MatchLocalhost)) + } + options.Hosts = ConfigureDefaultRegistries(opts...) + } + return &dockerResolver{ + hosts: options.Hosts, + header: options.Headers, + resolveHeader: resolveHeader, + tracker: options.Tracker, + } +} + +func getManifestMediaType(resp *http.Response) string { + // Strip encoding data (manifests should always be ascii JSON) + contentType := resp.Header.Get("Content-Type") + if sp := strings.IndexByte(contentType, ';'); sp != -1 { + contentType = contentType[0:sp] + } + + // As of Apr 30 2019 the registry.access.redhat.com registry does not specify + // the content type of any data but uses schema1 manifests. + if contentType == "text/plain" { + contentType = images.MediaTypeDockerSchema1Manifest + } + return contentType +} + +type countingReader struct { + reader io.Reader + bytesRead int64 +} + +func (r *countingReader) Read(p []byte) (int, error) { + n, err := r.reader.Read(p) + r.bytesRead += int64(n) + return n, err +} + +var _ resolve.Resolver = &dockerResolver{} + +func (r *dockerResolver) Resolve(ctx context.Context, ref string) (string, ocispec.Descriptor, error) { + base, err := r.resolveDockerBase(ref) + if err != nil { + return "", ocispec.Descriptor{}, err + } + refspec := base.refspec + if refspec.Object == "" { + return "", ocispec.Descriptor{}, reference.ErrObjectRequired + } + + var ( + firstErr error + paths [][]string + dgst = refspec.Digest() + caps = HostCapabilityPull + ) + + if dgst != "" { + if err := dgst.Validate(); err != nil { + // need to fail here, since we can't actually resolve the invalid + // digest. + return "", ocispec.Descriptor{}, err + } + + // turns out, we have a valid digest, make a url. + paths = append(paths, []string{"manifests", dgst.String()}) + + // fallback to blobs on not found. + paths = append(paths, []string{"blobs", dgst.String()}) + } else { + // Add + paths = append(paths, []string{"manifests", refspec.Object}) + caps |= HostCapabilityResolve + } + + hosts := base.filterHosts(caps) + if len(hosts) == 0 { + return "", ocispec.Descriptor{}, errors.Wrap(errdefs.ErrNotFound, "no resolve hosts") + } + + ctx, err = ContextWithRepositoryScope(ctx, refspec, false) + if err != nil { + return "", ocispec.Descriptor{}, err + } + + for _, u := range paths { + for _, host := range hosts { + ctxWithLogger := log.WithLogger(ctx, log.G(ctx).WithField("host", host.Host)) + + req := base.request(host, http.MethodHead, u...) + if err := req.addNamespace(base.refspec.Hostname()); err != nil { + return "", ocispec.Descriptor{}, err + } + + for key, value := range r.resolveHeader { + req.header[key] = append(req.header[key], value...) + } + + log.G(ctxWithLogger).Debug("resolving") + resp, err := req.doWithRetries(ctxWithLogger, nil) + if err != nil { + if errors.Is(err, ErrInvalidAuthorization) { + err = errors.Wrapf(err, "pull access denied, repository does not exist or may require authorization") + } else { + err = accessio.RetriableError(err) + } + // Store the error for referencing later + if firstErr == nil { + firstErr = err + } + log.G(ctxWithLogger).WithError(err).Info("trying next host") + continue // try another host + } + resp.Body.Close() // don't care about body contents. + + if resp.StatusCode > 299 { + if resp.StatusCode == http.StatusNotFound { + // log.G(ctxWithLogger).Info("trying next host - response was http.StatusNotFound") + continue + } + if resp.StatusCode > 399 { + // Set firstErr when encountering the first non-404 status code. + if firstErr == nil { + firstErr = errors.Errorf("pulling from host %s failed with status code %v: %v", host.Host, u, resp.Status) + } + continue // try another host + } + return "", ocispec.Descriptor{}, errors.Errorf("pulling from host %s failed with unexpected status code %v: %v", host.Host, u, resp.Status) + } + size := resp.ContentLength + contentType := getManifestMediaType(resp) + + // if no digest was provided, then only a resolve + // trusted registry was contacted, in this case use + // the digest header (or content from GET) + if dgst == "" { + // this is the only point at which we trust the registry. we use the + // content headers to assemble a descriptor for the name. when this becomes + // more robust, we mostly get this information from a secure trust store. + dgstHeader := digest.Digest(resp.Header.Get("Docker-Content-Digest")) + + if dgstHeader != "" && size != -1 { + if err := dgstHeader.Validate(); err != nil { + return "", ocispec.Descriptor{}, errors.Wrapf(err, "%q in header not a valid digest", dgstHeader) + } + dgst = dgstHeader + } + } + if dgst == "" || size == -1 { + log.G(ctxWithLogger).Debug("no Docker-Content-Digest header, fetching manifest instead") + + req = base.request(host, http.MethodGet, u...) + if err := req.addNamespace(base.refspec.Hostname()); err != nil { + return "", ocispec.Descriptor{}, err + } + + for key, value := range r.resolveHeader { + req.header[key] = append(req.header[key], value...) + } + + resp, err := req.doWithRetries(ctxWithLogger, nil) + if err != nil { + return "", ocispec.Descriptor{}, accessio.RetriableError(err) + } + defer resp.Body.Close() + + bodyReader := countingReader{reader: resp.Body} + + contentType = getManifestMediaType(resp) + if dgst == "" { + if contentType == images.MediaTypeDockerSchema1Manifest { + b, err := schema1.ReadStripSignature(&bodyReader) + if err != nil { + return "", ocispec.Descriptor{}, accessio.RetriableError(err) + } + + dgst = digest.FromBytes(b) + } else { + dgst, err = digest.FromReader(&bodyReader) + if err != nil { + return "", ocispec.Descriptor{}, accessio.RetriableError(err) + } + } + } else if _, err := io.Copy(io.Discard, &bodyReader); err != nil { + return "", ocispec.Descriptor{}, accessio.RetriableError(err) + } + size = bodyReader.bytesRead + } + // Prevent resolving to excessively large manifests + if size > MaxManifestSize { + if firstErr == nil { + firstErr = errors.Wrapf(errdefs.ErrNotFound, "rejecting %d byte manifest for %s", size, ref) + } + continue + } + + desc := ocispec.Descriptor{ + Digest: dgst, + MediaType: contentType, + Size: size, + } + + log.G(ctxWithLogger).WithField("desc.digest", desc.Digest).Debug("resolved") + return ref, desc, nil + } + } + + // If above loop terminates without return, then there was an error. + // "firstErr" contains the first non-404 error. That is, "firstErr == nil" + // means that either no registries were given or each registry returned 404. + + if firstErr == nil { + firstErr = errors.Wrap(errdefs.ErrNotFound, ref) + } + + return "", ocispec.Descriptor{}, firstErr +} + +func (r *dockerResolver) Fetcher(ctx context.Context, ref string) (resolve.Fetcher, error) { + base, err := r.resolveDockerBase(ref) + if err != nil { + return nil, err + } + + return dockerFetcher{ + dockerBase: base, + }, nil +} + +func (r *dockerResolver) Pusher(ctx context.Context, ref string) (resolve.Pusher, error) { + base, err := r.resolveDockerBase(ref) + if err != nil { + return nil, err + } + + return dockerPusher{ + dockerBase: base, + object: base.refspec.Object, + tracker: r.tracker, + }, nil +} + +func (r *dockerResolver) resolveDockerBase(ref string) (*dockerBase, error) { + refspec, err := reference.Parse(ref) + if err != nil { + return nil, err + } + + return r.base(refspec) +} + +type dockerBase struct { + refspec reference.Spec + repository string + hosts []RegistryHost + header http.Header +} + +func (r *dockerResolver) base(refspec reference.Spec) (*dockerBase, error) { + host := refspec.Hostname() + hosts, err := r.hosts(host) + if err != nil { + return nil, err + } + return &dockerBase{ + refspec: refspec, + repository: strings.TrimPrefix(refspec.Locator, host+"/"), + hosts: hosts, + header: r.header, + }, nil +} + +func (r *dockerBase) filterHosts(caps HostCapabilities) (hosts []RegistryHost) { + for _, host := range r.hosts { + if host.Capabilities.Has(caps) { + hosts = append(hosts, host) + } + } + return +} + +func (r *dockerBase) request(host RegistryHost, method string, ps ...string) *request { + header := r.header.Clone() + if header == nil { + header = http.Header{} + } + + for key, value := range host.Header { + header[key] = append(header[key], value...) + } + parts := append([]string{"/", host.Path, r.repository}, ps...) + p := path.Join(parts...) + // Join strips trailing slash, re-add ending "/" if included + if len(parts) > 0 && strings.HasSuffix(parts[len(parts)-1], "/") { + p += "/" + } + return &request{ + method: method, + path: p, + header: header, + host: host, + } +} + +func (r *request) authorize(ctx context.Context, req *http.Request) error { + // Check if has header for host + if r.host.Authorizer != nil { + if err := r.host.Authorizer.Authorize(ctx, req); err != nil { + return err + } + } + + return nil +} + +func (r *request) addNamespace(ns string) (err error) { + if !r.host.isProxy(ns) { + return nil + } + var q url.Values + // Parse query + if i := strings.IndexByte(r.path, '?'); i > 0 { + r.path = r.path[:i+1] + q, err = url.ParseQuery(r.path[i+1:]) + if err != nil { + return + } + } else { + r.path += "?" + q = url.Values{} + } + q.Add("ns", ns) + + r.path += q.Encode() + + return +} + +type request struct { + method string + path string + header http.Header + host RegistryHost + body func() (io.ReadCloser, error) + size int64 +} + +func (r *request) do(ctx context.Context) (*http.Response, error) { + u := r.host.Scheme + "://" + r.host.Host + r.path + req, err := http.NewRequestWithContext(ctx, r.method, u, nil) + if err != nil { + return nil, err + } + req.Header = http.Header{} // headers need to be copied to avoid concurrent map access + for k, v := range r.header { + req.Header[k] = v + } + if r.body != nil { + body, err := r.body() + if err != nil { + return nil, err + } + req.Body = body + req.GetBody = r.body + if r.size > 0 { + req.ContentLength = r.size + } + defer body.Close() + } + + ctx = log.WithLogger(ctx, log.G(ctx).WithField("url", u)) + log.G(ctx).WithFields(sanitizedRequestFields(req)).Debug("do request") + if err := r.authorize(ctx, req); err != nil { + return nil, errors.Wrap(err, "failed to authorize") + } + + client := &http.Client{} + if r.host.Client != nil { + *client = *r.host.Client + } + if client.CheckRedirect == nil { + client.CheckRedirect = func(req *http.Request, via []*http.Request) error { + if len(via) >= 10 { + return errors.New("stopped after 10 redirects") + } + return errors.Wrap(r.authorize(ctx, req), "failed to authorize redirect") + } + } + + resp, err := ctxhttp.Do(ctx, client, req) + if err != nil { + return nil, errors.Wrap(err, "failed to do request") + } + log.G(ctx).WithFields(responseFields(resp)).Debug("fetch response received") + return resp, nil +} + +func (r *request) doWithRetries(ctx context.Context, responses []*http.Response) (*http.Response, error) { + resp, err := r.do(ctx) + if err != nil { + return nil, err + } + + responses = append(responses, resp) + retry, err := r.retryRequest(ctx, responses) + if err != nil { + resp.Body.Close() + return nil, err + } + if retry { + resp.Body.Close() + return r.doWithRetries(ctx, responses) + } + return resp, err +} + +func (r *request) retryRequest(ctx context.Context, responses []*http.Response) (bool, error) { + if len(responses) > 5 { + return false, nil + } + last := responses[len(responses)-1] + switch last.StatusCode { + case http.StatusUnauthorized: + log.G(ctx).WithField("header", last.Header.Get("WWW-Authenticate")).Debug("Unauthorized") + if r.host.Authorizer != nil { + if err := r.host.Authorizer.AddResponses(ctx, responses); err == nil { + return true, nil + } else if !errdefs.IsNotImplemented(err) { + return false, err + } + } + + return false, nil + case http.StatusMethodNotAllowed: + // Support registries which have not properly implemented the HEAD method for + // manifests endpoint + if r.method == http.MethodHead && strings.Contains(r.path, "/manifests/") { + r.method = http.MethodGet + return true, nil + } + case http.StatusRequestTimeout, http.StatusTooManyRequests: + return true, nil + } + + // TODO: Handle 50x errors accounting for attempt history + return false, nil +} + +func (r *request) String() string { + return r.host.Scheme + "://" + r.host.Host + r.path +} + +func sanitizedRequestFields(req *http.Request) logrus.Fields { + fields := map[string]interface{}{ + "request.method": req.Method, + } + for k, vals := range req.Header { + k = strings.ToLower(k) + if k == "authorization" { + continue + } + for i, v := range vals { + field := "request.header." + k + if i > 0 { + field = fmt.Sprintf("%s.%d", field, i) + } + fields[field] = v + } + } + + return logrus.Fields(fields) +} + +func responseFields(resp *http.Response) logrus.Fields { + fields := map[string]interface{}{ + "response.status": resp.Status, + } + for k, vals := range resp.Header { + k = strings.ToLower(k) + for i, v := range vals { + field := "response.header." + k + if i > 0 { + field = fmt.Sprintf("%s.%d", field, i) + } + fields[field] = v + } + } + + return logrus.Fields(fields) +} diff --git a/go.mod b/go.mod index ad60c5afbb..795250e95c 100644 --- a/go.mod +++ b/go.mod @@ -16,6 +16,7 @@ require ( github.com/aws/aws-sdk-go-v2/service/s3 v1.66.0 github.com/cloudflare/cfssl v1.6.5 github.com/containerd/containerd v1.7.23 + github.com/containerd/errdefs v0.3.0 github.com/containerd/log v0.1.0 github.com/containers/image/v5 v5.32.2 github.com/cyberphone/json-canonicalization v0.0.0-20231217050601-ba74d44ecf5f @@ -80,7 +81,6 @@ require ( k8s.io/apimachinery v0.31.1 k8s.io/cli-runtime v0.31.1 k8s.io/client-go v0.31.1 - oras.land/oras-go/v2 v2.5.0 sigs.k8s.io/controller-runtime v0.19.0 sigs.k8s.io/yaml v1.4.0 ) @@ -156,7 +156,6 @@ require ( github.com/clbanning/mxj/v2 v2.7.0 // indirect github.com/cloudflare/circl v1.5.0 // indirect github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be // indirect - github.com/containerd/errdefs v0.3.0 // indirect github.com/containerd/platforms v0.2.1 // indirect github.com/containerd/stargz-snapshotter/estargz v0.15.1 // indirect github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01 // indirect @@ -276,6 +275,7 @@ require ( github.com/opencontainers/runtime-spec v1.2.0 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect github.com/pborman/uuid v1.2.1 // indirect + github.com/pelletier/go-toml v1.9.5 // indirect github.com/pelletier/go-toml/v2 v2.2.3 // indirect github.com/peterbourgon/diskv v2.0.1+incompatible // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect diff --git a/go.sum b/go.sum index 536d7eca57..b4577dbb10 100644 --- a/go.sum +++ b/go.sum @@ -1359,8 +1359,6 @@ k8s.io/utils v0.0.0-20240921022957-49e7df575cb6 h1:MDF6h2H/h4tbzmtIKTuctcwZmY0tY k8s.io/utils v0.0.0-20240921022957-49e7df575cb6/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= oras.land/oras-go v1.2.6 h1:z8cmxQXBU8yZ4mkytWqXfo6tZcamPwjsuxYU81xJ8Lk= oras.land/oras-go v1.2.6/go.mod h1:OVPc1PegSEe/K8YiLfosrlqlqTN9PUyFvOw5Y9gwrT8= -oras.land/oras-go/v2 v2.5.0 h1:o8Me9kLY74Vp5uw07QXPiitjsw7qNXi8Twd+19Zf02c= -oras.land/oras-go/v2 v2.5.0/go.mod h1:z4eisnLP530vwIOUOJeBIj0aGI0L1C3d53atvCBqZHg= sigs.k8s.io/controller-runtime v0.19.0 h1:nWVM7aq+Il2ABxwiCizrVDSlmDcshi9llbaFbC0ji/Q= sigs.k8s.io/controller-runtime v0.19.0/go.mod h1:iRmWllt8IlaLjvTTDLhRBXIEtkCK6hwVBJJsYS9Ajf4= sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE= From d85df39db13aabd3cbd47bd2942950dc7da1e035 Mon Sep 17 00:00:00 2001 From: "ocmbot[bot]" <125909804+ocmbot[bot]@users.noreply.github.com> Date: Thu, 24 Oct 2024 10:41:08 +0000 Subject: [PATCH 02/58] chore: update 'flake.nix' (#1012) Update OCM CLI vendor hash (see: .github/workflows/flake_vendorhash.yaml) Co-authored-by: ocmbot[bot] <125909804+ocmbot[bot]@users.noreply.github.com> --- flake.lock | 8 ++++---- flake.nix | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/flake.lock b/flake.lock index 39d7a094aa..4249bfa306 100644 --- a/flake.lock +++ b/flake.lock @@ -2,16 +2,16 @@ "nodes": { "nixpkgs": { "locked": { - "lastModified": 1722221733, - "narHash": "sha256-sga9SrrPb+pQJxG1ttJfMPheZvDOxApFfwXCFO0H9xw=", + "lastModified": 1729665710, + "narHash": "sha256-AlcmCXJZPIlO5dmFzV3V2XF6x/OpNWUV8Y/FMPGd8Z4=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "12bf09802d77264e441f48e25459c10c93eada2e", + "rev": "2768c7d042a37de65bb1b5b3268fc987e534c49d", "type": "github" }, "original": { "owner": "NixOS", - "ref": "nixos-24.05", + "ref": "nixos-unstable", "repo": "nixpkgs", "type": "github" } diff --git a/flake.nix b/flake.nix index 0a4bd6b392..e1433d73d8 100644 --- a/flake.nix +++ b/flake.nix @@ -35,7 +35,7 @@ state = if (self ? rev) then "clean" else "dirty"; # This vendorHash represents a derivative of all go.mod dependencies and needs to be adjusted with every change - vendorHash = "sha256-pfnq3+5xmybYvevMrWOP2UmMnN1lApTcq/oaq91Yrs0="; + vendorHash = "sha256-dI47I0+dpoWvMKprYdNbNdPujFahJelmu/HtIbEJzuI="; src = ./.; From 86bb590fdf1e7601ff4a1b67c0df7e11c390a1aa Mon Sep 17 00:00:00 2001 From: GitHub Actions Bot <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 24 Oct 2024 12:48:27 +0000 Subject: [PATCH 03/58] ReleaseNotes for v0.17.0-rc.1 --- docs/releasenotes/v0.17.0-rc.1.md | 34 +++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 docs/releasenotes/v0.17.0-rc.1.md diff --git a/docs/releasenotes/v0.17.0-rc.1.md b/docs/releasenotes/v0.17.0-rc.1.md new file mode 100644 index 0000000000..3039ec82dc --- /dev/null +++ b/docs/releasenotes/v0.17.0-rc.1.md @@ -0,0 +1,34 @@ +# Release v0.17.0-rc.1 + +- chore: update 'flake.nix' (#1012) +- Revert "feat: replace docker with oras (#904)" (#1005) +- !OCI Annotations change in Component Descriptor for Component Versions: \`ocm-artifact\` -> \`software.ocm.artifact\` and introduce \`software.ocm.creator\` (#987) +- Upgrade levenshtein dependency (#1009) +- Introduce update state on CV implementation API (#976) +- documentation: fix uploader documentation (#991) +- documentation: Update the installation options (#979) +- chore: reduce cache pressure by early deleting cache entries after PR closure (#986) + +## 🐛 Bug Fixes + +- fix!(release): retract 0.16.0-z (#1006) +- Fix/publish release (#1001) +- chore: fixes for docu + cleanup test leftovers (#993) + +## 🧰 Maintenance + +
+5 changes + +- chore(release): also call make generate to update files (#992) +- chore(ci): remove i386, optimize latest build and add various comments (#1010) +- chore(ci): use reusable stale bot configuration (#1008) +- chore(ci): add stale bot for issues (#1002) +- chore(ci): make sure we use candidates and branches by default (#1004) +
+ +## ⬆️ Dependencies + +- chore(deps): bump the go group with 5 updates (#989) +- chore(deps): bump anchore/sbom-action from 0.17.3 to 0.17.4 in the ci group (#988) + From d1a956d04498d8343465b18d8207311dde6078f4 Mon Sep 17 00:00:00 2001 From: Gergely Brautigam <182850+Skarlso@users.noreply.github.com> Date: Fri, 25 Oct 2024 09:19:28 +0200 Subject: [PATCH 04/58] fix: correct the default URL for uninstalling ocm controller (#1013) #### What this PR does / why we need it #### Which issue(s) this PR fixes Fixes https://github.com/open-component-model/ocm-controller/issues/542 --------- Co-authored-by: Hilmar Falkenberg --- .../genericocireg/annotation_test.go | 1 + .../commands/controllercmds/uninstall/cmd.go | 2 +- .../ocmcmds/components/hash/cmd_test.go | 2 +- docs/reference/ocm_controller_uninstall.md | 2 +- docs/releasenotes/v0.17.0-rc.1.md | 34 ------------------- .../lib/tour/01-getting-started/README.md | 14 ++++---- 6 files changed, 11 insertions(+), 44 deletions(-) delete mode 100644 docs/releasenotes/v0.17.0-rc.1.md diff --git a/api/ocm/extensions/repositories/genericocireg/annotation_test.go b/api/ocm/extensions/repositories/genericocireg/annotation_test.go index 60ec0db94b..4d06e4fc61 100644 --- a/api/ocm/extensions/repositories/genericocireg/annotation_test.go +++ b/api/ocm/extensions/repositories/genericocireg/annotation_test.go @@ -5,6 +5,7 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" . "ocm.software/ocm/api/helper/builder" + "ocm.software/ocm/api/oci/extensions/repositories/ctf" metav1 "ocm.software/ocm/api/ocm/compdesc/meta/v1" resourcetypes "ocm.software/ocm/api/ocm/extensions/artifacttypes" diff --git a/cmds/ocm/commands/controllercmds/uninstall/cmd.go b/cmds/ocm/commands/controllercmds/uninstall/cmd.go index 4261b22772..ef4148bb55 100644 --- a/cmds/ocm/commands/controllercmds/uninstall/cmd.go +++ b/cmds/ocm/commands/controllercmds/uninstall/cmd.go @@ -57,7 +57,7 @@ func (o *Command) ForName(name string) *cobra.Command { // AddFlags for the known item to delete. func (o *Command) AddFlags(set *pflag.FlagSet) { set.StringVarP(&o.Version, "version", "v", "latest", "the version of the controller to install") - set.StringVarP(&o.BaseURL, "base-url", "u", "https://ocm.software/ocm-controller/releases", "the base url to the ocm-controller's release page") + set.StringVarP(&o.BaseURL, "base-url", "u", "https://github.com/ocm-controller/releases", "the base url to the ocm-controller's release page") set.StringVarP(&o.ReleaseAPIURL, "release-api-url", "a", "https://api.github.com/repos/open-component-model/ocm-controller/releases", "the base url to the ocm-controller's API release page") set.StringVar(&o.CertManagerBaseURL, "cert-manager-base-url", "https://github.com/cert-manager/cert-manager/releases", "the base url to the cert-manager's release page") set.StringVar(&o.CertManagerReleaseAPIURL, "cert-manager-release-api-url", "https://api.github.com/repos/cert-manager/cert-manager/releases", "the base url to the cert-manager's API release page") diff --git a/cmds/ocm/commands/ocmcmds/components/hash/cmd_test.go b/cmds/ocm/commands/ocmcmds/components/hash/cmd_test.go index b0a4396a20..7783820f74 100644 --- a/cmds/ocm/commands/ocmcmds/components/hash/cmd_test.go +++ b/cmds/ocm/commands/ocmcmds/components/hash/cmd_test.go @@ -7,12 +7,12 @@ import ( . "github.com/mandelsoft/goutils/testutils" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" - "ocm.software/ocm/api/ocm/extensions/repositories/ctf" . "ocm.software/ocm/cmds/ocm/testhelper" "ocm.software/ocm/api/ocm/compdesc" metav1 "ocm.software/ocm/api/ocm/compdesc/meta/v1" resourcetypes "ocm.software/ocm/api/ocm/extensions/artifacttypes" + "ocm.software/ocm/api/ocm/extensions/repositories/ctf" "ocm.software/ocm/api/utils/accessio" "ocm.software/ocm/api/utils/mime" ) diff --git a/docs/reference/ocm_controller_uninstall.md b/docs/reference/ocm_controller_uninstall.md index 43e1fd4537..65386338e2 100644 --- a/docs/reference/ocm_controller_uninstall.md +++ b/docs/reference/ocm_controller_uninstall.md @@ -9,7 +9,7 @@ ocm controller uninstall controller ### Options ```text - -u, --base-url string the base url to the ocm-controller's release page (default "https://ocm.software/ocm-controller/releases") + -u, --base-url string the base url to the ocm-controller's release page (default "https://github.com/ocm-controller/releases") --cert-manager-base-url string the base url to the cert-manager's release page (default "https://github.com/cert-manager/cert-manager/releases") --cert-manager-release-api-url string the base url to the cert-manager's API release page (default "https://api.github.com/repos/cert-manager/cert-manager/releases") --cert-manager-version string version for cert-manager (default "v1.13.2") diff --git a/docs/releasenotes/v0.17.0-rc.1.md b/docs/releasenotes/v0.17.0-rc.1.md deleted file mode 100644 index 3039ec82dc..0000000000 --- a/docs/releasenotes/v0.17.0-rc.1.md +++ /dev/null @@ -1,34 +0,0 @@ -# Release v0.17.0-rc.1 - -- chore: update 'flake.nix' (#1012) -- Revert "feat: replace docker with oras (#904)" (#1005) -- !OCI Annotations change in Component Descriptor for Component Versions: \`ocm-artifact\` -> \`software.ocm.artifact\` and introduce \`software.ocm.creator\` (#987) -- Upgrade levenshtein dependency (#1009) -- Introduce update state on CV implementation API (#976) -- documentation: fix uploader documentation (#991) -- documentation: Update the installation options (#979) -- chore: reduce cache pressure by early deleting cache entries after PR closure (#986) - -## 🐛 Bug Fixes - -- fix!(release): retract 0.16.0-z (#1006) -- Fix/publish release (#1001) -- chore: fixes for docu + cleanup test leftovers (#993) - -## 🧰 Maintenance - -
-5 changes - -- chore(release): also call make generate to update files (#992) -- chore(ci): remove i386, optimize latest build and add various comments (#1010) -- chore(ci): use reusable stale bot configuration (#1008) -- chore(ci): add stale bot for issues (#1002) -- chore(ci): make sure we use candidates and branches by default (#1004) -
- -## ⬆️ Dependencies - -- chore(deps): bump the go group with 5 updates (#989) -- chore(deps): bump anchore/sbom-action from 0.17.3 to 0.17.4 in the ci group (#988) - diff --git a/examples/lib/tour/01-getting-started/README.md b/examples/lib/tour/01-getting-started/README.md index eef92cf8c4..33abc6f3ed 100644 --- a/examples/lib/tour/01-getting-started/README.md +++ b/examples/lib/tour/01-getting-started/README.md @@ -168,32 +168,32 @@ differ, because the code always describes the latest version): ```text resources of the latest version: - version: 0.16.2 + version: 0.17.0-rc.1 provider: ocm.software 1: name: ocmcli extra identity: "architecture"="amd64","os"="linux" resource type: executable - access: Local blob sha256:b199a1e6558af64898cf0af5245907a12ff3ce152926e30a1a446c8aa6f85fec[] + access: Local blob sha256:e02e4e177a41fd86d2c63f7b7769e2d403c53b10d802f1fe57b5759305b64b32[] 2: name: ocmcli extra identity: "architecture"="arm64","os"="linux" resource type: executable - access: Local blob sha256:b942839e4e86286ad702a9bfbdc30100c970e6ed1d6e45de3a06b67998f746bf[] + access: Local blob sha256:10ff2b950bb26601e497c317289a2fcc1a5ccee4ba5c7dff842cac6d2d78c2ba[] 3: name: ocmcli extra identity: "architecture"="arm64","os"="darwin" resource type: executable - access: Local blob sha256:827662585090c8fe0ffb0e3380b2219a0f1ef65d1e320767b2bdf5723bf0ac31[] + access: Local blob sha256:b033848ab254b52eea5389bb58e1caaa4cf896a1beef95d15187a8466ce3d861[] 4: name: ocmcli extra identity: "architecture"="amd64","os"="darwin" resource type: executable - access: Local blob sha256:c33865145684d2bf45fd50a80dd5435f3bf3f7153058126589e8a92f369205a4[] + access: Local blob sha256:15d86a60ade3ec5036ce71a163b7b92745f6ce7cdf755aa5123b811e2c5909ca[] 5: name: ocmcli extra identity: "architecture"="amd64","os"="windows" resource type: executable - access: Local blob sha256:97057f0822fb137b872c94f81c24618a3df25ea14bd956fea85464c6e8465661[] + access: Local blob sha256:72b6c6aa0b5116892972f7152306bd5b44ffce04f2832dc4557d900a921f7614[] 6: name: ocmcli-image extra identity: resource type: ociImage - access: OCI artifact ghcr.io/open-component-model/ocm/ocm.software/ocmcli/ocmcli-image:0.16.2@sha256:491c08697c6a0be0f0a2d468377eff4deb271b68169a8cf8eb992c553da32df8 + access: OCI artifact ghcr.io/open-component-model/ocm/ocm.software/ocmcli/ocmcli-image:0.17.0-rc.1@sha256:c7627052f1dfcc1dbe0be508466387b0af9bc48d7942911f308b91e3b35ff30c ``` Resources have some metadata, like their identity and a resource type. From ef703e7950abd8dd2b5224c18e09284239e44e6c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Oct 2024 09:23:20 +0100 Subject: [PATCH 05/58] chore(deps): bump anchore/sbom-action from 0.17.4 to 0.17.5 in the ci group (#1018) Bumps the ci group with 1 update: [anchore/sbom-action](https://github.com/anchore/sbom-action). Updates `anchore/sbom-action` from 0.17.4 to 0.17.5
Release notes

Sourced from anchore/sbom-action's releases.

v0.17.5

Changes in v0.17.5

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=anchore/sbom-action&package-manager=github_actions&previous-version=0.17.4&new-version=0.17.5)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index b1a60d85f5..c28e0b05e4 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -168,7 +168,7 @@ jobs: cache_name: release-go-cache - name: Setup Syft - uses: anchore/sbom-action/download-syft@8d0a6505bf28ced3e85154d13dc6af83299e13f1 # v0.17.4 + uses: anchore/sbom-action/download-syft@1ca97d9028b51809cf6d3c934c3e160716e1b605 # v0.17.5 - name: Setup Cosign uses: sigstore/cosign-installer@v3.7.0 From 0ddf454a240261a6158fc5fd4d8f6a301e2f1780 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Oct 2024 08:36:00 +0000 Subject: [PATCH 06/58] chore(deps): bump the go group with 8 updates (#1017) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps the go group with 8 updates: | Package | From | To | | --- | --- | --- | | [github.com/aws/aws-sdk-go-v2/feature/s3/manager](https://github.com/aws/aws-sdk-go-v2) | `1.17.33` | `1.17.34` | | [github.com/aws/aws-sdk-go-v2/service/s3](https://github.com/aws/aws-sdk-go-v2) | `1.66.0` | `1.66.1` | | [k8s.io/api](https://github.com/kubernetes/api) | `0.31.1` | `0.31.2` | | [k8s.io/apiextensions-apiserver](https://github.com/kubernetes/apiextensions-apiserver) | `0.31.1` | `0.31.2` | | [k8s.io/apimachinery](https://github.com/kubernetes/apimachinery) | `0.31.1` | `0.31.2` | | [k8s.io/cli-runtime](https://github.com/kubernetes/cli-runtime) | `0.31.1` | `0.31.2` | | [k8s.io/client-go](https://github.com/kubernetes/client-go) | `0.31.1` | `0.31.2` | | [sigs.k8s.io/controller-runtime](https://github.com/kubernetes-sigs/controller-runtime) | `0.19.0` | `0.19.1` | Updates `github.com/aws/aws-sdk-go-v2/feature/s3/manager` from 1.17.33 to 1.17.34
Commits

Updates `github.com/aws/aws-sdk-go-v2/service/s3` from 1.66.0 to 1.66.1
Commits

Updates `k8s.io/api` from 0.31.1 to 0.31.2
Commits

Updates `k8s.io/apiextensions-apiserver` from 0.31.1 to 0.31.2
Commits

Updates `k8s.io/apimachinery` from 0.31.1 to 0.31.2
Commits

Updates `k8s.io/cli-runtime` from 0.31.1 to 0.31.2
Commits

Updates `k8s.io/client-go` from 0.31.1 to 0.31.2
Commits

Updates `sigs.k8s.io/controller-runtime` from 0.19.0 to 0.19.1
Release notes

Sourced from sigs.k8s.io/controller-runtime's releases.

v0.19.1

What's Changed

Full Changelog: https://github.com/kubernetes-sigs/controller-runtime/compare/v0.19.0...v0.19.1

Commits
  • 013f46f Merge pull request #2992 from k8s-infra-cherrypick-robot/cherry-pick-2980-to-...
  • 4421425 bug: Fakeclient: Fix TOCTOU races
  • aa14005 Merge pull request #2974 from k8s-infra-cherrypick-robot/cherry-pick-2973-to-...
  • f883b25 Fix PR verify action
  • 409ae31 Merge pull request #2965 from k8s-infra-cherrypick-robot/cherry-pick-2964-to-...
  • 465b62a pr-verify: use env var for passing the PR title
  • d32b491 Merge pull request #2962 from k8s-infra-cherrypick-robot/cherry-pick-2961-to-...
  • b400366 pr-verify: use env var for passing the PR title
  • 22d9eab Merge pull request #2951 from k8s-infra-cherrypick-robot/cherry-pick-2949-to-...
  • f0e55af Preserve TypeMeta for PartialObjectMeta resources
  • Additional commits viewable in compare view

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 20 ++++++++++---------- go.sum | 40 ++++++++++++++++++++-------------------- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/go.mod b/go.mod index 795250e95c..0972a89432 100644 --- a/go.mod +++ b/go.mod @@ -11,9 +11,9 @@ require ( github.com/aws/aws-sdk-go-v2 v1.32.2 github.com/aws/aws-sdk-go-v2/config v1.28.0 github.com/aws/aws-sdk-go-v2/credentials v1.17.41 - github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.33 + github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.34 github.com/aws/aws-sdk-go-v2/service/ecr v1.36.2 - github.com/aws/aws-sdk-go-v2/service/s3 v1.66.0 + github.com/aws/aws-sdk-go-v2/service/s3 v1.66.1 github.com/cloudflare/cfssl v1.6.5 github.com/containerd/containerd v1.7.23 github.com/containerd/errdefs v0.3.0 @@ -76,12 +76,12 @@ require ( gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473 gopkg.in/yaml.v3 v3.0.1 helm.sh/helm/v3 v3.16.2 - k8s.io/api v0.31.1 - k8s.io/apiextensions-apiserver v0.31.1 - k8s.io/apimachinery v0.31.1 - k8s.io/cli-runtime v0.31.1 - k8s.io/client-go v0.31.1 - sigs.k8s.io/controller-runtime v0.19.0 + k8s.io/api v0.31.2 + k8s.io/apiextensions-apiserver v0.31.2 + k8s.io/apimachinery v0.31.2 + k8s.io/cli-runtime v0.31.2 + k8s.io/client-go v0.31.2 + sigs.k8s.io/controller-runtime v0.19.1 sigs.k8s.io/yaml v1.4.0 ) @@ -354,8 +354,8 @@ require ( gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - k8s.io/apiserver v0.31.1 // indirect - k8s.io/component-base v0.31.1 // indirect + k8s.io/apiserver v0.31.2 // indirect + k8s.io/component-base v0.31.2 // indirect k8s.io/klog/v2 v2.130.1 // indirect k8s.io/kube-openapi v0.0.0-20241009091222-67ed5848f094 // indirect k8s.io/kubectl v0.31.1 // indirect diff --git a/go.sum b/go.sum index b4577dbb10..57b55c754a 100644 --- a/go.sum +++ b/go.sum @@ -175,8 +175,8 @@ github.com/aws/aws-sdk-go-v2/credentials v1.17.41 h1:7gXo+Axmp+R4Z+AK8YFQO0ZV3L0 github.com/aws/aws-sdk-go-v2/credentials v1.17.41/go.mod h1:u4Eb8d3394YLubphT4jLEwN1rLNq2wFOlT6OuxFwPzU= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.17 h1:TMH3f/SCAWdNtXXVPPu5D6wrr4G5hI1rAxbcocKfC7Q= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.17/go.mod h1:1ZRXLdTpzdJb9fwTMXiLipENRxkGMTn1sfKexGllQCw= -github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.33 h1:X+4YY5kZRI/cOoSMVMGTqFXHAMg1bvvay7IBcqHpybQ= -github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.33/go.mod h1:DPynzu+cn92k5UQ6tZhX+wfTB4ah6QDU/NgdHqatmvk= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.34 h1:os83HS/WfOwi1LsZWLCSHTyj+whvPGaxUsq/D1Ol2Q0= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.34/go.mod h1:tG0BaDCAweumHRsOHm72tuPgAfRLASQThgthWYeTyV8= github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.21 h1:UAsR3xA31QGf79WzpG/ixT9FZvQlh5HY1NRqSHBNOCk= github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.21/go.mod h1:JNr43NFf5L9YaG3eKTm7HQzls9J+A9YYcGI5Quh1r2Y= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.21 h1:6jZVETqmYCadGFvrYEQfC5fAQmlo80CeL5psbno6r0s= @@ -199,8 +199,8 @@ github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.2 h1:t7iUP9+4wdc5lt github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.2/go.mod h1:/niFCtmuQNxqx9v8WAPq5qh7EH25U4BF6tjoyq9bObM= github.com/aws/aws-sdk-go-v2/service/kms v1.37.0 h1:ovrHGOiNu4S0GSMeexZlsMhBkUb3bCE3iOktFZ7rmBU= github.com/aws/aws-sdk-go-v2/service/kms v1.37.0/go.mod h1:YLqfMkq9GWbICgqT5XMIzT8I2+MxVKodTnNBo3BONgE= -github.com/aws/aws-sdk-go-v2/service/s3 v1.66.0 h1:xA6XhTF7PE89BCNHJbQi8VvPzcgMtmGC5dr8S8N7lHk= -github.com/aws/aws-sdk-go-v2/service/s3 v1.66.0/go.mod h1:cB6oAuus7YXRZhWCc1wIwPywwZ1XwweNp2TVAEGYeB8= +github.com/aws/aws-sdk-go-v2/service/s3 v1.66.1 h1:MkQ4unegQEStiQYmfFj+Aq5uTp265ncSmm0XTQwDwi0= +github.com/aws/aws-sdk-go-v2/service/s3 v1.66.1/go.mod h1:cB6oAuus7YXRZhWCc1wIwPywwZ1XwweNp2TVAEGYeB8= github.com/aws/aws-sdk-go-v2/service/sso v1.24.2 h1:bSYXVyUzoTHoKalBmwaZxs97HU9DWWI3ehHSAMa7xOk= github.com/aws/aws-sdk-go-v2/service/sso v1.24.2/go.mod h1:skMqY7JElusiOUjMJMOv1jJsP7YUg7DrhgqZZWuzu1U= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.2 h1:AhmO1fHINP9vFYUE0LHzCWg/LfUWUF+zFPEcY9QXb7o= @@ -1335,20 +1335,20 @@ helm.sh/helm/v3 v3.16.2 h1:Y9v7ry+ubQmi+cb5zw1Llx8OKHU9Hk9NQ/+P+LGBe2o= helm.sh/helm/v3 v3.16.2/go.mod h1:SyTXgKBjNqi2NPsHCW5dDAsHqvGIu0kdNYNH9gQaw70= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -k8s.io/api v0.31.1 h1:Xe1hX/fPW3PXYYv8BlozYqw63ytA92snr96zMW9gWTU= -k8s.io/api v0.31.1/go.mod h1:sbN1g6eY6XVLeqNsZGLnI5FwVseTrZX7Fv3O26rhAaI= -k8s.io/apiextensions-apiserver v0.31.1 h1:L+hwULvXx+nvTYX/MKM3kKMZyei+UiSXQWciX/N6E40= -k8s.io/apiextensions-apiserver v0.31.1/go.mod h1:tWMPR3sgW+jsl2xm9v7lAyRF1rYEK71i9G5dRtkknoQ= -k8s.io/apimachinery v0.31.1 h1:mhcUBbj7KUjaVhyXILglcVjuS4nYXiwC+KKFBgIVy7U= -k8s.io/apimachinery v0.31.1/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= -k8s.io/apiserver v0.31.1 h1:Sars5ejQDCRBY5f7R3QFHdqN3s61nhkpaX8/k1iEw1c= -k8s.io/apiserver v0.31.1/go.mod h1:lzDhpeToamVZJmmFlaLwdYZwd7zB+WYRYIboqA1kGxM= -k8s.io/cli-runtime v0.31.1 h1:/ZmKhmZ6hNqDM+yf9s3Y4KEYakNXUn5sod2LWGGwCuk= -k8s.io/cli-runtime v0.31.1/go.mod h1:pKv1cDIaq7ehWGuXQ+A//1OIF+7DI+xudXtExMCbe9U= -k8s.io/client-go v0.31.1 h1:f0ugtWSbWpxHR7sjVpQwuvw9a3ZKLXX0u0itkFXufb0= -k8s.io/client-go v0.31.1/go.mod h1:sKI8871MJN2OyeqRlmA4W4KM9KBdBUpDLu/43eGemCg= -k8s.io/component-base v0.31.1 h1:UpOepcrX3rQ3ab5NB6g5iP0tvsgJWzxTyAo20sgYSy8= -k8s.io/component-base v0.31.1/go.mod h1:WGeaw7t/kTsqpVTaCoVEtillbqAhF2/JgvO0LDOMa0w= +k8s.io/api v0.31.2 h1:3wLBbL5Uom/8Zy98GRPXpJ254nEFpl+hwndmk9RwmL0= +k8s.io/api v0.31.2/go.mod h1:bWmGvrGPssSK1ljmLzd3pwCQ9MgoTsRCuK35u6SygUk= +k8s.io/apiextensions-apiserver v0.31.2 h1:W8EwUb8+WXBLu56ser5IudT2cOho0gAKeTOnywBLxd0= +k8s.io/apiextensions-apiserver v0.31.2/go.mod h1:i+Geh+nGCJEGiCGR3MlBDkS7koHIIKWVfWeRFiOsUcM= +k8s.io/apimachinery v0.31.2 h1:i4vUt2hPK56W6mlT7Ry+AO8eEsyxMD1U44NR22CLTYw= +k8s.io/apimachinery v0.31.2/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= +k8s.io/apiserver v0.31.2 h1:VUzOEUGRCDi6kX1OyQ801m4A7AUPglpsmGvdsekmcI4= +k8s.io/apiserver v0.31.2/go.mod h1:o3nKZR7lPlJqkU5I3Ove+Zx3JuoFjQobGX1Gctw6XuE= +k8s.io/cli-runtime v0.31.2 h1:7FQt4C4Xnqx8V1GJqymInK0FFsoC+fAZtbLqgXYVOLQ= +k8s.io/cli-runtime v0.31.2/go.mod h1:XROyicf+G7rQ6FQJMbeDV9jqxzkWXTYD6Uxd15noe0Q= +k8s.io/client-go v0.31.2 h1:Y2F4dxU5d3AQj+ybwSMqQnpZH9F30//1ObxOKlTI9yc= +k8s.io/client-go v0.31.2/go.mod h1:NPa74jSVR/+eez2dFsEIHNa+3o09vtNaWwWwb1qSxSs= +k8s.io/component-base v0.31.2 h1:Z1J1LIaC0AV+nzcPRFqfK09af6bZ4D1nAOpWsy9owlA= +k8s.io/component-base v0.31.2/go.mod h1:9PeyyFN/drHjtJZMCTkSpQJS3U9OXORnHQqMLDz0sUQ= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= k8s.io/kube-openapi v0.0.0-20241009091222-67ed5848f094 h1:MErs8YA0abvOqJ8gIupA1Tz6PKXYUw34XsGlA7uSL1k= @@ -1359,8 +1359,8 @@ k8s.io/utils v0.0.0-20240921022957-49e7df575cb6 h1:MDF6h2H/h4tbzmtIKTuctcwZmY0tY k8s.io/utils v0.0.0-20240921022957-49e7df575cb6/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= oras.land/oras-go v1.2.6 h1:z8cmxQXBU8yZ4mkytWqXfo6tZcamPwjsuxYU81xJ8Lk= oras.land/oras-go v1.2.6/go.mod h1:OVPc1PegSEe/K8YiLfosrlqlqTN9PUyFvOw5Y9gwrT8= -sigs.k8s.io/controller-runtime v0.19.0 h1:nWVM7aq+Il2ABxwiCizrVDSlmDcshi9llbaFbC0ji/Q= -sigs.k8s.io/controller-runtime v0.19.0/go.mod h1:iRmWllt8IlaLjvTTDLhRBXIEtkCK6hwVBJJsYS9Ajf4= +sigs.k8s.io/controller-runtime v0.19.1 h1:Son+Q40+Be3QWb+niBXAg2vFiYWolDjjRfO8hn/cxOk= +sigs.k8s.io/controller-runtime v0.19.1/go.mod h1:iRmWllt8IlaLjvTTDLhRBXIEtkCK6hwVBJJsYS9Ajf4= sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE= sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= sigs.k8s.io/kustomize/api v0.18.0 h1:hTzp67k+3NEVInwz5BHyzc9rGxIauoXferXyjv5lWPo= From f9dbb6939a6aa73585952ceba8fc7e668df7d69d Mon Sep 17 00:00:00 2001 From: "ocmbot[bot]" <125909804+ocmbot[bot]@users.noreply.github.com> Date: Mon, 28 Oct 2024 08:48:02 +0000 Subject: [PATCH 07/58] chore: update 'flake.nix' (#1019) Update OCM CLI vendor hash (see: .github/workflows/flake_vendorhash.yaml) Co-authored-by: ocmbot[bot] <125909804+ocmbot[bot]@users.noreply.github.com> --- flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index e1433d73d8..1f5be3cd20 100644 --- a/flake.nix +++ b/flake.nix @@ -35,7 +35,7 @@ state = if (self ? rev) then "clean" else "dirty"; # This vendorHash represents a derivative of all go.mod dependencies and needs to be adjusted with every change - vendorHash = "sha256-dI47I0+dpoWvMKprYdNbNdPujFahJelmu/HtIbEJzuI="; + vendorHash = "sha256-MvQl2/jaIIjrz9e9L8NbzDW+Ozgx8XI9XI1jFFulRWs="; src = ./.; From fccd22c988f6985cbdd0a3631a256ac4814aa946 Mon Sep 17 00:00:00 2001 From: Uwe Krueger Date: Mon, 28 Oct 2024 09:58:14 +0100 Subject: [PATCH 08/58] fix double completion of option sets in CLI (#1015) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #### What this PR does / why we need it CLI Option objects typically feature some *completion* method. It is used to check values set by CLI options and to provide derived fields. There are different flavors for such completion methods, without any argument, with some context object or with a session object, according to the requirement of the completion function. The `Run` method of a CLI command is called by a Cobra wrapper. THis wrapper knows about the context object for the command and already calls the session-less compöletion flavors. Some commands have options whose completion method requires a session object. This cannot be called by the command wrapper, because the existence of a session is specific for dedicated command implementations. Therefore, those command call the function ` CompleteOptionsWithSession` to create an option processor completing the configured optio set with a session. The current implementation not only tries the session variant but all other variants, also. Therefore, completion of options using the standard completion behaviour are completed twice. The fix changed this behaviour to process the standard completion flavors only if explicitly requested. By default, only the session variant is called (because the others are already called by the used command wrapper. This problem has be detected, because configured upload handlers (per CLI option) were registered twice. #### Which issue(s) this PR fixes --- .../extensions/attrs/ociuploadattr/attr.go | 2 +- cmds/ocm/commands/ocmcmds/common/utils.go | 22 ++++++++++++++----- cmds/ocm/common/options/interfaces.go | 10 +++++++++ 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/api/ocm/extensions/attrs/ociuploadattr/attr.go b/api/ocm/extensions/attrs/ociuploadattr/attr.go index eb3a07e318..529c1472f2 100644 --- a/api/ocm/extensions/attrs/ociuploadattr/attr.go +++ b/api/ocm/extensions/attrs/ociuploadattr/attr.go @@ -55,7 +55,7 @@ func (a AttributeType) Decode(data []byte, unmarshaller runtime.Unmarshaler) (in return &value, nil } if value.Ref == "" { - return nil, errors.ErrInvalidWrap(errors.Newf("missing repository or ref"), oci.KIND_OCI_REFERENCE, string(data)) + return nil, errors.ErrInvalidWrap(errors.Newf("missing repository or ociRef"), oci.KIND_OCI_REFERENCE, string(data)) } data = []byte(value.Ref) } diff --git a/cmds/ocm/commands/ocmcmds/common/utils.go b/cmds/ocm/commands/ocmcmds/common/utils.go index 5537d634b1..b5324d114c 100644 --- a/cmds/ocm/commands/ocmcmds/common/utils.go +++ b/cmds/ocm/commands/ocmcmds/common/utils.go @@ -5,6 +5,7 @@ import ( "strings" "github.com/mandelsoft/goutils/errors" + "github.com/mandelsoft/goutils/general" clictx "ocm.software/ocm/api/cli" "ocm.software/ocm/api/ocm" @@ -66,20 +67,29 @@ func MapArgsToIdentityPattern(args ...string) (metav1.Identity, error) { //////////////////////////////////////////////////////////////////////////////// +// OptionWithSessionCompleter describes the interface for option objects requiring +// a completion with a session. type OptionWithSessionCompleter interface { CompleteWithSession(ctx clictx.OCM, session ocm.Session) error } -func CompleteOptionsWithSession(ctx clictx.Context, session ocm.Session) options.OptionsProcessor { +// CompleteOptionsWithSession provides an options.OptionsProcessor completing +// options by passing a session object using the OptionWithSessionCompleter interface. +// If an optional argument true is given, it also tries the other standard completion +// methods possible for an options object. +func CompleteOptionsWithSession(ctx clictx.Context, session ocm.Session, all ...bool) options.OptionsProcessor { + otherCompleters := general.Optional(all...) return func(opt options.Options) error { if c, ok := opt.(OptionWithSessionCompleter); ok { return c.CompleteWithSession(ctx.OCM(), session) } - if c, ok := opt.(options.OptionWithCLIContextCompleter); ok { - return c.Configure(ctx) - } - if c, ok := opt.(options.SimpleOptionCompleter); ok { - return c.Complete() + if otherCompleters { + if c, ok := opt.(options.OptionWithCLIContextCompleter); ok { + return c.Configure(ctx) + } + if c, ok := opt.(options.SimpleOptionCompleter); ok { + return c.Complete() + } } return nil } diff --git a/cmds/ocm/common/options/interfaces.go b/cmds/ocm/common/options/interfaces.go index e48cbad36c..68caba0413 100644 --- a/cmds/ocm/common/options/interfaces.go +++ b/cmds/ocm/common/options/interfaces.go @@ -10,16 +10,24 @@ import ( "ocm.software/ocm/api/utils/out" ) +// OptionsProcessor is handler used to process all +// option found in a set of options. type OptionsProcessor func(Options) error +// SimpleOptionCompleter describes the interface for an option object +// requirung completion without any further information. type SimpleOptionCompleter interface { Complete() error } +// OptionWithOutputContextCompleter describes the interface for an option object +// requirung completion with an output context. type OptionWithOutputContextCompleter interface { Complete(ctx out.Context) error } +// OptionWithCLIContextCompleter describes the interface for an option object +// requirung completion with a CLI context. type OptionWithCLIContextCompleter interface { Configure(ctx clictx.Context) error } @@ -144,6 +152,8 @@ func (s OptionSet) Get(proto interface{}) bool { return false } +// ProcessOnOptions processes all options found in the option set +// woth a given OptionsProcessor. func (s OptionSet) ProcessOnOptions(f OptionsProcessor) error { for _, n := range s { var err error From 5b1737cc342d5ee5f299657774728ce64360b994 Mon Sep 17 00:00:00 2001 From: Fabian Burth Date: Mon, 28 Oct 2024 10:30:31 +0100 Subject: [PATCH 09/58] chore: makefile adjustment (#1014) #### What this PR does / why we need it Small fix and adjustments in Makefile to avoid future potential confusion. #### Which issue(s) this PR fixes --- Makefile | 3 ++- hack/Makefile | 14 +++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index c9c129d764..b7ca8a681b 100644 --- a/Makefile +++ b/Makefile @@ -74,10 +74,11 @@ check-and-fix: force-test: @go test --count=1 $(EFFECTIVE_DIRECTORIES) +TESTFLAGS = --tags=integration .PHONY: test test: @echo "> Run Tests" - @go test --tags=integration $(EFFECTIVE_DIRECTORIES) + go test $(TESTFLAGS) $(EFFECTIVE_DIRECTORIES) .PHONY: unit-test unit-test: diff --git a/hack/Makefile b/hack/Makefile index d40a41f49c..297864f875 100644 --- a/hack/Makefile +++ b/hack/Makefile @@ -59,7 +59,7 @@ VAULT := $(shell ($(LOCALBIN)/vault --version 2>/dev/null || echo 0.0) | sed 's/ ifneq ($(VAULT), $(VAULT_VERSION)) deps += vault endif -OCI_REGISTRY_VERSION := 3.0.0-alpha.1 +OCI_REGISTRY_VERSION := 3.0.0-beta.1 OCI_REGISTRY := $(shell (registry --version 2>/dev/null || echo 0.0) | sed 's/.* v\([0-9a-z\.\-]*\).*/\1/') ifneq ($(OCI_REGISTRY), $(OCI_REGISTRY_VERSION)) deps += oci-registry @@ -97,18 +97,18 @@ go-bindata: .PHONY: vault vault: - @if [ "$(VAULT)" != "$(VAULT_VERSION)" ]; then \ +ifneq ($(VAULT), $(VAULT_VERSION)) curl -o $(LOCALBIN)/vault.zip https://releases.hashicorp.com/vault/$(VAULT_VERSION)/vault_$(VAULT_VERSION)_$(OS_ARCH).zip; \ unzip -o $(LOCALBIN)/vault.zip -d $(LOCALBIN); \ rm $(LOCALBIN)/vault.zip; \ - chmod a+x $(LOCALBIN)/vault;\ - fi + chmod a+x $(LOCALBIN)/vault; +endif .PHONY: oci-registry oci-registry: - @if [ "$(OCI_REGISTRY)" != "$(OCI_REGISTRY_VERSION)" ]; then \ - go install -v github.com/distribution/distribution/v3/cmd/registry@v3.0.0-alpha.1; \ - fi +ifeq (,$(findstring $(OCI_REGISTRY_VERSION), $(OCI_REGISTRY))) + go install -v github.com/distribution/distribution/v3/cmd/registry@v$(OCI_REGISTRY_VERSION) +endif $(GOPATH)/bin/goimports: go install -v golang.org/x/tools/cmd/goimports@latest From 0a0f4877a0d42f56018595d3ca6fa7cda7c260fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakob=20M=C3=B6ller?= Date: Tue, 29 Oct 2024 13:41:24 +0100 Subject: [PATCH 10/58] chore: release fallout corrections (#1023) runs make generate because it was only run on the release branch. adds check as mandatory dep of release to make sure the tag-check inside is not rgiacing against release. adds necessary build steps for tools needed in make generate. #### What this PR does / why we need it #### Which issue(s) this PR fixes --- .github/workflows/release.yaml | 9 +++++---- examples/lib/tour/01-getting-started/README.md | 14 +++++++------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index c28e0b05e4..fa9dcc133e 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -119,9 +119,10 @@ jobs: pull-requests: read release: -# needs: -# - lint-and-test -# - components + needs: + # run check before actual release to make sure we succeed + # they will be skipped from the needs check + - check name: Release Build runs-on: large_runner permissions: @@ -283,7 +284,7 @@ jobs: v="$(go run ./api/version/generate bump-version)" echo "$v" > VERSION # Trigger a bump of any potential files that depend on a new version - make generate + make -f hack/Makefile mdref && make -f hack/Makefile go-bindata && make generate git add --all git commit -m "Update version to $v" git push origin ${GITHUB_REF#refs/heads/} diff --git a/examples/lib/tour/01-getting-started/README.md b/examples/lib/tour/01-getting-started/README.md index 33abc6f3ed..1c0b22d69e 100644 --- a/examples/lib/tour/01-getting-started/README.md +++ b/examples/lib/tour/01-getting-started/README.md @@ -168,32 +168,32 @@ differ, because the code always describes the latest version): ```text resources of the latest version: - version: 0.17.0-rc.1 + version: 0.17.0 provider: ocm.software 1: name: ocmcli extra identity: "architecture"="amd64","os"="linux" resource type: executable - access: Local blob sha256:e02e4e177a41fd86d2c63f7b7769e2d403c53b10d802f1fe57b5759305b64b32[] + access: Local blob sha256:03a45dcde67ba565fe806cb5db67da3387f772f7c50af711a0edd6f802570c04[] 2: name: ocmcli extra identity: "architecture"="arm64","os"="linux" resource type: executable - access: Local blob sha256:10ff2b950bb26601e497c317289a2fcc1a5ccee4ba5c7dff842cac6d2d78c2ba[] + access: Local blob sha256:5a622634ae43cf03eac91079389d83266891d1f9b2d8a3884cef6fe639180324[] 3: name: ocmcli extra identity: "architecture"="arm64","os"="darwin" resource type: executable - access: Local blob sha256:b033848ab254b52eea5389bb58e1caaa4cf896a1beef95d15187a8466ce3d861[] + access: Local blob sha256:1482fe5b764e3a86cf96704d7a839ad7e53dcbfd4f5fce5405abffb1962153dd[] 4: name: ocmcli extra identity: "architecture"="amd64","os"="darwin" resource type: executable - access: Local blob sha256:15d86a60ade3ec5036ce71a163b7b92745f6ce7cdf755aa5123b811e2c5909ca[] + access: Local blob sha256:805f181aff48511eea12c699ed1bbcee8bdc4c5168924e81058aff8715946875[] 5: name: ocmcli extra identity: "architecture"="amd64","os"="windows" resource type: executable - access: Local blob sha256:72b6c6aa0b5116892972f7152306bd5b44ffce04f2832dc4557d900a921f7614[] + access: Local blob sha256:20839c68bf0c4cf99444d78ebb93f53358fa9e95fe806f186220bd21d520efa7[] 6: name: ocmcli-image extra identity: resource type: ociImage - access: OCI artifact ghcr.io/open-component-model/ocm/ocm.software/ocmcli/ocmcli-image:0.17.0-rc.1@sha256:c7627052f1dfcc1dbe0be508466387b0af9bc48d7942911f308b91e3b35ff30c + access: OCI artifact ghcr.io/open-component-model/ocm/ocm.software/ocmcli/ocmcli-image:0.17.0@sha256:16fb52a1cb11c867bd058f4124dea53fbab94229842cc14b52653c2e80b1cede ``` Resources have some metadata, like their identity and a resource type. From e076fa4d91c6950c27a8934b0bca997dd2767fd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakob=20M=C3=B6ller?= Date: Tue, 29 Oct 2024 14:53:41 +0100 Subject: [PATCH 11/58] fix: remove ocm release key if present (#1024) #### What this PR does / why we need it #### Which issue(s) this PR fixes --- .github/workflows/release.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index fa9dcc133e..7d6729a541 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -259,6 +259,10 @@ jobs: GORELEASER_CURRENT_TAG: ${{ env.RELEASE_VERSION }} NFPM_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} + - name: Remove GPG Token file + run: | + rm ocm-releases-key.gpg + - name: Push OCM Components env: GITHUBORG: ${{ github.repository_owner }} From 0d76b3cf563e50cbbf178d213ea9e45ceef40d21 Mon Sep 17 00:00:00 2001 From: Fabian Burth Date: Tue, 29 Oct 2024 17:56:21 +0100 Subject: [PATCH 12/58] Adjust README with rotated GPG key (#1025) #### What this PR does / why we need it #### Which issue(s) this PR fixes --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 576b4399ae..d0025805a8 100644 --- a/README.md +++ b/README.md @@ -173,7 +173,7 @@ More comprehensive examples can be taken from the [`components`](components) con ## GPG Public Key -The authenticity of released packages that have been uploaded to public repositories can be verified using our GPG public key. You can find the key in the file [OCM-RELEASES-PUBLIC.gpg](https://ocm.software/OCM-RELEASES-PUBLIC.gpg) on our website. +The authenticity of released packages that have been uploaded to public repositories can be verified using our GPG public key. You can find the current key in the file [OCM-RELEASES-PUBLIC-CURRENT.gpg](https://ocm.software/gpg/OCM-RELEASES-PUBLIC-CURRENT.gpg) on our website. You can find the old keys in the website github repository [here](https://github.com/open-component-model/ocm-website/tree/main/static/gpg). ## Contributing From a9e7420d66d0ba718dee82d37c639e79e8c897d7 Mon Sep 17 00:00:00 2001 From: Uwe Krueger Date: Thu, 31 Oct 2024 11:04:39 +0100 Subject: [PATCH 13/58] fix downloader handling (#1031) #### What this PR does / why we need it - fix types nil pointer to support empty config for downloader registration - fix config object docu for uploader/downloader config object #### Which issue(s) this PR fixes --- api/ocm/extensions/blobhandler/config/type.go | 2 +- .../download/config/registration_test.go | 40 +++++++++++++++++++ .../extensions/download/config/suite_test.go | 13 ++++++ api/ocm/extensions/download/config/type.go | 6 ++- .../common/options/optutils/reg_test.go | 14 +++---- .../common/options/optutils/registration.go | 8 ++-- .../options/uploaderoption/uploader_test.go | 12 +++--- .../ocmcmds/resources/download/cmd_test.go | 22 ++++++++++ docs/reference/ocm_configfile.md | 8 ++-- 9 files changed, 101 insertions(+), 24 deletions(-) create mode 100644 api/ocm/extensions/download/config/registration_test.go create mode 100644 api/ocm/extensions/download/config/suite_test.go diff --git a/api/ocm/extensions/blobhandler/config/type.go b/api/ocm/extensions/blobhandler/config/type.go index 7d36e228ba..211108164c 100644 --- a/api/ocm/extensions/blobhandler/config/type.go +++ b/api/ocm/extensions/blobhandler/config/type.go @@ -82,7 +82,7 @@ of preconfigured upload handler registrations (see ocm ocm-uploadhandlers type: ` + ConfigType + ` description: "my standard upload handler configuration" - handlers: + registrations: - name: oci/artifact artifactType: ociImage config: diff --git a/api/ocm/extensions/download/config/registration_test.go b/api/ocm/extensions/download/config/registration_test.go new file mode 100644 index 0000000000..e2f81a3f40 --- /dev/null +++ b/api/ocm/extensions/download/config/registration_test.go @@ -0,0 +1,40 @@ +package config_test + +import ( + "encoding/json" + + . "github.com/mandelsoft/goutils/testutils" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "ocm.software/ocm/api/ocm" + "ocm.software/ocm/api/ocm/extensions/download" + "ocm.software/ocm/api/ocm/ocmutils" + "ocm.software/ocm/api/tech/helm" + + me "ocm.software/ocm/api/ocm/extensions/download/config" +) + +var _ = Describe("Download Handler regigistration", func() { + It("register by ocm config", func() { + + ctx := ocm.New() + + cfg := me.New() + cfg.AddRegistration(me.Registration{ + Name: "helm/artifact", + Description: "some registration", + HandlerOptions: download.HandlerOptions{ + HandlerKey: download.HandlerKey{ + ArtifactType: "someType", + }, + }, + Config: nil, + }) + + data := Must(json.Marshal(cfg)) + ocmutils.ConfigureByData(ctx, data, "manual") + + h := download.For(ctx).LookupHandler("someType", helm.ChartMediaType) + Expect(h.Len()).To(Equal(1)) + }) +}) diff --git a/api/ocm/extensions/download/config/suite_test.go b/api/ocm/extensions/download/config/suite_test.go new file mode 100644 index 0000000000..c580e9c0ec --- /dev/null +++ b/api/ocm/extensions/download/config/suite_test.go @@ -0,0 +1,13 @@ +package config_test + +import ( + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +func TestConfig(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "cdownload handler config Test Suite") +} diff --git a/api/ocm/extensions/download/config/type.go b/api/ocm/extensions/download/config/type.go index 7f6aca2ce5..c29fa3eeee 100644 --- a/api/ocm/extensions/download/config/type.go +++ b/api/ocm/extensions/download/config/type.go @@ -81,10 +81,12 @@ of preconfigured download handler registrations (see ocm ocm-downloadhandle
     type: ` + ConfigType + `
     description: "my standard download handler configuration"
-    handlers:
+    registrations:
       - name: oci/artifact
         artifactType: ociImage
-        mimeType:
+        mimeType: ...
+        description: ...
+        priority: ...
         config: ...
       ...
 
diff --git a/cmds/ocm/commands/ocmcmds/common/options/optutils/reg_test.go b/cmds/ocm/commands/ocmcmds/common/options/optutils/reg_test.go index edca672cdb..cb15c02251 100644 --- a/cmds/ocm/commands/ocmcmds/common/options/optutils/reg_test.go +++ b/cmds/ocm/commands/ocmcmds/common/options/optutils/reg_test.go @@ -1,8 +1,6 @@ package optutils_test import ( - "encoding/json" - . "github.com/mandelsoft/goutils/testutils" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" @@ -37,7 +35,7 @@ var _ = Describe("registration options", func() { Name: "plugin/name", ArtifactType: "art", MediaType: "media", - Config: json.RawMessage(`{"name":"Name"}`), + Config: []byte(`{"name":"Name"}`), }})) }) @@ -49,7 +47,7 @@ var _ = Describe("registration options", func() { Name: "plugin/name", ArtifactType: "art", MediaType: "", - Config: json.RawMessage(`{"name":"Name"}`), + Config: []byte(`{"name":"Name"}`), }})) }) @@ -61,7 +59,7 @@ var _ = Describe("registration options", func() { Name: "plugin/name", ArtifactType: "", MediaType: "", - Config: json.RawMessage(`{"name":"Name"}`), + Config: []byte(`{"name":"Name"}`), }})) }) @@ -73,7 +71,7 @@ var _ = Describe("registration options", func() { Name: "plugin/name", ArtifactType: "", MediaType: "", - Config: json.RawMessage(`{"name":"Name"}`), + Config: []byte(`{"name":"Name"}`), }})) }) @@ -85,7 +83,7 @@ var _ = Describe("registration options", func() { Name: "plugin/name", ArtifactType: "", MediaType: "", - Config: json.RawMessage(`"Name"`), + Config: []byte(`"Name"`), }})) }) @@ -101,7 +99,7 @@ var _ = Describe("registration options", func() { Name: "plugin/name", ArtifactType: "", MediaType: "", - Config: json.RawMessage(`{"name":"Name"}`), + Config: []byte(`{"name":"Name"}`), }})) }) diff --git a/cmds/ocm/commands/ocmcmds/common/options/optutils/registration.go b/cmds/ocm/commands/ocmcmds/common/options/optutils/registration.go index aaa7040419..a83fe2b1fd 100644 --- a/cmds/ocm/commands/ocmcmds/common/options/optutils/registration.go +++ b/cmds/ocm/commands/ocmcmds/common/options/optutils/registration.go @@ -18,7 +18,7 @@ type Registration struct { Name string ArtifactType string MediaType string - Config json.RawMessage + Config interface{} } func NewRegistrationOption(name, short, desc, usage string) RegistrationOption { @@ -64,7 +64,7 @@ func (o *RegistrationOption) Configure(ctx clictx.Context) error { } } - var data json.RawMessage + var data interface{} var raw []byte var err error if strings.HasPrefix(v, "@") { @@ -73,7 +73,9 @@ func (o *RegistrationOption) Configure(ctx clictx.Context) error { return errors.Wrapf(err, "cannot read %s config from %q", o.name, v[1:]) } } else { - raw = []byte(v) + if v != "" { + raw = []byte(v) + } } if len(raw) > 0 { diff --git a/cmds/ocm/commands/ocmcmds/common/options/uploaderoption/uploader_test.go b/cmds/ocm/commands/ocmcmds/common/options/uploaderoption/uploader_test.go index 8dbd4404e7..fbc5e9f99d 100644 --- a/cmds/ocm/commands/ocmcmds/common/options/uploaderoption/uploader_test.go +++ b/cmds/ocm/commands/ocmcmds/common/options/uploaderoption/uploader_test.go @@ -1,8 +1,6 @@ package uploaderoption import ( - "encoding/json" - . "github.com/mandelsoft/goutils/testutils" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" @@ -33,7 +31,7 @@ var _ = Describe("uploader option", func() { Name: "plugin/name", ArtifactType: "art", MediaType: "media", - Config: json.RawMessage(`{"name":"Name"}`), + Config: []byte(`{"name":"Name"}`), }})) }) @@ -45,7 +43,7 @@ var _ = Describe("uploader option", func() { Name: "plugin/name", ArtifactType: "art", MediaType: "", - Config: json.RawMessage(`{"name":"Name"}`), + Config: []byte(`{"name":"Name"}`), }})) }) @@ -57,7 +55,7 @@ var _ = Describe("uploader option", func() { Name: "plugin/name", ArtifactType: "", MediaType: "", - Config: json.RawMessage(`{"name":"Name"}`), + Config: []byte(`{"name":"Name"}`), }})) }) @@ -69,7 +67,7 @@ var _ = Describe("uploader option", func() { Name: "plugin/name", ArtifactType: "", MediaType: "", - Config: json.RawMessage(`{"name":"Name"}`), + Config: []byte(`{"name":"Name"}`), }})) }) @@ -81,7 +79,7 @@ var _ = Describe("uploader option", func() { Name: "plugin/name", ArtifactType: "", MediaType: "", - Config: json.RawMessage(`"Name"`), + Config: []byte(`"Name"`), }})) }) diff --git a/cmds/ocm/commands/ocmcmds/resources/download/cmd_test.go b/cmds/ocm/commands/ocmcmds/resources/download/cmd_test.go index e3aea958ca..6aab6733e6 100644 --- a/cmds/ocm/commands/ocmcmds/resources/download/cmd_test.go +++ b/cmds/ocm/commands/ocmcmds/resources/download/cmd_test.go @@ -78,6 +78,28 @@ var _ = Describe("Test Environment", func() { Expect(env.ReadFile(OUT)).To(Equal([]byte("testdata"))) }) + It("registers download handler without config", func() { + env.OCMCommonTransport(ARCH, accessio.FormatDirectory, func() { + env.Component(COMP, func() { + env.Version(VERSION, func() { + env.Provider(PROVIDER) + env.Resource("testdata", "", "PlainText", metav1.LocalRelation, func() { + env.BlobStringData(mime.MIME_TEXT, "testdata") + }) + }) + }) + }) + + buf := bytes.NewBuffer(nil) + Expect(env.CatchOutput(buf).Execute("download", "resources", "--downloader", "helm/artifact:helm/v1", "-O", OUT, ARCH)).To(Succeed()) + Expect(buf.String()).To(StringEqualTrimmedWithContext( + ` +/tmp/res: 8 byte(s) written +`)) + Expect(env.FileExists(OUT)).To(BeTrue()) + Expect(env.ReadFile(OUT)).To(Equal([]byte("testdata"))) + }) + Context("with closure", func() { BeforeEach(func() { env.OCMCommonTransport(ARCH, accessio.FormatDirectory, func() { diff --git a/docs/reference/ocm_configfile.md b/docs/reference/ocm_configfile.md index 4cccc01e1e..e92a1ba5e6 100644 --- a/docs/reference/ocm_configfile.md +++ b/docs/reference/ocm_configfile.md @@ -66,10 +66,12 @@ The following configuration types are supported:
       type: downloader.ocm.config.ocm.software
       description: "my standard download handler configuration"
-      handlers:
+      registrations:
         - name: oci/artifact
           artifactType: ociImage
-          mimeType:
+          mimeType: ...
+          description: ...
+          priority: ...
           config: ...
         ...
   
@@ -317,7 +319,7 @@ The following configuration types are supported:
       type: uploader.ocm.config.ocm.software
       description: "my standard upload handler configuration"
-      handlers:
+      registrations:
         - name: oci/artifact
           artifactType: ociImage
           config:

From c8c3abcbde3758d5b4adf9c38bb0a0d47bcd883c Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Sun, 3 Nov 2024 19:16:33 +0100
Subject: [PATCH 14/58] chore(deps): bump the go group with 8 updates (#1036)

Bumps the go group with 8 updates:

| Package | From | To |
| --- | --- | --- |
| [github.com/aws/aws-sdk-go-v2](https://github.com/aws/aws-sdk-go-v2) |
`1.32.2` | `1.32.3` |
|
[github.com/aws/aws-sdk-go-v2/config](https://github.com/aws/aws-sdk-go-v2)
| `1.28.0` | `1.28.1` |
|
[github.com/aws/aws-sdk-go-v2/credentials](https://github.com/aws/aws-sdk-go-v2)
| `1.17.41` | `1.17.42` |
|
[github.com/aws/aws-sdk-go-v2/feature/s3/manager](https://github.com/aws/aws-sdk-go-v2)
| `1.17.34` | `1.17.35` |
|
[github.com/aws/aws-sdk-go-v2/service/ecr](https://github.com/aws/aws-sdk-go-v2)
| `1.36.2` | `1.36.3` |
|
[github.com/aws/aws-sdk-go-v2/service/s3](https://github.com/aws/aws-sdk-go-v2)
| `1.66.1` | `1.66.2` |
| [github.com/onsi/ginkgo/v2](https://github.com/onsi/ginkgo) | `2.20.2`
| `2.21.0` |
| [github.com/onsi/gomega](https://github.com/onsi/gomega) | `1.34.2` |
`1.35.1` |

Updates `github.com/aws/aws-sdk-go-v2` from 1.32.2 to 1.32.3
Commits
  • 6b53348 Release 2024-10-28
  • 784d2d3 Regenerated Clients
  • 7258bd2 Update endpoints model
  • f322198 Update API model
  • b65b80a Merge pull request #2852 from RanVaknin/signature-header-parsing-fix
  • 803614d Fixing changelog description and implementation to use TrimSpace
  • b12c8cf adding changelog
  • f0caa97 patching GetSignedRequestSignature to cover edge cases with the signature
  • e058903 drop service/nimble (#2851)
  • 896793a Release 2024-10-25
  • Additional commits viewable in compare view

Updates `github.com/aws/aws-sdk-go-v2/config` from 1.28.0 to 1.28.1
Commits
  • 6b53348 Release 2024-10-28
  • 784d2d3 Regenerated Clients
  • 7258bd2 Update endpoints model
  • f322198 Update API model
  • b65b80a Merge pull request #2852 from RanVaknin/signature-header-parsing-fix
  • 803614d Fixing changelog description and implementation to use TrimSpace
  • b12c8cf adding changelog
  • f0caa97 patching GetSignedRequestSignature to cover edge cases with the signature
  • e058903 drop service/nimble (#2851)
  • 896793a Release 2024-10-25
  • Additional commits viewable in compare view

Updates `github.com/aws/aws-sdk-go-v2/credentials` from 1.17.41 to 1.17.42
Commits
  • 6b53348 Release 2024-10-28
  • 784d2d3 Regenerated Clients
  • 7258bd2 Update endpoints model
  • f322198 Update API model
  • b65b80a Merge pull request #2852 from RanVaknin/signature-header-parsing-fix
  • 803614d Fixing changelog description and implementation to use TrimSpace
  • b12c8cf adding changelog
  • f0caa97 patching GetSignedRequestSignature to cover edge cases with the signature
  • e058903 drop service/nimble (#2851)
  • 896793a Release 2024-10-25
  • Additional commits viewable in compare view

Updates `github.com/aws/aws-sdk-go-v2/feature/s3/manager` from 1.17.34 to 1.17.35
Commits

Updates `github.com/aws/aws-sdk-go-v2/service/ecr` from 1.36.2 to 1.36.3
Commits

Updates `github.com/aws/aws-sdk-go-v2/service/s3` from 1.66.1 to 1.66.2
Commits
  • 6b53348 Release 2024-10-28
  • 784d2d3 Regenerated Clients
  • 7258bd2 Update endpoints model
  • f322198 Update API model
  • b65b80a Merge pull request #2852 from RanVaknin/signature-header-parsing-fix
  • 803614d Fixing changelog description and implementation to use TrimSpace
  • b12c8cf adding changelog
  • f0caa97 patching GetSignedRequestSignature to cover edge cases with the signature
  • e058903 drop service/nimble (#2851)
  • See full diff in compare view

Updates `github.com/onsi/ginkgo/v2` from 2.20.2 to 2.21.0
Release notes

Sourced from github.com/onsi/ginkgo/v2's releases.

v2.21.0

2.21.0

Features

  • add support for GINKGO_TIME_FORMAT [a69eb39]
  • add GINKGO_NO_COLOR to disable colors via environment variables [bcab9c8]

Fixes

  • increase threshold in timeline matcher [e548367]
  • Fix the document by replacing SpecsThatWillBeRun with SpecsThatWillRun [c2c4d3c]

Maintenance

  • bump various dependencies [7e65a00]
Changelog

Sourced from github.com/onsi/ginkgo/v2's changelog.

2.21.0

Features

  • add support for GINKGO_TIME_FORMAT [a69eb39]
  • add GINKGO_NO_COLOR to disable colors via environment variables [bcab9c8]

Fixes

  • increase threshold in timeline matcher [e548367]
  • Fix the document by replacing SpecsThatWillBeRun with SpecsThatWillRun [c2c4d3c]

Maintenance

  • bump various dependencies [7e65a00]
Commits
  • ac8918e v2.21.0
  • a69eb39 add support for GINKGO_TIME_FORMAT
  • e548367 increase threshold in timeline matcher
  • bcab9c8 add GINKGO_NO_COLOR to disable colors via environment variables
  • 7e65a00 bump various dependencies
  • c2c4d3c Fix the document by replacing SpecsThatWillBeRun with SpecsThatWillRun
  • See full diff in compare view

Updates `github.com/onsi/gomega` from 1.34.2 to 1.35.1
Release notes

Sourced from github.com/onsi/gomega's releases.

v1.35.1

1.35.1

Fixes

  • Export EnforceDefaultTimeoutsWhenUsingContexts and DisableDefaultTimeoutsWhenUsingContext [ca36da1]

v1.35.0

1.35.0

Features

  • You can now call EnforceDefaultTimeoutsWhenUsingContexts() to have Eventually honor the default timeout when passed a context. (prior to this you had to expclility add a timeout) [e4c4265]
  • You can call StopTrying(message).Successfully() to abort a Consistently early without failure [eeca931]

Fixes

  • Stop memoizing the result of HaveField to avoid unexpected errors when used with async assertions. [3bdbc4e]

Maintenance

  • Bump all dependencies [a05a416]
Changelog

Sourced from github.com/onsi/gomega's changelog.

1.35.1

Fixes

  • Export EnforceDefaultTimeoutsWhenUsingContexts and DisableDefaultTimeoutsWhenUsingContext [ca36da1]

1.35.0

Features

  • You can now call EnforceDefaultTimeoutsWhenUsingContexts() to have Eventually honor the default timeout when passed a context. (prior to this you had to expclility add a timeout) [e4c4265]
  • You can call StopTrying(message).Successfully() to abort a Consistently early without failure [eeca931]

Fixes

  • Stop memoizing the result of HaveField to avoid unexpected errors when used with async assertions. [3bdbc4e]

Maintenance

  • Bump all dependencies [a05a416]
Commits
  • 9f5a208 v1.35.1
  • ca36da1 Export EnforceDefaultTimeoutsWhenUsingContexts and DisableDefaultTimeoutsWhen...
  • d6331f9 v1.35.0
  • 5deaf23 fix tests, but like actually this time
  • eeca931 Add Successfully() to StopTrying() to signal that Consistently can end early ...
  • 3bdbc4e stop memoizing result of HaveField
  • e35358d sheepishly fix broken test. thanks CI
  • 1b717d7 grrr. go mod tidy
  • a05a416 bump all dependencies
  • e4c4265 Add EnforceDefaultTimeoutsWhenUsingContexts()
  • See full diff in compare view

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 38 ++++++++++++++--------------- go.sum | 76 +++++++++++++++++++++++++++++----------------------------- 2 files changed, 57 insertions(+), 57 deletions(-) diff --git a/go.mod b/go.mod index 0972a89432..2ba017ab8e 100644 --- a/go.mod +++ b/go.mod @@ -8,12 +8,12 @@ require ( github.com/DataDog/gostackparse v0.7.0 github.com/InfiniteLoopSpace/go_S-MIME v0.0.0-20181221134359-3f58f9a4b2b6 github.com/Masterminds/semver/v3 v3.3.0 - github.com/aws/aws-sdk-go-v2 v1.32.2 - github.com/aws/aws-sdk-go-v2/config v1.28.0 - github.com/aws/aws-sdk-go-v2/credentials v1.17.41 - github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.34 - github.com/aws/aws-sdk-go-v2/service/ecr v1.36.2 - github.com/aws/aws-sdk-go-v2/service/s3 v1.66.1 + github.com/aws/aws-sdk-go-v2 v1.32.3 + github.com/aws/aws-sdk-go-v2/config v1.28.1 + github.com/aws/aws-sdk-go-v2/credentials v1.17.42 + github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.35 + github.com/aws/aws-sdk-go-v2/service/ecr v1.36.3 + github.com/aws/aws-sdk-go-v2/service/s3 v1.66.2 github.com/cloudflare/cfssl v1.6.5 github.com/containerd/containerd v1.7.23 github.com/containerd/errdefs v0.3.0 @@ -51,8 +51,8 @@ require ( github.com/mitchellh/copystructure v1.2.0 github.com/mittwald/go-helm-client v0.12.14 github.com/modern-go/reflect2 v1.0.2 - github.com/onsi/ginkgo/v2 v2.20.2 - github.com/onsi/gomega v1.34.2 + github.com/onsi/ginkgo/v2 v2.21.0 + github.com/onsi/gomega v1.35.1 github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/image-spec v1.1.0 github.com/pkg/errors v0.9.1 @@ -127,19 +127,19 @@ require ( github.com/aliyun/credentials-go v1.3.10 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.6 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.17 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.21 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.21 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.18 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.22 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.22 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect - github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.21 // indirect + github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.22 // indirect github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.27.2 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.0 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.2 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.2 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.2 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.24.2 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.2 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.32.2 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.3 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.3 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.3 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.24.3 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.3 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.32.3 // indirect github.com/aws/smithy-go v1.22.0 // indirect github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20241009180534-e718692eec62 // indirect github.com/beorn7/perks v1.0.1 // indirect @@ -214,7 +214,7 @@ require ( github.com/google/go-github/v55 v55.0.0 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/google/gofuzz v1.2.0 // indirect - github.com/google/pprof v0.0.0-20241009165004-a3522334989c // indirect + github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db // indirect github.com/google/s2a-go v0.1.8 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/google/uuid v1.6.0 // indirect diff --git a/go.sum b/go.sum index 57b55c754a..6325568d92 100644 --- a/go.sum +++ b/go.sum @@ -165,48 +165,48 @@ github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3d github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/aws/aws-sdk-go v1.55.5 h1:KKUZBfBoyqy5d3swXyiC7Q76ic40rYcbqH7qjh59kzU= github.com/aws/aws-sdk-go v1.55.5/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU= -github.com/aws/aws-sdk-go-v2 v1.32.2 h1:AkNLZEyYMLnx/Q/mSKkcMqwNFXMAvFto9bNsHqcTduI= -github.com/aws/aws-sdk-go-v2 v1.32.2/go.mod h1:2SK5n0a2karNTv5tbP1SjsX0uhttou00v/HpXKM1ZUo= +github.com/aws/aws-sdk-go-v2 v1.32.3 h1:T0dRlFBKcdaUPGNtkBSwHZxrtis8CQU17UpNBZYd0wk= +github.com/aws/aws-sdk-go-v2 v1.32.3/go.mod h1:2SK5n0a2karNTv5tbP1SjsX0uhttou00v/HpXKM1ZUo= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.6 h1:pT3hpW0cOHRJx8Y0DfJUEQuqPild8jRGmSFmBgvydr0= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.6/go.mod h1:j/I2++U0xX+cr44QjHay4Cvxj6FUbnxrgmqN3H1jTZA= -github.com/aws/aws-sdk-go-v2/config v1.28.0 h1:FosVYWcqEtWNxHn8gB/Vs6jOlNwSoyOCA/g/sxyySOQ= -github.com/aws/aws-sdk-go-v2/config v1.28.0/go.mod h1:pYhbtvg1siOOg8h5an77rXle9tVG8T+BWLWAo7cOukc= -github.com/aws/aws-sdk-go-v2/credentials v1.17.41 h1:7gXo+Axmp+R4Z+AK8YFQO0ZV3L0gizGINCOWxSLY9W8= -github.com/aws/aws-sdk-go-v2/credentials v1.17.41/go.mod h1:u4Eb8d3394YLubphT4jLEwN1rLNq2wFOlT6OuxFwPzU= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.17 h1:TMH3f/SCAWdNtXXVPPu5D6wrr4G5hI1rAxbcocKfC7Q= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.17/go.mod h1:1ZRXLdTpzdJb9fwTMXiLipENRxkGMTn1sfKexGllQCw= -github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.34 h1:os83HS/WfOwi1LsZWLCSHTyj+whvPGaxUsq/D1Ol2Q0= -github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.34/go.mod h1:tG0BaDCAweumHRsOHm72tuPgAfRLASQThgthWYeTyV8= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.21 h1:UAsR3xA31QGf79WzpG/ixT9FZvQlh5HY1NRqSHBNOCk= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.21/go.mod h1:JNr43NFf5L9YaG3eKTm7HQzls9J+A9YYcGI5Quh1r2Y= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.21 h1:6jZVETqmYCadGFvrYEQfC5fAQmlo80CeL5psbno6r0s= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.21/go.mod h1:1SR0GbLlnN3QUmYaflZNiH1ql+1qrSiB2vwcJ+4UM60= +github.com/aws/aws-sdk-go-v2/config v1.28.1 h1:oxIvOUXy8x0U3fR//0eq+RdCKimWI900+SV+10xsCBw= +github.com/aws/aws-sdk-go-v2/config v1.28.1/go.mod h1:bRQcttQJiARbd5JZxw6wG0yIK3eLeSCPdg6uqmmlIiI= +github.com/aws/aws-sdk-go-v2/credentials v1.17.42 h1:sBP0RPjBU4neGpIYyx8mkU2QqLPl5u9cmdTWVzIpHkM= +github.com/aws/aws-sdk-go-v2/credentials v1.17.42/go.mod h1:FwZBfU530dJ26rv9saAbxa9Ej3eF/AK0OAY86k13n4M= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.18 h1:68jFVtt3NulEzojFesM/WVarlFpCaXLKaBxDpzkQ9OQ= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.18/go.mod h1:Fjnn5jQVIo6VyedMc0/EhPpfNlPl7dHV916O6B+49aE= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.35 h1:ihPPdcCVSN0IvBByXwqVp28/l4VosBZ6sDulcvU2J7w= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.35/go.mod h1:JkgEhs3SVF51Dj3m1Bj+yL8IznpxzkwlA3jLg3x7Kls= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.22 h1:Jw50LwEkVjuVzE1NzkhNKkBf9cRN7MtE1F/b2cOKTUM= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.22/go.mod h1:Y/SmAyPcOTmpeVaWSzSKiILfXTVJwrGmYZhcRbhWuEY= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.22 h1:981MHwBaRZM7+9QSR6XamDzF/o7ouUGxFzr+nVSIhrs= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.22/go.mod h1:1RA1+aBEfn+CAB/Mh0MB6LsdCYCnjZm7tKXtnk499ZQ= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 h1:VaRN3TlFdd6KxX1x3ILT5ynH6HvKgqdiXoTxAF4HQcQ= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.21 h1:7edmS3VOBDhK00b/MwGtGglCm7hhwNYnjJs/PgFdMQE= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.21/go.mod h1:Q9o5h4HoIWG8XfzxqiuK/CGUbepCJ8uTlaE3bAbxytQ= -github.com/aws/aws-sdk-go-v2/service/ecr v1.36.2 h1:VDQaVwGOokbd3VUbHF+wupiffdrbAZPdQnr5XZMJqrs= -github.com/aws/aws-sdk-go-v2/service/ecr v1.36.2/go.mod h1:lvUlMghKYmSxSfv0vU7pdU/8jSY+s0zpG8xXhaGKCw0= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.22 h1:yV+hCAHZZYJQcwAaszoBNwLbPItHvApxT0kVIw6jRgs= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.22/go.mod h1:kbR1TL8llqB1eGnVbybcA4/wgScxdylOdyAd51yxPdw= +github.com/aws/aws-sdk-go-v2/service/ecr v1.36.3 h1:bqmoQEKpWFRDRxOv4lC5yZLc+N1cogZHPLeQACfVUJo= +github.com/aws/aws-sdk-go-v2/service/ecr v1.36.3/go.mod h1:KwOqlt4MOBK9EpOGkj8RU9fqfTEae5AOUHi1pDEZ3OQ= github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.27.2 h1:Zru9Iy2JPM5+uRnFnoqeOZzi8JIVIHJ0ua6JdeDHcyg= github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.27.2/go.mod h1:PtQC3XjutCYFCn1+i8+wtpDaXvEK+vXF2gyLIKAmh4A= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.0 h1:TToQNkvGguu209puTojY/ozlqy2d/SFNcoLIqTFi42g= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.0/go.mod h1:0jp+ltwkf+SwG2fm/PKo8t4y8pJSgOCO4D8Lz3k0aHQ= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.2 h1:4FMHqLfk0efmTqhXVRL5xYRqlEBNBiRI7N6w4jsEdd4= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.2/go.mod h1:LWoqeWlK9OZeJxsROW2RqrSPvQHKTpp69r/iDjwsSaw= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.2 h1:s7NA1SOw8q/5c0wr8477yOPp0z+uBaXBnLE0XYb0POA= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.2/go.mod h1:fnjjWyAW/Pj5HYOxl9LJqWtEwS7W2qgcRLWP+uWbss0= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.2 h1:t7iUP9+4wdc5lt3E41huP+GvQZJD38WLsgVp4iOtAjg= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.2/go.mod h1:/niFCtmuQNxqx9v8WAPq5qh7EH25U4BF6tjoyq9bObM= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.3 h1:kT6BcZsmMtNkP/iYMcRG+mIEA/IbeiUimXtGmqF39y0= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.3/go.mod h1:Z8uGua2k4PPaGOYn66pK02rhMrot3Xk3tpBuUFPomZU= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.3 h1:qcxX0JYlgWH3hpPUnd6U0ikcl6LLA9sLkXE2w1fpMvY= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.3/go.mod h1:cLSNEmI45soc+Ef8K/L+8sEA3A3pYFEYf5B5UI+6bH4= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.3 h1:ZC7Y/XgKUxwqcdhO5LE8P6oGP1eh6xlQReWNKfhvJno= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.3/go.mod h1:WqfO7M9l9yUAw0HcHaikwRd/H6gzYdz7vjejCA5e2oY= github.com/aws/aws-sdk-go-v2/service/kms v1.37.0 h1:ovrHGOiNu4S0GSMeexZlsMhBkUb3bCE3iOktFZ7rmBU= github.com/aws/aws-sdk-go-v2/service/kms v1.37.0/go.mod h1:YLqfMkq9GWbICgqT5XMIzT8I2+MxVKodTnNBo3BONgE= -github.com/aws/aws-sdk-go-v2/service/s3 v1.66.1 h1:MkQ4unegQEStiQYmfFj+Aq5uTp265ncSmm0XTQwDwi0= -github.com/aws/aws-sdk-go-v2/service/s3 v1.66.1/go.mod h1:cB6oAuus7YXRZhWCc1wIwPywwZ1XwweNp2TVAEGYeB8= -github.com/aws/aws-sdk-go-v2/service/sso v1.24.2 h1:bSYXVyUzoTHoKalBmwaZxs97HU9DWWI3ehHSAMa7xOk= -github.com/aws/aws-sdk-go-v2/service/sso v1.24.2/go.mod h1:skMqY7JElusiOUjMJMOv1jJsP7YUg7DrhgqZZWuzu1U= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.2 h1:AhmO1fHINP9vFYUE0LHzCWg/LfUWUF+zFPEcY9QXb7o= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.2/go.mod h1:o8aQygT2+MVP0NaV6kbdE1YnnIM8RRVQzoeUH45GOdI= -github.com/aws/aws-sdk-go-v2/service/sts v1.32.2 h1:CiS7i0+FUe+/YY1GvIBLLrR/XNGZ4CtM1Ll0XavNuVo= -github.com/aws/aws-sdk-go-v2/service/sts v1.32.2/go.mod h1:HtaiBI8CjYoNVde8arShXb94UbQQi9L4EMr6D+xGBwo= +github.com/aws/aws-sdk-go-v2/service/s3 v1.66.2 h1:p9TNFL8bFUMd+38YIpTAXpoxyz0MxC7FlbFEH4P4E1U= +github.com/aws/aws-sdk-go-v2/service/s3 v1.66.2/go.mod h1:fNjyo0Coen9QTwQLWeV6WO2Nytwiu+cCcWaTdKCAqqE= +github.com/aws/aws-sdk-go-v2/service/sso v1.24.3 h1:UTpsIf0loCIWEbrqdLb+0RxnTXfWh2vhw4nQmFi4nPc= +github.com/aws/aws-sdk-go-v2/service/sso v1.24.3/go.mod h1:FZ9j3PFHHAR+w0BSEjK955w5YD2UwB/l/H0yAK3MJvI= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.3 h1:2YCmIXv3tmiItw0LlYf6v7gEHebLY45kBEnPezbUKyU= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.3/go.mod h1:u19stRyNPxGhj6dRm+Cdgu6N75qnbW7+QN0q0dsAk58= +github.com/aws/aws-sdk-go-v2/service/sts v1.32.3 h1:wVnQ6tigGsRqSWDEEyH6lSAJ9OyFUsSnbaUWChuSGzs= +github.com/aws/aws-sdk-go-v2/service/sts v1.32.3/go.mod h1:VZa9yTFyj4o10YGsmDO4gbQJUvvhY72fhumT8W4LqsE= github.com/aws/smithy-go v1.22.0 h1:uunKnWlcoL3zO7q+gG2Pk53joueEOsnNB28QdMsmiMM= github.com/aws/smithy-go v1.22.0/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20241009180534-e718692eec62 h1:T5b8GwBFIlqQzAbqTNcyLvzcAvJ09MXrF6zyUlIic8A= @@ -542,8 +542,8 @@ github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/ github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20241009165004-a3522334989c h1:NDovD0SMpBYXlE1zJmS1q55vWB/fUQBcPAqAboZSccA= -github.com/google/pprof v0.0.0-20241009165004-a3522334989c/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= +github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo= +github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= github.com/google/s2a-go v0.1.8 h1:zZDs9gcbt9ZPLV0ndSyQk6Kacx2g/X+SKYovpnz3SMM= github.com/google/s2a-go v0.1.8/go.mod h1:6iNWHTpQ+nfNRN5E00MSdfDwVesa8hhS32PhPO8deJA= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= @@ -789,15 +789,15 @@ github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vv github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= -github.com/onsi/ginkgo/v2 v2.20.2 h1:7NVCeyIWROIAheY21RLS+3j2bb52W0W82tkberYytp4= -github.com/onsi/ginkgo/v2 v2.20.2/go.mod h1:K9gyxPIlb+aIvnZ8bd9Ak+YP18w3APlR+5coaZoE2ag= +github.com/onsi/ginkgo/v2 v2.21.0 h1:7rg/4f3rB88pb5obDgNZrNHrQ4e6WpjonchcpuBRnZM= +github.com/onsi/ginkgo/v2 v2.21.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= -github.com/onsi/gomega v1.34.2 h1:pNCwDkzrsv7MS9kpaQvVb1aVLahQXyJ/Tv5oAZMI3i8= -github.com/onsi/gomega v1.34.2/go.mod h1:v1xfxRgk0KIsG+QOdm7p8UosrOzPYRo60fd3B/1Dukc= +github.com/onsi/gomega v1.35.1 h1:Cwbd75ZBPxFSuZ6T+rN/WCb/gOc6YgFBXLlZLhC7Ds4= +github.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog= github.com/open-component-model/cobra v0.0.0-20230329075350-b1fd876abfb9 h1:b2cJvZ8nWAVvCqvPhUaFl26Wht4nM4mqfl2ksY9lVzU= github.com/open-component-model/cobra v0.0.0-20230329075350-b1fd876abfb9/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= github.com/open-policy-agent/opa v0.68.0 h1:Jl3U2vXRjwk7JrHmS19U3HZO5qxQRinQbJ2eCJYSqJQ= From e5258922ef3a178a0112d7f79d051ec4f6ed01f4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 3 Nov 2024 18:29:54 +0000 Subject: [PATCH 15/58] chore(deps): bump the ci group with 2 updates (#1038) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps the ci group with 2 updates: [thollander/actions-comment-pull-request](https://github.com/thollander/actions-comment-pull-request) and [anchore/sbom-action](https://github.com/anchore/sbom-action). Updates `thollander/actions-comment-pull-request` from 3.0.0 to 3.0.1
Release notes

Sourced from thollander/actions-comment-pull-request's releases.

v3.0.1

What's Changed

Full Changelog: https://github.com/thollander/actions-comment-pull-request/compare/v3.0.0...v3.0.1

Commits
  • 24bffb9 Merge pull request #410 from thollander/chore/release-3.0.1
  • 5fd7012 chore: release 3.0.1
  • a38b001 Merge pull request #409 from thollander/fix/wrong-var-renaming
  • a11fbfe fix: some wrong variables renaming
  • cb13519 Merge pull request #300 from thollander/dependabot/npm_and_yarn/actions/githu...
  • 38af97b chore(deps): bump @​actions/github from 5.1.1 to 6.0.0
  • 301a80e Merge pull request #393 from thollander/dependabot/npm_and_yarn/prettier-3.3.3
  • 64dcac7 chore(deps-dev): bump prettier from 3.2.5 to 3.3.3
  • 0a327d5 Merge pull request #394 from thollander/dependabot/npm_and_yarn/actions/core-...
  • ece12ba Merge pull request #392 from thollander/dependabot/npm_and_yarn/vercel/ncc-0....
  • Additional commits viewable in compare view

Updates `anchore/sbom-action` from 0.17.5 to 0.17.6
Release notes

Sourced from anchore/sbom-action's releases.

v0.17.6

Changes in v0.17.6

Commits

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/mend_scan.yaml | 2 +- .github/workflows/release.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/mend_scan.yaml b/.github/workflows/mend_scan.yaml index 2de6a8063c..3ec6096c24 100644 --- a/.github/workflows/mend_scan.yaml +++ b/.github/workflows/mend_scan.yaml @@ -198,7 +198,7 @@ jobs: - name: Comment Mend Status on PR if: ${{ github.event_name != 'schedule' && steps.pr_exists.outputs.pr_found == 'true' }} - uses: thollander/actions-comment-pull-request@v3.0.0 + uses: thollander/actions-comment-pull-request@v3.0.1 with: message: | ## Mend Scan Summary: :${{ steps.report.outputs.status }}: diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 7d6729a541..f84cd02dcb 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -169,7 +169,7 @@ jobs: cache_name: release-go-cache - name: Setup Syft - uses: anchore/sbom-action/download-syft@1ca97d9028b51809cf6d3c934c3e160716e1b605 # v0.17.5 + uses: anchore/sbom-action/download-syft@251a468eed47e5082b105c3ba6ee500c0e65a764 # v0.17.6 - name: Setup Cosign uses: sigstore/cosign-installer@v3.7.0 From b1ab4c569faf9e9f15aa91bda9f547ff4f5da978 Mon Sep 17 00:00:00 2001 From: "ocmbot[bot]" <125909804+ocmbot[bot]@users.noreply.github.com> Date: Sun, 3 Nov 2024 18:41:40 +0000 Subject: [PATCH 16/58] chore: update 'flake.nix' (#1039) Update OCM CLI vendor hash (see: .github/workflows/flake_vendorhash.yaml) Co-authored-by: ocmbot[bot] <125909804+ocmbot[bot]@users.noreply.github.com> --- flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index 1f5be3cd20..8199b80c9c 100644 --- a/flake.nix +++ b/flake.nix @@ -35,7 +35,7 @@ state = if (self ? rev) then "clean" else "dirty"; # This vendorHash represents a derivative of all go.mod dependencies and needs to be adjusted with every change - vendorHash = "sha256-MvQl2/jaIIjrz9e9L8NbzDW+Ozgx8XI9XI1jFFulRWs="; + vendorHash = "sha256-dYEotkFKbJuUdlPee9tZTZttpcy/YAXX3VQSnkewy2I="; src = ./.; From e879879c1f6d43d907c8e53729fa915038e8b9d9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Nov 2024 08:51:33 +0000 Subject: [PATCH 17/58] chore(deps): bump github.com/containerd/errdefs from 0.3.0 to 1.0.0 (#1037) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [//]: # (dependabot-start) ⚠️ **Dependabot is rebasing this PR** ⚠️ Rebasing might not happen immediately, so don't worry if this takes some time. Note: if you make any changes to this PR yourself, they will take precedence over the rebase. --- [//]: # (dependabot-end) Bumps [github.com/containerd/errdefs](https://github.com/containerd/errdefs) from 0.3.0 to 1.0.0.
Release notes

Sourced from github.com/containerd/errdefs's releases.

v1.0.0

The first major release of errdefs brings a guarantee of stability with the error types and interface. Additional functions for grpc and http error translation and stacktraces can be found in the separate github.com/containerd/errdefs/pkg module.

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=github.com/containerd/errdefs&package-manager=go_modules&previous-version=0.3.0&new-version=1.0.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 2ba017ab8e..348d27999e 100644 --- a/go.mod +++ b/go.mod @@ -16,7 +16,7 @@ require ( github.com/aws/aws-sdk-go-v2/service/s3 v1.66.2 github.com/cloudflare/cfssl v1.6.5 github.com/containerd/containerd v1.7.23 - github.com/containerd/errdefs v0.3.0 + github.com/containerd/errdefs v1.0.0 github.com/containerd/log v0.1.0 github.com/containers/image/v5 v5.32.2 github.com/cyberphone/json-canonicalization v0.0.0-20231217050601-ba74d44ecf5f diff --git a/go.sum b/go.sum index 6325568d92..ea161dd7a6 100644 --- a/go.sum +++ b/go.sum @@ -284,8 +284,8 @@ github.com/containerd/containerd v1.7.23 h1:H2CClyUkmpKAGlhQp95g2WXHfLYc7whAuvZG github.com/containerd/containerd v1.7.23/go.mod h1:7QUzfURqZWCZV7RLNEn1XjUCQLEf0bkaK4GjUaZehxw= github.com/containerd/continuity v0.4.2 h1:v3y/4Yz5jwnvqPKJJ+7Wf93fyWoCB3F5EclWG023MDM= github.com/containerd/continuity v0.4.2/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ= -github.com/containerd/errdefs v0.3.0 h1:FSZgGOeK4yuT/+DnF07/Olde/q4KBoMsaamhXxIMDp4= -github.com/containerd/errdefs v0.3.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M= +github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI= +github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M= github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A= From 42d65367f68312dec640ebdea61ae347e7f9ddaf Mon Sep 17 00:00:00 2001 From: "ocmbot[bot]" <125909804+ocmbot[bot]@users.noreply.github.com> Date: Mon, 4 Nov 2024 09:02:52 +0000 Subject: [PATCH 18/58] chore: update 'flake.nix' (#1040) Update OCM CLI vendor hash (see: .github/workflows/flake_vendorhash.yaml) Co-authored-by: ocmbot[bot] <125909804+ocmbot[bot]@users.noreply.github.com> --- flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index 8199b80c9c..acacc3b717 100644 --- a/flake.nix +++ b/flake.nix @@ -35,7 +35,7 @@ state = if (self ? rev) then "clean" else "dirty"; # This vendorHash represents a derivative of all go.mod dependencies and needs to be adjusted with every change - vendorHash = "sha256-dYEotkFKbJuUdlPee9tZTZttpcy/YAXX3VQSnkewy2I="; + vendorHash = "sha256-rn2toYSngdWuLWgWLDIykAVz66HljQcS1VK8Fd0fCLc="; src = ./.; From 65d65348f6e00f3ae1dde55d1b8643bfdad26873 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakob=20M=C3=B6ller?= Date: Mon, 4 Nov 2024 13:01:00 +0100 Subject: [PATCH 19/58] chore(ci): various optimizations for build processing, caching and concurrency (#996) Our caches are getting too big: ``` Approaching total cache storage limit (58.09 GB of 10 GB Used) ``` On top we dont make use of makes inbuilt parallelism (`-j`) and also we do not make use of shells forking mechanism for concurrent execution (`&` execution chain followed by `wait`) #### What this PR does / why we need it Limits the cache save to only the main branch in the build step, all other branches/PRs and Jobs will reuse that cache instead of computing their own What does this mean: PRO: - only one cache that should roundabout have 4 (build files for all platforms) + 2 (build+test files for unit tests on amd64) Gi of modules and builds that get updated on every commit to main - The build cache is likely unaffected or largely still valid for most if not every PR. This leads to compile time improvements upwards of 600% depending on PR size without killing our cache usage. CON: - a rebuild or dependency changes will be able to "invalidate" that cache and could lead to longer build times faster. However in general, most builds should still perform the same. If the go.mod / go.sum is not touched, the build cache will be restored for all files except the ones touched or impacted by the PR. #### Which issue(s) this PR fixes fix #999 #1000 --------- Co-authored-by: Hilmar Falkenberg --- .../workflows/blackduck_scan_scheduled.yaml | 18 ++++++ .github/workflows/buildcomponents.yaml | 8 +-- .github/workflows/check_diff_action.yaml | 13 ++-- .github/workflows/codeql.yml | 56 +++++++++++----- .github/workflows/components.yaml | 64 +++++++++++++------ .github/workflows/lint_and_test.yaml | 48 +++++++++++--- .github/workflows/publish-latest.yaml | 26 ++++++-- .github/workflows/release-drafter.yaml | 13 ++-- .github/workflows/release.yaml | 13 ++-- .github/workflows/releasenotes.yaml | 13 ++-- Makefile | 44 +++++++++---- components/demoplugin/Makefile | 27 +++++--- components/ecrplugin/Makefile | 28 +++++--- components/helmdemo/Makefile | 34 +++++++--- components/helminstaller/Dockerfile | 4 +- components/helminstaller/Makefile | 42 +++++++++--- components/ocmcli/Makefile | 30 ++++++--- components/subchartsdemo/Makefile | 25 ++++++-- 18 files changed, 369 insertions(+), 137 deletions(-) diff --git a/.github/workflows/blackduck_scan_scheduled.yaml b/.github/workflows/blackduck_scan_scheduled.yaml index 2dbff357dd..4b2146e628 100644 --- a/.github/workflows/blackduck_scan_scheduled.yaml +++ b/.github/workflows/blackduck_scan_scheduled.yaml @@ -23,6 +23,24 @@ jobs: uses: actions/setup-go@v5 with: go-version-file: '${{ github.workspace }}/go.mod' + cache: false + + # This step will only reuse the go mod and build cache from main made during the Build, + # see push_ocm.yaml => "ocm-cli-latest" Job + # This means it never caches by itself and PRs cannot cause cache pollution / thrashing + # This is because we have huge storage requirements for our cache because of the mass of dependencies + - name: Restore / Reuse Cache from central build + id: cache-golang-restore + uses: actions/cache/restore@v4 # Only Restore, not build another cache (too big) + with: + path: | + ${{ env.go_cache }} + ${{ env.go_modcache }} + key: ${{ env.cache_name }}-${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}-${{ hashFiles('**/go.mod') }} + restore-keys: | + ${{ env.cache_name }}-${{ runner.os }}-go- + env: + cache_name: ocm-cli-latest-go-cache # needs to be the same key in the end as in the build step - name: Blackduck Full Scan uses: mercedesbenzio/detect-action@v2 diff --git a/.github/workflows/buildcomponents.yaml b/.github/workflows/buildcomponents.yaml index d86805b513..49807661ea 100644 --- a/.github/workflows/buildcomponents.yaml +++ b/.github/workflows/buildcomponents.yaml @@ -36,16 +36,14 @@ jobs: echo "go_modcache=$(go env GOMODCACHE)" >> $GITHUB_ENV - name: Set up cache # https://github.com/actions/setup-go/issues/358 - cache is not working with setup-go for multiple jobs - uses: actions/cache@v4 + uses: actions/cache/restore@v4 with: path: | ${{ env.go_cache }} ${{ env.go_modcache }} - key: ${{ env.cache_name }}-${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}-${{ hashFiles('**/go.mod') }} - restore-keys: | - ${{ env.cache_name }}-${{ runner.os }}-go- + key: ${{ env.cache_name }}-${{ runner.os }}-go- env: - cache_name: buildcomponents-go-cache + cache_name: ocm-cli-latest-go-cache # needs to be the same key in the end as in the build step - name: Push OCM Components if: inputs.ocm_push == true diff --git a/.github/workflows/check_diff_action.yaml b/.github/workflows/check_diff_action.yaml index d3439e427c..30cfeeb60b 100644 --- a/.github/workflows/check_diff_action.yaml +++ b/.github/workflows/check_diff_action.yaml @@ -21,9 +21,14 @@ jobs: run: | echo "go_cache=$(go env GOCACHE)" >> $GITHUB_ENV echo "go_modcache=$(go env GOMODCACHE)" >> $GITHUB_ENV - - name: Set up cache - # https://github.com/actions/setup-go/issues/358 - cache is not working with setup-go for multiple jobs - uses: actions/cache@v4 + + # This step will only reuse the go mod and build cache from main made during the Build, + # see lint_and_test.yaml => "test" Job + # This means it never caches by itself and PRs cannot cause cache pollution / thrashing + # This is because we have huge storage requirements for our cache because of the mass of dependencies + - name: Restore / Reuse Cache from central build + id: cache-golang-restore + uses: actions/cache/restore@v4 # Only Restore, not build another cache (too big) with: path: | ${{ env.go_cache }} @@ -32,7 +37,7 @@ jobs: restore-keys: | ${{ env.cache_name }}-${{ runner.os }}-go- env: - cache_name: diff-check-go-cache + cache_name: run-tests-go-cache # needs to be the same key in the end as in the build step - name: Make generate and deepcopy run: | diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 0e1964b0cd..7f05fae76d 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -27,7 +27,8 @@ jobs: # - https://gh.io/supported-runners-and-hardware-resources # - https://gh.io/using-larger-runners (GitHub.com only) # Consider using larger runners or machines with greater resources for possible analysis time improvements. - runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }} + # - ADDENDUM: We moved this to a larger runner for faster analysis + runs-on: large_runner timeout-minutes: ${{ (matrix.language == 'swift' && 120) || 360 }} permissions: # required for all workflows @@ -45,7 +46,7 @@ jobs: matrix: include: - language: go - build-mode: autobuild + build-mode: manual # CodeQL supports the following values keywords for 'language': 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift' # Use `c-cpp` to analyze code written in C, C++ or both # Use 'java-kotlin' to analyze code written in Java, Kotlin or both @@ -61,7 +62,39 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 - # Initializes the CodeQL tools for scanning. + + - name: Setup Go + uses: actions/setup-go@v5 + if: matrix.build-mode == 'manual' + with: + go-version-file: '${{ github.workspace }}/go.mod' + cache: false + + - name: Get go environment for use with cache + if: matrix.build-mode == 'manual' + run: | + echo "go_cache=$(go env GOCACHE)" >> $GITHUB_ENV + echo "go_modcache=$(go env GOMODCACHE)" >> $GITHUB_ENV + + # This step will only reuse the go mod and build cache from main made during the Build, + # see push_ocm.yaml => "ocm-cli-latest" Job + # This means it never caches by itself and PRs cannot cause cache pollution / thrashing + # This is because we have huge storage requirements for our cache because of the mass of dependencies + - name: Restore / Reuse Cache from central build + if: matrix.build-mode == 'manual' + id: cache-golang-restore + uses: actions/cache/restore@v4 # Only Restore, not build another cache (too big) + with: + path: | + ${{ env.go_cache }} + ${{ env.go_modcache }} + key: ${{ env.cache_name }}-${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}-${{ hashFiles('**/go.mod') }} + restore-keys: | + ${{ env.cache_name }}-${{ runner.os }}-go- + env: + cache_name: ocm-cli-latest-go-cache # needs to be the same key in the end as in the build step + + # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL uses: github/codeql-action/init@v3 with: @@ -74,20 +107,9 @@ jobs: # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs # queries: security-extended,security-and-quality - # If the analyze step fails for one of the languages you are analyzing with - # "We were unable to automatically build your code", modify the matrix above - # to set the build mode to "manual" for that language. Then modify this step - # to build your code. - # ℹ️ Command-line programs to run using the OS shell. - # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun - - if: matrix.build-mode == 'manual' - run: | - echo 'If you are using a "manual" build mode for one or more of the' \ - 'languages you are analyzing, replace this with the commands to build' \ - 'your code, for example:' - echo ' make bootstrap' - echo ' make release' - exit 1 + - name: Build + if: matrix.build-mode == 'manual' + run: make build -j - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v3 diff --git a/.github/workflows/components.yaml b/.github/workflows/components.yaml index 88958fc9ed..dee82afeb0 100644 --- a/.github/workflows/components.yaml +++ b/.github/workflows/components.yaml @@ -28,9 +28,13 @@ jobs: run: | echo "go_cache=$(go env GOCACHE)" >> $GITHUB_ENV echo "go_modcache=$(go env GOMODCACHE)" >> $GITHUB_ENV - - name: Set up cache - # https://github.com/actions/setup-go/issues/358 - cache is not working with setup-go for multiple jobs - uses: actions/cache@v4 + # This step will only reuse the go mod and build cache from main made during the Build, + # see push_ocm.yaml => "ocm-cli-latest" Job + # This means it never caches by itself and PRs cannot cause cache pollution / thrashing + # This is because we have huge storage requirements for our cache because of the mass of dependencies + - name: Restore / Reuse Cache from central build + id: cache-golang-restore + uses: actions/cache/restore@v4 # Only Restore, not build another cache (too big) with: path: | ${{ env.go_cache }} @@ -39,7 +43,7 @@ jobs: restore-keys: | ${{ env.cache_name }}-${{ runner.os }}-go- env: - cache_name: cli-go-cache + cache_name: ocm-cli-latest-go-cache # needs to be the same key in the end as in the build step - name: CTF run: | @@ -62,9 +66,14 @@ jobs: run: | echo "go_cache=$(go env GOCACHE)" >> $GITHUB_ENV echo "go_modcache=$(go env GOMODCACHE)" >> $GITHUB_ENV - - name: Set up cache - # https://github.com/actions/setup-go/issues/358 - cache is not working with setup-go for multiple jobs - uses: actions/cache@v4 + + # This step will only reuse the go mod and build cache from main made during the Build, + # see push_ocm.yaml => "ocm-cli-latest" Job + # This means it never caches by itself and PRs cannot cause cache pollution / thrashing + # This is because we have huge storage requirements for our cache because of the mass of dependencies + - name: Restore / Reuse Cache from central build + id: cache-golang-restore + uses: actions/cache/restore@v4 # Only Restore, not build another cache (too big) with: path: | ${{ env.go_cache }} @@ -73,7 +82,7 @@ jobs: restore-keys: | ${{ env.cache_name }}-${{ runner.os }}-go- env: - cache_name: helminstaller-go-cache + cache_name: ocm-cli-latest-go-cache # needs to be the same key in the end as in the build step - name: CTF run: | @@ -96,9 +105,14 @@ jobs: run: | echo "go_cache=$(go env GOCACHE)" >> $GITHUB_ENV echo "go_modcache=$(go env GOMODCACHE)" >> $GITHUB_ENV - - name: Set up cache - # https://github.com/actions/setup-go/issues/358 - cache is not working with setup-go for multiple jobs - uses: actions/cache@v4 + + # This step will only reuse the go mod and build cache from main made during the Build, + # see push_ocm.yaml => "ocm-cli-latest" Job + # This means it never caches by itself and PRs cannot cause cache pollution / thrashing + # This is because we have huge storage requirements for our cache because of the mass of dependencies + - name: Restore / Reuse Cache from central build + id: cache-golang-restore + uses: actions/cache/restore@v4 # Only Restore, not build another cache (too big) with: path: | ${{ env.go_cache }} @@ -107,7 +121,7 @@ jobs: restore-keys: | ${{ env.cache_name }}-${{ runner.os }}-go- env: - cache_name: helmdemo-go-cache + cache_name: ocm-cli-latest-go-cache # needs to be the same key in the end as in the build step - name: CTF run: | @@ -130,9 +144,14 @@ jobs: run: | echo "go_cache=$(go env GOCACHE)" >> $GITHUB_ENV echo "go_modcache=$(go env GOMODCACHE)" >> $GITHUB_ENV - - name: Set up cache - # https://github.com/actions/setup-go/issues/358 - cache is not working with setup-go for multiple jobs - uses: actions/cache@v4 + + # This step will only reuse the go mod and build cache from main made during the Build, + # see push_ocm.yaml => "ocm-cli-latest" Job + # This means it never caches by itself and PRs cannot cause cache pollution / thrashing + # This is because we have huge storage requirements for our cache because of the mass of dependencies + - name: Restore / Reuse Cache from central build + id: cache-golang-restore + uses: actions/cache/restore@v4 # Only Restore, not build another cache (too big) with: path: | ${{ env.go_cache }} @@ -141,7 +160,7 @@ jobs: restore-keys: | ${{ env.cache_name }}-${{ runner.os }}-go- env: - cache_name: helm-subchart-go-cache + cache_name: ocm-cli-latest-go-cache # needs to be the same key in the end as in the build step - name: CTF run: | @@ -167,9 +186,14 @@ jobs: run: | echo "go_cache=$(go env GOCACHE)" >> $GITHUB_ENV echo "go_modcache=$(go env GOMODCACHE)" >> $GITHUB_ENV - - name: Set up cache - # https://github.com/actions/setup-go/issues/358 - cache is not working with setup-go for multiple jobs - uses: actions/cache@v4 + + # This step will only reuse the go mod and build cache from main made during the Build, + # see push_ocm.yaml => "ocm-cli-latest" Job + # This means it never caches by itself and PRs cannot cause cache pollution / thrashing + # This is because we have huge storage requirements for our cache because of the mass of dependencies + - name: Restore / Reuse Cache from central build + id: cache-golang-restore + uses: actions/cache/restore@v4 # Only Restore, not build another cache (too big) with: path: | ${{ env.go_cache }} @@ -178,7 +202,7 @@ jobs: restore-keys: | ${{ env.cache_name }}-${{ runner.os }}-go- env: - cache_name: ecr-plugin-go-cache + cache_name: ocm-cli-latest-go-cache # needs to be the same key in the end as in the build step - name: CTF run: | diff --git a/.github/workflows/lint_and_test.yaml b/.github/workflows/lint_and_test.yaml index a728855768..20bfddb4a1 100644 --- a/.github/workflows/lint_and_test.yaml +++ b/.github/workflows/lint_and_test.yaml @@ -30,9 +30,17 @@ jobs: run: | echo "go_cache=$(go env GOCACHE)" >> $GITHUB_ENV echo "go_modcache=$(go env GOMODCACHE)" >> $GITHUB_ENV - - name: Set up cache - # https://github.com/actions/setup-go/issues/358 - cache is not working with setup-go for multiple jobs - uses: actions/cache@v4 + + # This step will only reuse the go mod and build cache from main made during the Build, + # see lint_and_test.yaml => "test" Job + # This means it never caches by itself and PRs cannot cause cache pollution / thrashing + # This is because we have huge storage requirements for our cache because of the mass of dependencies + # + # NOTE: This is different from our regular build cache (which contains all archs and is built in a different job) + # This is because it requires caching of test dependencies, which are compiled only for linux-amd64 for test runs in CI. + - name: Restore / Reuse Cache from central build + id: cache-golang-restore + uses: actions/cache/restore@v4 # Only Restore, not build another cache (too big) with: path: | ${{ env.go_cache }} @@ -41,10 +49,27 @@ jobs: restore-keys: | ${{ env.cache_name }}-${{ runner.os }}-go- env: - cache_name: run-tests-go-cache + cache_name: run-tests-go-cache # needs to be the same key in the end as in the build step + - name: Build + run: make build -j - name: Test - run: make build install-requirements test + run: make install-requirements test + + # NOTE: This is different from our regular build cache (which contains all archs and is built in a different job) + # This is because it requires caching of test dependencies, which are compiled only for linux-amd64 for test runs in CI. + - name: Save Cache of Build (only on main) + id: cache-golang-save + if: github.ref == 'refs/heads/main' # Only run on main, never in PR + uses: actions/cache/save@v4 # Only saves cache build-test (linux-amd64) + with: + path: | + ${{ env.go_cache }} + ${{ env.go_modcache }} + key: ${{ env.cache_name }}-${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}-${{ hashFiles('**/go.mod') }} + upload-chunk-size: 256000000 # default of 32MB is not really optimal for our large cache, choose 256MB instead + env: + cache_name: run-tests-go-cache # needs to be the same key in the end as in the build step go-lint: name: Lint Golang @@ -64,9 +89,14 @@ jobs: run: | echo "go_cache=$(go env GOCACHE)" >> $GITHUB_ENV echo "go_modcache=$(go env GOMODCACHE)" >> $GITHUB_ENV - - name: Set up cache - # https://github.com/actions/setup-go/issues/358 - cache is not working with setup-go for multiple jobs - uses: actions/cache@v4 + + # This step will only reuse the go mod and build cache from main made during the Build, + # see push_ocm.yaml => "ocm-cli-latest" Job + # This means it never caches by itself and PRs cannot cause cache pollution / thrashing + # This is because we have huge storage requirements for our cache because of the mass of dependencies + - name: Restore / Reuse Cache from central build + id: cache-golang-restore + uses: actions/cache/restore@v4 # Only Restore, not build another cache (too big) with: path: | ${{ env.go_cache }} @@ -75,7 +105,7 @@ jobs: restore-keys: | ${{ env.cache_name }}-${{ runner.os }}-go- env: - cache_name: golint-go-cache + cache_name: ocm-cli-latest-go-cache # needs to be the same key in the end as in the build step - name: Install goimports run: go install golang.org/x/tools/cmd/goimports@latest diff --git a/.github/workflows/publish-latest.yaml b/.github/workflows/publish-latest.yaml index 7d2ee728b2..9d60f1dd52 100644 --- a/.github/workflows/publish-latest.yaml +++ b/.github/workflows/publish-latest.yaml @@ -108,9 +108,14 @@ jobs: run: | echo "go_cache=$(go env GOCACHE)" >> $GITHUB_ENV echo "go_modcache=$(go env GOMODCACHE)" >> $GITHUB_ENV - - name: Set up cache - # https://github.com/actions/setup-go/issues/358 - cache is not working with setup-go for multiple jobs - uses: actions/cache@v4 + + # This step will only reuse the go mod and build cache from main made during the Build, + # see push_ocm.yaml => "ocm-cli-latest" Job + # This means it never caches by itself and PRs cannot cause cache pollution / thrashing + # This is because we have huge storage requirements for our cache because of the mass of dependencies + - name: Restore / Reuse Cache from central build + id: cache-golang-restore + uses: actions/cache/restore@v4 # Only Restore, not build another cache (too big) with: path: | ${{ env.go_cache }} @@ -119,7 +124,7 @@ jobs: restore-keys: | ${{ env.cache_name }}-${{ runner.os }}-go- env: - cache_name: ocm-cli-latest-go-cache + cache_name: ocm-cli-latest-go-cache # needs to be the same key in the end as in the build step - name: Goreleaser release snapshot uses: goreleaser/goreleaser-action@v6 @@ -149,3 +154,16 @@ jobs: skipIfReleaseExists: false body: | holds always the latest ocm-cli binaries + + # This step is actually responsible for populating our build cache for the next runs in PRs or on main. + - name: Save Cache of Build (only on main) + id: cache-golang-save + uses: actions/cache/save@v4 # Only save build cache once + with: + path: | + ${{ env.go_cache }} + ${{ env.go_modcache }} + key: ${{ env.cache_name }}-${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}-${{ hashFiles('**/go.mod') }} + upload-chunk-size: 256000000 # default of 32MB is not really optimal for our large cache, choose 256MB instead + env: + cache_name: ocm-cli-latest-go-cache # needs to be the same key in the end as in the build step \ No newline at end of file diff --git a/.github/workflows/release-drafter.yaml b/.github/workflows/release-drafter.yaml index efa4b7c86c..59e819bed0 100644 --- a/.github/workflows/release-drafter.yaml +++ b/.github/workflows/release-drafter.yaml @@ -29,9 +29,14 @@ jobs: run: | echo "go_cache=$(go env GOCACHE)" >> $GITHUB_ENV echo "go_modcache=$(go env GOMODCACHE)" >> $GITHUB_ENV - - name: Set up cache - # https://github.com/actions/setup-go/issues/358 - cache is not working with setup-go for multiple jobs - uses: actions/cache@v4 + + # This step will only reuse the go mod and build cache from main made during the Build, + # see push_ocm.yaml => "ocm-cli-latest" Job + # This means it never caches by itself and PRs cannot cause cache pollution / thrashing + # This is because we have huge storage requirements for our cache because of the mass of dependencies + - name: Restore / Reuse Cache from central build + id: cache-golang-restore + uses: actions/cache/restore@v4 # Only Restore, not build another cache (too big) with: path: | ${{ env.go_cache }} @@ -40,7 +45,7 @@ jobs: restore-keys: | ${{ env.cache_name }}-${{ runner.os }}-go- env: - cache_name: release-draft-go-cache + cache_name: ocm-cli-latest-go-cache # needs to be the same key in the end as in the build step - name: Set Version run: | diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index f84cd02dcb..d881b1aee4 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -155,9 +155,14 @@ jobs: run: | echo "go_cache=$(go env GOCACHE)" >> $GITHUB_ENV echo "go_modcache=$(go env GOMODCACHE)" >> $GITHUB_ENV - - name: Set up cache - # https://github.com/actions/setup-go/issues/358 - cache is not working with setup-go for multiple jobs - uses: actions/cache@v4 + + # This step will only reuse the go mod and build cache from main made during the Build, + # see push_ocm.yaml => "ocm-cli-latest" Job + # This means it never caches by itself and PRs cannot cause cache pollution / thrashing + # This is because we have huge storage requirements for our cache because of the mass of dependencies + - name: Restore / Reuse Cache from central build + id: cache-golang-restore + uses: actions/cache/restore@v4 # Only Restore, not build another cache (too big) with: path: | ${{ env.go_cache }} @@ -166,7 +171,7 @@ jobs: restore-keys: | ${{ env.cache_name }}-${{ runner.os }}-go- env: - cache_name: release-go-cache + cache_name: ocm-cli-latest-go-cache # needs to be the same key in the end as in the build step - name: Setup Syft uses: anchore/sbom-action/download-syft@251a468eed47e5082b105c3ba6ee500c0e65a764 # v0.17.6 diff --git a/.github/workflows/releasenotes.yaml b/.github/workflows/releasenotes.yaml index 9988dd047c..bec485b73f 100644 --- a/.github/workflows/releasenotes.yaml +++ b/.github/workflows/releasenotes.yaml @@ -27,9 +27,14 @@ jobs: run: | echo "go_cache=$(go env GOCACHE)" >> $GITHUB_ENV echo "go_modcache=$(go env GOMODCACHE)" >> $GITHUB_ENV - - name: Set up cache - # https://github.com/actions/setup-go/issues/358 - cache is not working with setup-go for multiple jobs - uses: actions/cache@v4 + + # This step will only reuse the go mod and build cache from main made during the Build, + # see push_ocm.yaml => "ocm-cli-latest" Job + # This means it never caches by itself and PRs cannot cause cache pollution / thrashing + # This is because we have huge storage requirements for our cache because of the mass of dependencies + - name: Restore / Reuse Cache from central build + id: cache-golang-restore + uses: actions/cache/restore@v4 # Only Restore, not build another cache (too big) with: path: | ${{ env.go_cache }} @@ -38,7 +43,7 @@ jobs: restore-keys: | ${{ env.cache_name }}-${{ runner.os }}-go- env: - cache_name: releasenotes-go-cache + cache_name: ocm-cli-latest-go-cache # needs to be the same key in the end as in the build step - name: Setup git config run: | diff --git a/Makefile b/Makefile index b7ca8a681b..de950abc41 100644 --- a/Makefile +++ b/Makefile @@ -27,26 +27,44 @@ BUILD_FLAGS := "-s -w \ -X ocm.software/ocm/api/version.gitTreeState=$(GIT_TREE_STATE) \ -X ocm.software/ocm/api/version.gitCommit=$(COMMIT) \ -X ocm.software/ocm/api/version.buildDate=$(NOW)" +CGO_ENABLED := 0 COMPONENTS ?= ocmcli helminstaller demoplugin ecrplugin helmdemo subchartsdemo -.PHONY: build -build: ${SOURCES} +.PHONY: build bin +build: bin bin/ocm bin/helminstaller bin/demo bin/cliplugin bin/ecrplugin + +bin: mkdir -p bin + +bin/ocm: bin ${SOURCES} + CGO_ENABLED=$(CGO_ENABLED) go build -ldflags $(BUILD_FLAGS) -o bin/ocm ./cmds/ocm + +bin/helminstaller: bin ${SOURCES} + CGO_ENABLED=$(CGO_ENABLED) go build -ldflags $(BUILD_FLAGS) -o bin/helminstaller ./cmds/helminstaller + +bin/demo: bin ${SOURCES} + CGO_ENABLED=$(CGO_ENABLED) go build -ldflags $(BUILD_FLAGS) -o bin/demo ./cmds/demoplugin + +bin/cliplugin: bin ${SOURCES} + CGO_ENABLED=$(CGO_ENABLED) go build -ldflags $(BUILD_FLAGS) -o bin/cliplugin ./cmds/cliplugin + +bin/ecrplugin: bin ${SOURCES} + CGO_ENABLED=$(CGO_ENABLED) go build -ldflags $(BUILD_FLAGS) -o bin/ecrplugin ./cmds/ecrplugin + +api: ${SOURCES} go build ./api/... + +examples: ${SOURCES} go build ./examples/... - CGO_ENABLED=0 go build -ldflags $(BUILD_FLAGS) -o bin/ocm ./cmds/ocm - CGO_ENABLED=0 go build -ldflags $(BUILD_FLAGS) -o bin/helminstaller ./cmds/helminstaller - CGO_ENABLED=0 go build -ldflags $(BUILD_FLAGS) -o bin/demo ./cmds/demoplugin - CGO_ENABLED=0 go build -ldflags $(BUILD_FLAGS) -o bin/cliplugin ./cmds/cliplugin - CGO_ENABLED=0 go build -ldflags $(BUILD_FLAGS) -o bin/ecrplugin ./cmds/ecrplugin build-platforms: $(GEN)/.exists $(SOURCES) @for i in $(PLATFORMS); do \ echo GOARCH=$$(basename $$i) GOOS=$$(dirname $$i); \ - GOARCH=$$(basename $$i) GOOS=$$(dirname $$i) CGO_ENABLED=0 go build ./cmds/ocm ./cmds/helminstaller ./cmds/ecrplugin; \ - done + GOARCH=$$(basename $$i) GOOS=$$(dirname $$i) CGO_ENABLED=$(CGO_ENABLED) go build ./cmds/ocm ./cmds/helminstaller ./cmds/ecrplugin & \ + done; \ + wait .PHONY: install-requirements install-requirements: @@ -72,18 +90,18 @@ check-and-fix: .PHONY: force-test force-test: - @go test --count=1 $(EFFECTIVE_DIRECTORIES) + @go test -vet=off --count=1 $(EFFECTIVE_DIRECTORIES) -TESTFLAGS = --tags=integration +TESTFLAGS = -vet=off --tags=integration .PHONY: test test: @echo "> Run Tests" - go test $(TESTFLAGS) $(EFFECTIVE_DIRECTORIES) + go test $(TESTFLAGS) $(EFFECTIVE_DIRECTORIES) .PHONY: unit-test unit-test: @echo "> Run Unit Tests" - @go test $(EFFECTIVE_DIRECTORIES) + @go test -vet=off $(EFFECTIVE_DIRECTORIES) .PHONY: generate generate: diff --git a/components/demoplugin/Makefile b/components/demoplugin/Makefile index b10d4e36d3..14ae276201 100644 --- a/components/demoplugin/Makefile +++ b/components/demoplugin/Makefile @@ -15,7 +15,16 @@ CMDSRCS=$(shell find $(REPO_ROOT)/cmds/$(NAME) -type f) OCMSRCS=$(shell find $(REPO_ROOT)/pkg -type f) $(REPO_ROOT)/go.* CREDS ?= -OCM = go run $(REPO_ROOT)/cmds/ocm $(CREDS) +# Define the path to the binary +OCM_BIN = $(REPO_ROOT)/bin/ocm + +# Rule to build the binary if it doesn't exist or if the source code has changed +$(OCM_BIN): $(REPO_ROOT)/cmds/ocm/main.go + mkdir -p $(REPO_ROOT)/bin + go build -ldflags $(BUILD_FLAGS) -o $(OCM_BIN) $(REPO_ROOT)/cmds/ocm + +# Use the binary for the OCM command +OCM = $(OCM_BIN) $(CREDS) GEN = $(REPO_ROOT)/gen/$(NAME) @@ -34,15 +43,15 @@ $(GEN)/build: $(CMDSRCS) $(OCMSRCS) @for i in $(PLATFORMS); do \ tag=$$(echo $$i | sed -e s:/:-:g); \ echo GOARCH=$$(basename $$i) GOOS=$$(dirname $$i) CGO_ENABLED=0 go build -ldflags $(BUILD_FLAGS) -o $(GEN)/$(NAME).$$tag ../../cmds/$(NAME); \ - GOARCH=$$(basename $$i) GOOS=$$(dirname $$i) CGO_ENABLED=0 go build -ldflags $(BUILD_FLAGS) -o $(GEN)/$(NAME).$$tag ../../cmds/$(NAME); \ - done + GOARCH=$$(basename $$i) GOOS=$$(dirname $$i) CGO_ENABLED=0 go build -ldflags $(BUILD_FLAGS) -o $(GEN)/$(NAME).$$tag ../../cmds/$(NAME) & \ + done; \ + wait @touch $(GEN)/build - .PHONY: ctf ctf: $(GEN)/ctf -$(GEN)/ctf: $(GEN)/ca.done +$(GEN)/ctf: $(GEN)/ca.done $(OCM_BIN) @rm -rf "$(GEN)/ctf" $(OCM) transfer ca $(GEN)/ca $(GEN)/ctf touch "$(GEN)/ctf" @@ -54,7 +63,7 @@ version: .PHONY: ca ca: $(GEN)/ca.done -$(GEN)/ca.done: $(GEN)/.exists $(GEN)/build resources.yaml $(CHARTSRCS) +$(GEN)/ca.done: $(GEN)/.exists $(GEN)/build resources.yaml $(CHARTSRCS) $(OCM_BIN) $(OCM) create ca -f $(COMPONENT) "$(VERSION)" --provider $(PROVIDER) --file $(GEN)/ca $(OCM) add resources --templater=spiff --file $(GEN)/ca NAME="$(NAME)" VERSION="$(VERSION)" COMMIT="$(COMMIT)" GEN="$(GEN)" PLATFORMS="$(PLATFORMS)" resources.yaml @touch $(GEN)/ca.done @@ -62,17 +71,17 @@ $(GEN)/ca.done: $(GEN)/.exists $(GEN)/build resources.yaml $(CHARTSRCS) .PHONY: push push: $(GEN)/ctf $(GEN)/push.$(NAME) -$(GEN)/push.$(NAME): $(GEN)/ctf +$(GEN)/push.$(NAME): $(GEN)/ctf $(OCM_BIN) $(OCM) transfer ctf -f $(GEN)/ctf $(OCMREPO) @touch $(GEN)/push.$(NAME) .PHONY: plain-push -plain-push: $(GEN) +plain-push: $(GEN) $(OCM_BIN) $(OCM) transfer ctf -f $(GEN)/ctf $(OCMREPO) @touch $(GEN)/push.$(NAME) .PHONY: transport -transport: +transport: $(OCM_BIN) ifneq ($(TARGETREPO),) $(OCM) transfer component -Vc $(OCMREPO)//$(COMPONENT):$(VERSION) $(TARGETREPO) endif diff --git a/components/ecrplugin/Makefile b/components/ecrplugin/Makefile index 3f037f8f21..2034ac669e 100644 --- a/components/ecrplugin/Makefile +++ b/components/ecrplugin/Makefile @@ -16,7 +16,16 @@ CMDSRCS=$(shell find $(REPO_ROOT)/cmds/$(NAME) -type f) OCMSRCS=$(shell find $(REPO_ROOT)/pkg -type f) $(REPO_ROOT)/go.* CREDS ?= -OCM = go run $(REPO_ROOT)/cmds/ocm $(CREDS) +# Define the path to the binary +OCM_BIN = $(REPO_ROOT)/bin/ocm + +# Rule to build the binary if it doesn't exist or if the source code has changed +$(OCM_BIN): $(REPO_ROOT)/cmds/ocm/main.go + mkdir -p $(REPO_ROOT)/bin + go build -ldflags $(BUILD_FLAGS) -o $(OCM_BIN) $(REPO_ROOT)/cmds/ocm + +# Use the binary for the OCM command +OCM = $(OCM_BIN) $(CREDS) GEN = $(REPO_ROOT)/gen/$(NAME) @@ -35,15 +44,16 @@ $(GEN)/build: $(CMDSRCS) $(OCMSRCS) @for i in $(PLATFORMS); do \ tag=$$(echo $$i | sed -e s:/:-:g); \ echo GOARCH=$$(basename $$i) GOOS=$$(dirname $$i) CGO_ENABLED=0 go build -ldflags $(BUILD_FLAGS) -o $(GEN)/$(NAME).$$tag ../../cmds/$(NAME); \ - GOARCH=$$(basename $$i) GOOS=$$(dirname $$i) CGO_ENABLED=0 go build -ldflags $(BUILD_FLAGS) -o $(GEN)/$(NAME).$$tag ../../cmds/$(NAME); \ - done + GOARCH=$$(basename $$i) GOOS=$$(dirname $$i) CGO_ENABLED=0 go build -ldflags $(BUILD_FLAGS) -o $(GEN)/$(NAME).$$tag ../../cmds/$(NAME) & \ + done; \ + wait @touch $(GEN)/build .PHONY: ctf ctf: $(GEN)/ctf -$(GEN)/ctf: $(GEN)/ca.done +$(GEN)/ctf: $(GEN)/ca.done $(OCM_BIN) @rm -rf "$(GEN)/ctf" $(OCM) transfer ca $(GEN)/ca $(GEN)/ctf touch "$(GEN)/ctf" @@ -55,30 +65,30 @@ version: .PHONY: ca ca: $(GEN)/ca.done -$(GEN)/ca.done: $(GEN)/.exists $(GEN)/build resources.yaml $(CHARTSRCS) +$(GEN)/ca.done: $(GEN)/.exists $(GEN)/build resources.yaml $(CHARTSRCS) $(OCM_BIN) $(OCM) create ca -f $(COMPONENT) "$(VERSION)" --provider $(PROVIDER) --file $(GEN)/ca $(OCM) add resources --templater=spiff --file $(GEN)/ca NAME="$(NAME)" VERSION="$(VERSION)" COMMIT="$(COMMIT)" GEN="$(GEN)" PLATFORMS="$(PLATFORMS)" resources.yaml @touch $(GEN)/ca.done .PHONY: plain-ca -plain-ca: $(GEN)/.exists resources.yaml $(CHARTSRCS) +plain-ca: $(GEN)/.exists resources.yaml $(CHARTSRCS) $(OCM_BIN) $(OCM) create ca -f $(COMPONENT) "$(VERSION)" --provider $(PROVIDER) --file $(GEN)/ca $(OCM) add resources --templater=spiff --file $(GEN)/ca NAME="$(NAME)" VERSION="$(VERSION)" COMMIT="$(COMMIT)" GEN="$(GEN)" PLATFORMS="$(PLATFORMS)" resources.yaml .PHONY: push push: $(GEN)/ctf $(GEN)/push.$(NAME) -$(GEN)/push.$(NAME): $(GEN)/ctf +$(GEN)/push.$(NAME): $(GEN)/ctf $(OCM_BIN) $(OCM) transfer ctf -f $(GEN)/ctf $(OCMREPO) @touch $(GEN)/push.$(NAME) .PHONY: plain-push -plain-push: $(GEN) +plain-push: $(GEN) $(OCM_BIN) $(OCM) transfer ctf -f $(GEN)/ctf $(OCMREPO) @touch $(GEN)/push.$(NAME) .PHONY: transport -transport: +transport: $(OCM_BIN) ifneq ($(TARGETREPO),) $(OCM) transfer component -Vc $(OCMREPO)//$(COMPONENT):$(VERSION) $(TARGETREPO) endif diff --git a/components/helmdemo/Makefile b/components/helmdemo/Makefile index 6268331544..12d858db1f 100644 --- a/components/helmdemo/Makefile +++ b/components/helmdemo/Makefile @@ -13,16 +13,32 @@ EFFECTIVE_VERSION = $(VERSION)-$(COMMIT) HELMINSTVERSION ?= $(VERSION) CREDS ?= -OCM = go run $(REPO_ROOT)/cmds/ocm $(CREDS) +# Define the path to the binary +OCM_BIN = $(REPO_ROOT)/bin/ocm + +# Rule to build the binary if it doesn't exist or if the source code has changed +$(OCM_BIN): $(REPO_ROOT)/cmds/ocm/main.go + mkdir -p $(REPO_ROOT)/bin + go build -ldflags $(BUILD_FLAGS) -o $(OCM_BIN) $(REPO_ROOT)/cmds/ocm + +# Use the binary for the OCM command +OCM = $(OCM_BIN) $(CREDS) GEN := $(REPO_ROOT)/gen/$(NAME) +NOW := $(shell date -u +%FT%T%z) +BUILD_FLAGS := "-s -w \ + -X ocm.software/ocm/api/version.gitVersion=$(EFFECTIVE_VERSION) \ + -X ocm.software/ocm/api/version.gitTreeState=$(GIT_TREE_STATE) \ + -X ocm.software/ocm/api/version.gitCommit=$(COMMIT) \ + -X ocm.software/ocm/api/version.buildDate=$(NOW)" + CHARTSRCS=$(shell find echoserver -type f) .PHONY: ctf ctf: $(GEN)/ctf -$(GEN)/ctf: $(GEN)/ca +$(GEN)/ctf: $(GEN)/ca $(OCM_BIN) @rm -rf $(GEN)/ctf $(OCM) -X keeplocalblob=true transfer ca $(GEN)/ca $(GEN)/ctf touch $(GEN)/ctf @@ -34,7 +50,7 @@ version: .PHONY: ca ca: $(GEN)/ca -$(GEN)/ca: $(GEN)/.exists sources.yaml resources.yaml references.yaml $(CHARTSRCS) packagespec.yaml examples/* helmconfig.yaml +$(GEN)/ca: $(GEN)/.exists sources.yaml resources.yaml references.yaml $(CHARTSRCS) packagespec.yaml examples/* helmconfig.yaml $(OCM_BIN) $(OCM) create ca -f $(COMPONENT) "$(VERSION)" --provider $(PROVIDER) --file $(GEN)/ca $(OCM) add sources $(GEN)/ca VERSION="$(VERSION)" COMMIT="$(COMMIT)" sources.yaml $(OCM) add resources $(GEN)/ca VERSION="$(VERSION)" COMMIT="$(COMMIT)" resources.yaml @@ -42,23 +58,23 @@ $(GEN)/ca: $(GEN)/.exists sources.yaml resources.yaml references.yaml $(CHARTSRC @touch $(GEN)/ca .PHONY: eval-resources -eval-resources: +eval-resources: $(OCM_BIN) $(OCM) add resources --dry-run VERSION="$(VERSION)" COMMIT="$(COMMIT)" resources.yaml -O "$(GEN)/resources.yaml" .PHONY: push push: $(GEN)/ctf $(GEN)/push.$(NAME) -$(GEN)/push.$(NAME): $(GEN)/ctf +$(GEN)/push.$(NAME): $(GEN)/ctf $(OCM_BIN) $(OCM) -X keeplocalblob=true transfer ctf -f $(GEN)/ctf $(OCMREPO) @touch $(GEN)/push.$(NAME) .PHONY: plain-push -plain-push: $(GEN) +plain-push: $(GEN) $(OCM_BIN) $(OCM) -X keeplocalblob=true transfer ctf -f $(GEN)/ctf $(OCMREPO) @touch $(GEN)/push.$(NAME) .PHONY: transport -transport: +transport: $(OCM_BIN) ifneq ($(TARGETREPO),) $(OCM) -X keeplocalblob=true transfer component -Vc $(OCMREPO)//$(COMPONENT):$(VERSION) $(TARGETREPO) endif @@ -76,11 +92,11 @@ info: @echo "version for helminstaller: $(HELMINSTVERSION)" .PHONY: describe -describe: $(GEN)/ctf +describe: $(GEN)/ctf $(OCM_BIN) $(OCM) get resources --lookup $(OCMREPO) -r -o treewide $(GEN)/ctf .PHONY: descriptor -descriptor: $(GEN)/ctf +descriptor: $(GEN)/ctf $(OCM_BIN) $(OCM) get component -S v3alpha1 -o yaml $(GEN)/ctf .PHONY: clean diff --git a/components/helminstaller/Dockerfile b/components/helminstaller/Dockerfile index 008f78d481..f0d8aa97e4 100644 --- a/components/helminstaller/Dockerfile +++ b/components/helminstaller/Dockerfile @@ -8,8 +8,8 @@ COPY api api COPY cmds cmds COPY hack/generate-docs hack/generate-docs #COPY go/api api -RUN --mount=type=cache,target=/root/.cache/go-build go get -d ./... -RUN --mount=type=cache,target=/root/.cache/go-build CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH \ +RUN go get -d ./... +RUN CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH \ go build -o /main -ldflags "-s -w \ -X ocm.software/ocm/api/version.gitVersion=$EFFECTIVE_VERSION \ -X ocm.software/ocm/api/version.gitTreeState=$GIT_TREE_STATE \ diff --git a/components/helminstaller/Makefile b/components/helminstaller/Makefile index ccc438c2f1..24513b618c 100644 --- a/components/helminstaller/Makefile +++ b/components/helminstaller/Makefile @@ -13,12 +13,30 @@ COMMIT := $(shell git rev-parse --verify EFFECTIVE_VERSION := $(VERSION)-$(COMMIT) GIT_TREE_STATE := $(shell [ -z "$$(git status --porcelain 2>/dev/null)" ] && echo clean || echo dirty) PLATFORM := $(shell go env GOOS)/$(shell go env GOARCH) +CACHE_DIR := $(shell go env GOCACHE) +MOD_CACHE_DIR := $(shell go env GOMODCACHE) CREDS ?= -OCM = go run $(REPO_ROOT)/cmds/ocm $(CREDS) +# Define the path to the binary +OCM_BIN = $(REPO_ROOT)/bin/ocm + +# Rule to build the binary if it doesn't exist or if the source code has changed +$(OCM_BIN): $(REPO_ROOT)/cmds/ocm/main.go + mkdir -p $(REPO_ROOT)/bin + go build -ldflags $(BUILD_FLAGS) -o $(OCM_BIN) $(REPO_ROOT)/cmds/ocm + +# Use the binary for the OCM command +OCM = $(OCM_BIN) $(CREDS) GEN = $(REPO_ROOT)/gen/$(NAME) +NOW := $(shell date -u +%FT%T%z) +BUILD_FLAGS := "-s -w \ + -X ocm.software/ocm/api/version.gitVersion=$(EFFECTIVE_VERSION) \ + -X ocm.software/ocm/api/version.gitTreeState=$(GIT_TREE_STATE) \ + -X ocm.software/ocm/api/version.gitCommit=$(COMMIT) \ + -X ocm.software/ocm/api/version.buildDate=$(NOW)" + CMDSRCS=$(shell find $(REPO_ROOT)/cmds/$(NAME) -type f) OCMSRCS=$(shell find $(REPO_ROOT)/pkg -type f) $(REPO_ROOT)/go.* @@ -31,13 +49,13 @@ endif .PHONY: ctf ctf: $(GEN)/ctf -$(GEN)/ctf: $(GEN)/ca +$(GEN)/ctf: $(GEN)/ca $(OCM_BIN) @rm -rf "$(GEN)/ctf" $(OCM) transfer ca $(GEN)/ca $(GEN)/ctf touch $(GEN)/ctf .PHONY: plain-ctf -plain-ctf: +plain-ctf: $(OCM_BIN) $(OCM) transfer ca $(GEN)/ca $(GEN)/ctf touch $(GEN)/ctf @@ -48,20 +66,20 @@ version: .PHONY: ca ca: $(GEN)/ca -$(GEN)/ca: $(GEN)/.exists $(GEN)/image.$(NAME)$(FLAGSUF) resources.yaml executorspec.yaml +$(GEN)/ca: $(GEN)/.exists $(GEN)/image.$(NAME)$(FLAGSUF) resources.yaml executorspec.yaml $(OCM_BIN) $(OCM) create ca -f $(COMPONENT) "$(VERSION)" --provider $(PROVIDER) --file $(GEN)/ca $(OCM) add resources --templater spiff $(GEN)/ca $(ATTRIBUTES) resources.yaml @touch $(GEN)/ca .PHONY: plain-ca -plain-ca: $(GEN)/.exists +plain-ca: $(GEN)/.exists $(OCM_BIN) $(OCM) create ca -f $(COMPONENT) "$(VERSION)" --provider $(PROVIDER) --file $(GEN)/ca $(OCM) add resources --templater spiff $(GEN)/ca $(ATTRIBUTES) resources.yaml @touch $(GEN)/ca .PHONY: eval-resources -eval-resources: +eval-resources: $(OCM_BIN) $(OCM) add resources --dry-run --templater spiff $(ATTRIBUTES) resources.yaml .PHONY: build @@ -70,8 +88,10 @@ build: $(GEN)/image.$(NAME)$(FLAGSUF) $(GEN)/image.$(NAME): $(GEN)/.exists Dockerfile $(CMDSRCS) $(OCMSRCS) docker buildx build -t $(IMAGE):$(VERSION) --platform $(PLATFORM) --file Dockerfile $(REPO_ROOT) \ --build-arg COMMIT=$(COMMIT) \ + --build-arg CACHE_DIR=$(CACHE_DIR) \ + --build-arg MOD_CACHE_DIR=$(MOD_CACHE_DIR) \ --build-arg EFFECTIVE_VERSION=$(EFFECTIVE_VERSION) \ - --build-arg GIT_TREE_STATE=$(GIT_TREE_STATE) + --build-arg GIT_TREE_STATE=$(GIT_TREE_STATE); \ @touch $(GEN)/image.$(NAME) push-image: @@ -87,6 +107,8 @@ $(GEN)/image.$(NAME).multi: $(GEN)/.exists Dockerfile $(CMDSRCS) $(OCMSRCS) echo building platform $$i; \ docker buildx build --load -t $(IMAGE):$(VERSION)-$$tag --platform $$i --file Dockerfile $(REPO_ROOT) \ --build-arg COMMIT=$(COMMIT) \ + --build-arg CACHE_DIR=$(CACHE_DIR) \ + --build-arg MOD_CACHE_DIR=$(MOD_CACHE_DIR) \ --build-arg EFFECTIVE_VERSION=$(EFFECTIVE_VERSION) \ --build-arg GIT_TREE_STATE=$(GIT_TREE_STATE); \ done @@ -95,17 +117,17 @@ $(GEN)/image.$(NAME).multi: $(GEN)/.exists Dockerfile $(CMDSRCS) $(OCMSRCS) .PHONY: push push: $(GEN)/ctf $(GEN)/push.$(NAME) -$(GEN)/push.$(NAME): $(GEN)/ctf +$(GEN)/push.$(NAME): $(GEN)/ctf $(OCM_BIN) $(OCM) transfer ctf -f $(GEN)/ctf $(OCMREPO) @touch $(GEN)/push.$(NAME) .PHONY: plain-push -plain-push: $(GEN)/.exists +plain-push: $(GEN)/.exists $(OCM_BIN) $(OCM) transfer ctf -f $(GEN)/ctf $(OCMREPO) @touch $(GEN)/push.$(NAME) .PHONY: transport -transport: +transport: $(OCM_BIN) ifneq ($(TARGETREPO),) $(OCM) transfer component -Vr $(OCMREPO)//$(COMPONENT):$(VERSION) $(TARGETREPO) endif diff --git a/components/ocmcli/Makefile b/components/ocmcli/Makefile index 66979a20bc..418712ca37 100644 --- a/components/ocmcli/Makefile +++ b/components/ocmcli/Makefile @@ -27,7 +27,16 @@ FLAGSUF = .multi endif CREDS ?= -OCM = go run $(REPO_ROOT)/cmds/ocm $(CREDS) +# Define the path to the binary +OCM_BIN = $(REPO_ROOT)/bin/ocm + +# Rule to build the binary if it doesn't exist or if the source code has changed +$(OCM_BIN): $(REPO_ROOT)/cmds/ocm/main.go + mkdir -p $(REPO_ROOT)/bin + go build -ldflags $(BUILD_FLAGS) -o $(OCM_BIN) $(REPO_ROOT)/cmds/ocm + +# Use the binary for the OCM command +OCM = $(OCM_BIN) $(CREDS) GEN = $(REPO_ROOT)/gen/$(shell basename $(realpath .)) @@ -45,10 +54,11 @@ build: $(GEN)/build $(GEN)/build: $(GEN)/.exists $(CMDSRCS) $(OCMSRCS) @for i in $(PLATFORMS); do \ - tag=$$(echo $$i | sed -e s:/:-:g); \ - echo GOARCH=$$(basename $$i) GOOS=$$(dirname $$i) CGO_ENABLED=0 go build -ldflags $(BUILD_FLAGS) -o $(GEN)/$(NAME).$$tag ../../cmds/$(CMD); \ - GOARCH=$$(basename $$i) GOOS=$$(dirname $$i) CGO_ENABLED=0 go build -ldflags $(BUILD_FLAGS) -o $(GEN)/$(NAME).$$tag ../../cmds/$(CMD); \ - done + tag=$$(echo $$i | sed -e s:/:-:g); \ + echo GOARCH=$$(basename $$i) GOOS=$$(dirname $$i) CGO_ENABLED=0 go build -ldflags $(BUILD_FLAGS) -o $(GEN)/$(NAME).$$tag ../../cmds/$(CMD); \ + GOARCH=$$(basename $$i) GOOS=$$(dirname $$i) CGO_ENABLED=0 go build -ldflags $(BUILD_FLAGS) -o $(GEN)/$(NAME).$$tag ../../cmds/$(CMD) & \ + done; \ + wait @touch $(GEN)/build .PHONY: image @@ -89,7 +99,7 @@ $(GEN)/image.multi: Dockerfile $(GEN)/build .PHONY: ctf ctf: $(GEN)/ctf -$(GEN)/ctf: $(GEN)/ca.done +$(GEN)/ctf: $(GEN)/ca.done $(OCM_BIN) @rm -rf "$(GEN)/ctf" $(OCM) transfer ca $(GEN)/ca $(GEN)/ctf touch $(GEN)/ctf @@ -101,7 +111,7 @@ version: .PHONY: ca ca: $(GEN)/ca.done -$(GEN)/ca.done: $(GEN)/.exists $(GEN)/build $(GEN)/image$(FLAGSUF) resources.yaml $(CHARTSRCS) Makefile +$(GEN)/ca.done: $(GEN)/.exists $(GEN)/build $(GEN)/image$(FLAGSUF) resources.yaml $(CHARTSRCS) Makefile $(OCM_BIN) $(OCM) create ca -f $(COMPONENT) "$(VERSION)" --provider $(PROVIDER) --file $(GEN)/ca $(OCM) add resources --templater=spiff --file $(GEN)/ca $(ATTRIBUTES) resources.yaml $(OCM) add sources $(GEN)/ca VERSION="$(VERSION)" COMMIT="$(COMMIT)" sources.yaml @@ -110,17 +120,17 @@ $(GEN)/ca.done: $(GEN)/.exists $(GEN)/build $(GEN)/image$(FLAGSUF) resources.yam .PHONY: push push: $(GEN)/ctf $(GEN)/push.$(NAME) -$(GEN)/push.$(NAME): $(GEN)/ctf +$(GEN)/push.$(NAME): $(GEN)/ctf $(OCM_BIN) $(OCM) transfer ctf -f $(GEN)/ctf $(OCMREPO) @touch $(GEN)/push.$(NAME) .PHONY: plain-push -plain-push: $(GEN) +plain-push: $(GEN) $(OCM_BIN) $(OCM) transfer ctf -f $(GEN)/ctf $(OCMREPO) @touch $(GEN)/push.$(NAME) .PHONY: transport -transport: +transport: $(OCM_BIN) ifneq ($(TARGETREPO),) $(OCM) transfer component -Vc $(OCMREPO)//$(COMPONENT):$(VERSION) $(TARGETREPO) endif diff --git a/components/subchartsdemo/Makefile b/components/subchartsdemo/Makefile index 67a3af7da6..3987b361e1 100644 --- a/components/subchartsdemo/Makefile +++ b/components/subchartsdemo/Makefile @@ -12,13 +12,30 @@ PODINFO_VERSION = 6.3.5 PODINFO_CHART_VERSION = 6.3.5 REPO_ROOT := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))/../.. +GIT_TREE_STATE = $(shell [ -z "$$(git status --porcelain 2>/dev/null)" ] && echo clean || echo dirty) VERSION = $(shell go run $(REPO_ROOT)/api/version/generate/release_generate.go print-rc-version $(CANDIDATE)) COMMIT = $(shell git rev-parse HEAD) EFFECTIVE_VERSION = $(VERSION)-$(COMMIT) HELMINSTVERSION ?= $(VERSION) CREDS ?= -OCM = go run $(REPO_ROOT)/cmds/ocm $(CREDS) +# Define the path to the binary +OCM_BIN = $(REPO_ROOT)/bin/ocm + +# Rule to build the binary if it doesn't exist or if the source code has changed +$(OCM_BIN): $(REPO_ROOT)/cmds/ocm/main.go + mkdir -p $(REPO_ROOT)/bin + go build -ldflags $(BUILD_FLAGS) -o $(OCM_BIN) $(REPO_ROOT)/cmds/ocm + +# Use the binary for the OCM command +OCM = $(OCM_BIN) $(CREDS) + +NOW := $(shell date -u +%FT%T%z) +BUILD_FLAGS := "-s -w \ + -X ocm.software/ocm/api/version.gitVersion=$(EFFECTIVE_VERSION) \ + -X ocm.software/ocm/api/version.gitTreeState=$(GIT_TREE_STATE) \ + -X ocm.software/ocm/api/version.gitCommit=$(COMMIT) \ + -X ocm.software/ocm/api/version.buildDate=$(NOW)" GEN = $(REPO_ROOT)/gen/subchartsdemo @@ -31,7 +48,7 @@ ctf: $(GEN)/ctf version: @echo $(VERSION) -$(GEN)/ctf: $(GEN)/.exists component-constructor.yaml $(ECHOCHARTSRCS) packagespec.yaml podinfo/podinfo-$(PODINFO_CHART_VERSION).tgz +$(GEN)/ctf: $(GEN)/.exists component-constructor.yaml $(ECHOCHARTSRCS) packagespec.yaml podinfo/podinfo-$(PODINFO_CHART_VERSION).tgz $(OCM_BIN) @rm -rf $(GEN)/ctf $(OCM) add componentversions --create VERSION="$(VERSION)" COMMIT="$(COMMIT)" COMPONENT_PREFIX=$(COMPONENT_PREFIX) PROVIDER=$(PROVIDER) PODINFO_VERSION=$(PODINFO_VERSION) PODINFO_CHART_VERSION=$(PODINFO_CHART_VERSION) HELMINSTCOMP=$(HELMINSTCOMP) HELMINSTVERSION=$(HELMINSTVERSION) ECHO_VERSION=$(ECHO_VERSION) ECHO_CHART_VERSION=$(ECHO_CHART_VERSION) --file $(GEN)/ctf component-constructor.yaml @touch $(GEN)/ctf @@ -39,12 +56,12 @@ $(GEN)/ctf: $(GEN)/.exists component-constructor.yaml $(ECHOCHARTSRCS) packagesp .PHONY: push push: $(GEN)/ctf $(GEN)/push.$(NAME) -$(GEN)/push.$(NAME): $(GEN)/ctf +$(GEN)/push.$(NAME): $(GEN)/ctf $(OCM_BIN) $(OCM) -X keeplocalblob=true transfer ctf --copy-resources -f $(GEN)/ctf $(OCMREPO) @touch $(GEN)/push.$(NAME) .PHONY: plain-push -plain-push: $(GEN) +plain-push: $(GEN) $(OCM_BIN) $(OCM) -X keeplocalblob=true transfer ctf --copy-resources -f $(GEN)/ctf $(OCMREPO) @touch $(GEN)/push.$(NAME) From 18704891c40273c332be63297ad33fd8c0af0900 Mon Sep 17 00:00:00 2001 From: Uwe Krueger Date: Mon, 4 Nov 2024 14:25:39 +0100 Subject: [PATCH 20/58] add action doc (#1032) #### What this PR does / why we need it Add documentation to command `ocm execute action`. #### Which issue(s) this PR fixes --- api/datacontext/action/api/registry.go | 8 ++++++ api/datacontext/action/api/utils.go | 25 +++++++++++++++++++ .../commands/misccmds/action/execute/cmd.go | 7 ++++-- docs/reference/ocm_execute_action.md | 18 ++++++++++++- 4 files changed, 55 insertions(+), 3 deletions(-) diff --git a/api/datacontext/action/api/registry.go b/api/datacontext/action/api/registry.go index bf2ceee6df..24049f3401 100644 --- a/api/datacontext/action/api/registry.go +++ b/api/datacontext/action/api/registry.go @@ -5,6 +5,7 @@ import ( "sync" "github.com/mandelsoft/goutils/errors" + "github.com/mandelsoft/goutils/maputils" "golang.org/x/exp/slices" "ocm.software/ocm/api/utils" @@ -26,6 +27,7 @@ type ActionTypeRegistry interface { DecodeActionResult(data []byte, unmarshaler runtime.Unmarshaler) (ActionResult, error) EncodeActionResult(spec ActionResult, marshaler runtime.Marshaler) ([]byte, error) + GetActionNames() []string GetAction(name string) Action SupportedActionVersions(name string) []string @@ -161,6 +163,12 @@ func (r *actionRegistry) RegisterActionType(typ ActionType) error { return nil } +func (r *actionRegistry) GetActionNames() []string { + r.lock.Lock() + defer r.lock.Unlock() + return maputils.OrderedKeys(r.actions) +} + func (r *actionRegistry) GetAction(name string) Action { r.lock.Lock() defer r.lock.Unlock() diff --git a/api/datacontext/action/api/utils.go b/api/datacontext/action/api/utils.go index 52535f92f8..a6602c45f9 100644 --- a/api/datacontext/action/api/utils.go +++ b/api/datacontext/action/api/utils.go @@ -1,6 +1,8 @@ package api import ( + "ocm.software/ocm/api/utils" + common "ocm.software/ocm/api/utils/misc" "ocm.software/ocm/api/utils/runtime" ) @@ -36,3 +38,26 @@ func (a *actionType) SpecificationType() ActionSpecType { func (a *actionType) ResultType() ActionResultType { return a.restype } + +func Usage(reg ActionTypeRegistry) string { + p, buf := common.NewBufferedPrinter() + for _, n := range reg.GetActionNames() { + a := reg.GetAction(n) + p.Printf("- Name: %s\n", n) + if a.Description() != "" { + p.Printf("%s\n", utils.IndentLines(a.Description(), " ")) + } + if a.Usage() != "" { + p.Printf("\n%s\n", utils.IndentLines(a.Usage(), " ")) + } + p := p.AddGap(" ") + + if len(a.ConsumerAttributes()) > 0 { + p.Printf("Possible Consumer Attributes:\n") + for _, a := range a.ConsumerAttributes() { + p.Printf("- %s\n", a) + } + } + } + return buf.String() +} diff --git a/cmds/ocm/commands/misccmds/action/execute/cmd.go b/cmds/ocm/commands/misccmds/action/execute/cmd.go index b669e2c73f..a781ed6511 100644 --- a/cmds/ocm/commands/misccmds/action/execute/cmd.go +++ b/cmds/ocm/commands/misccmds/action/execute/cmd.go @@ -11,6 +11,7 @@ import ( clictx "ocm.software/ocm/api/cli" "ocm.software/ocm/api/credentials" "ocm.software/ocm/api/datacontext/action" + "ocm.software/ocm/api/datacontext/action/api" utils2 "ocm.software/ocm/api/utils" common "ocm.software/ocm/api/utils/misc" "ocm.software/ocm/api/utils/out" @@ -54,11 +55,13 @@ func (o *Command) ForName(name string) *cobra.Command { Args: cobra.MinimumNArgs(1), Long: ` Execute an action extension for a given action specification. The specification -show be a JSON or YAML argument. +should be a JSON or YAML argument. Additional properties settings can be used to describe a consumer id to retrieve credentials for. -`, + +The following actions are supported: +` + api.Usage(api.DefaultRegistry()), Example: ` $ ocm execute action '{ "type": "oci.repository.prepare/v1", "hostname": "...", "repository": "..."}' `, diff --git a/docs/reference/ocm_execute_action.md b/docs/reference/ocm_execute_action.md index e051e59a29..0d709936df 100644 --- a/docs/reference/ocm_execute_action.md +++ b/docs/reference/ocm_execute_action.md @@ -18,11 +18,27 @@ ocm execute action [] {=} ### Description Execute an action extension for a given action specification. The specification -show be a JSON or YAML argument. +should be a JSON or YAML argument. Additional properties settings can be used to describe a consumer id to retrieve credentials for. +The following actions are supported: +- Name: oci.repository.prepare + Prepare the usage of a repository in an OCI registry. + + The hostname of the target repository is used as selector. The action should + assure, that the requested repository is available on the target OCI registry. + + Spec version v1 uses the following specification fields: + - hostname *string*: The hostname of the OCI registry. + - repository *string*: The OCI repository name. + + Possible Consumer Attributes: + - hostname + - port + - pathprefix + ### Examples ```bash From 1a0570e5d704cf4a68a46167336378eb8247e895 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakob=20M=C3=B6ller?= Date: Mon, 4 Nov 2024 18:39:58 +0100 Subject: [PATCH 21/58] chore: migrate all component builds: ca => ctf (#1043) #### What this PR does / why we need it part of release work on https://github.com/open-component-model/ocm/issues/995 We want to move away from component archives because we only really need the CTF as single source of truth. This makes the makefiles a little easier to understand and allows us to reuse these commands fairly easily in the next github actions reworks. #### Which issue(s) this PR fixes --- .github/workflows/buildcomponents.yaml | 67 ------------------- .github/workflows/release.yaml | 45 ++----------- Makefile | 16 ++--- components/demoplugin/Makefile | 41 +++++++----- .../demoplugin/component-constructor.yaml | 23 +++++++ components/demoplugin/resources.yaml | 18 ----- components/ecrplugin/Makefile | 46 +++++++------ .../ecrplugin/component-constructor.yaml | 23 +++++++ components/ecrplugin/resources.yaml | 18 ----- components/helmdemo/Makefile | 37 +++++----- .../helmdemo/component-constructor.yaml | 58 ++++++++++++++++ components/helmdemo/references.yaml | 4 -- components/helmdemo/resources.yaml | 43 ------------ components/helmdemo/sources.yaml | 7 -- components/helminstaller/Makefile | 58 +++++++--------- components/helminstaller/a.yaml | 1 - .../helminstaller/component-constructor.yaml | 25 +++++++ components/helminstaller/resources.yaml | 20 ------ components/ocmcli/Makefile | 50 ++++++++------ ...ources.yaml => component-constructor.yaml} | 17 ++++- components/ocmcli/sources.yaml | 7 -- 21 files changed, 280 insertions(+), 344 deletions(-) delete mode 100644 .github/workflows/buildcomponents.yaml create mode 100644 components/demoplugin/component-constructor.yaml delete mode 100644 components/demoplugin/resources.yaml create mode 100644 components/ecrplugin/component-constructor.yaml delete mode 100644 components/ecrplugin/resources.yaml create mode 100644 components/helmdemo/component-constructor.yaml delete mode 100644 components/helmdemo/references.yaml delete mode 100644 components/helmdemo/resources.yaml delete mode 100644 components/helmdemo/sources.yaml delete mode 100644 components/helminstaller/a.yaml create mode 100644 components/helminstaller/component-constructor.yaml delete mode 100644 components/helminstaller/resources.yaml rename components/ocmcli/{resources.yaml => component-constructor.yaml} (63%) delete mode 100644 components/ocmcli/sources.yaml diff --git a/.github/workflows/buildcomponents.yaml b/.github/workflows/buildcomponents.yaml deleted file mode 100644 index 49807661ea..0000000000 --- a/.github/workflows/buildcomponents.yaml +++ /dev/null @@ -1,67 +0,0 @@ -name: BuildComponents - -on: - workflow_dispatch: - inputs: - ocm_push: - type: boolean - description: "Push to OCM Repository" - default: false - -jobs: - components: - name: Trigger component build - runs-on: large_runner - permissions: - contents: write - id-token: write - packages: write - repository-projects: read - steps: - - name: Self Hosted Runner Post Job Cleanup Action - uses: TooMuch4U/actions-clean@v2.2 - - - name: Checkout - uses: actions/checkout@v4 - - - name: Setup Go - uses: actions/setup-go@v5 - with: - go-version-file: '${{ github.workspace }}/go.mod' - cache: false - - - name: Get go environment for use with cache - run: | - echo "go_cache=$(go env GOCACHE)" >> $GITHUB_ENV - echo "go_modcache=$(go env GOMODCACHE)" >> $GITHUB_ENV - - name: Set up cache - # https://github.com/actions/setup-go/issues/358 - cache is not working with setup-go for multiple jobs - uses: actions/cache/restore@v4 - with: - path: | - ${{ env.go_cache }} - ${{ env.go_modcache }} - key: ${{ env.cache_name }}-${{ runner.os }}-go- - env: - cache_name: ocm-cli-latest-go-cache # needs to be the same key in the end as in the build step - - - name: Push OCM Components - if: inputs.ocm_push == true - env: - GITHUBORG: ${{ github.repository_owner }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - make push - - - name: Build OCM Components - if: inputs.ocm_push == false - env: - GITHUBORG: ${{ github.repository_owner }} - run: | - make ctf - - - name: Upload OCM Archive - uses: actions/upload-artifact@v4 - with: - name: ocm.ctf - path: gen/ctf diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index d881b1aee4..5091f797ab 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -33,38 +33,17 @@ jobs: with: fetch-depth: 0 - - name: Job Settings - run: | - echo "Release Job Arguments" - if ${{ github.event.inputs.release_candidate }}; then - v="v$(go run $GITHUB_WORKSPACE/api/version/generate --no-dev print-rc-version ${{ github.event.inputs.prerelease }})" - if [ -n "${{ github.event.inputs.prerelease }}" ]; then - echo "Candidate: $v" - else - echo "Candidate: $v (taken from source)" - fi - else - v="v$(go run $GITHUB_WORKSPACE/api/version/generate print-version)" - echo "Final Release: $v" - if ${{ github.event.inputs.create_branch }}; then - echo "with release branch creation" - else - echo "without release branch creation" - fi - fi - - - name: Set Base Version + - name: Generate Base Version run: | BASE_VERSION=v$(go run $GITHUB_WORKSPACE/api/version/generate print-version) echo "BASE_VERSION=$BASE_VERSION" >> $GITHUB_ENV - - name: Set Pre-Release Version + - name: Generate Pre-Release Version if: inputs.release_candidate == true run: | RELEASE_VERSION=v$(go run $GITHUB_WORKSPACE/api/version/generate --no-dev print-rc-version ${{ github.event.inputs.prerelease }}) echo "RELEASE_VERSION=$RELEASE_VERSION" >> $GITHUB_ENV - - - name: Set Version + - name: Generate Release Version if: inputs.release_candidate == false run: | RELEASE_VERSION=${{env.BASE_VERSION}} @@ -96,13 +75,6 @@ jobs: draft: true releaseName: ${{ env.BASE_VERSION }} - lint-and-test: - name: Lint and Unit Tests - uses: ./.github/workflows/lint_and_test.yaml - needs: check - permissions: - contents: read - pull-requests: read components: name: Component CTF Builds uses: ./.github/workflows/components.yaml @@ -110,13 +82,7 @@ jobs: permissions: contents: read pull-requests: read - diff-check-manifests: - name: Check for diff after go mod tidy and generated targets - uses: ./.github/workflows/check_diff_action.yaml - needs: check - permissions: - contents: read - pull-requests: read + release: needs: @@ -141,6 +107,7 @@ jobs: - name: Checkout uses: actions/checkout@v4 with: + # fetch all history so we can calculate the version and tagging fetch-depth: 0 token: ${{ steps.generate_token.outputs.token }} @@ -188,14 +155,12 @@ jobs: run: | BASE_VERSION=v$(go run $GITHUB_WORKSPACE/api/version/generate print-version) echo "BASE_VERSION=$BASE_VERSION" >> $GITHUB_ENV - - name: Set Pre-Release Version if: inputs.release_candidate == true run: | RELEASE_VERSION=v$(go run $GITHUB_WORKSPACE/api/version/generate --no-dev print-rc-version ${{ github.event.inputs.prerelease }}) echo "RELEASE_VERSION=$RELEASE_VERSION" >> $GITHUB_ENV echo "release name is $RELEASE_VERSION" - - name: Set Version if: inputs.release_candidate == false run: | diff --git a/Makefile b/Makefile index de950abc41..e33fb4c075 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,7 @@ PLATFORMS = windows/amd64 darwin/arm64 darwin/amd64 linux/amd64 linux/arm64 CREDS ?= OCM := go run $(REPO_ROOT)/cmds/ocm $(CREDS) -CTF_TYPE ?= tgz +CTF_TYPE ?= directory GEN := $(REPO_ROOT)/gen @@ -37,25 +37,25 @@ build: bin bin/ocm bin/helminstaller bin/demo bin/cliplugin bin/ecrplugin bin: mkdir -p bin -bin/ocm: bin ${SOURCES} +bin/ocm: bin $(SOURCES) CGO_ENABLED=$(CGO_ENABLED) go build -ldflags $(BUILD_FLAGS) -o bin/ocm ./cmds/ocm -bin/helminstaller: bin ${SOURCES} +bin/helminstaller: bin $(SOURCES) CGO_ENABLED=$(CGO_ENABLED) go build -ldflags $(BUILD_FLAGS) -o bin/helminstaller ./cmds/helminstaller -bin/demo: bin ${SOURCES} +bin/demo: bin $(SOURCES) CGO_ENABLED=$(CGO_ENABLED) go build -ldflags $(BUILD_FLAGS) -o bin/demo ./cmds/demoplugin -bin/cliplugin: bin ${SOURCES} +bin/cliplugin: bin $(SOURCES) CGO_ENABLED=$(CGO_ENABLED) go build -ldflags $(BUILD_FLAGS) -o bin/cliplugin ./cmds/cliplugin -bin/ecrplugin: bin ${SOURCES} +bin/ecrplugin: bin $(SOURCES) CGO_ENABLED=$(CGO_ENABLED) go build -ldflags $(BUILD_FLAGS) -o bin/ecrplugin ./cmds/ecrplugin -api: ${SOURCES} +api: $(SOURCES) go build ./api/... -examples: ${SOURCES} +examples: $(SOURCES) go build ./examples/... diff --git a/components/demoplugin/Makefile b/components/demoplugin/Makefile index 14ae276201..4e1a35502f 100644 --- a/components/demoplugin/Makefile +++ b/components/demoplugin/Makefile @@ -4,6 +4,7 @@ GITHUBORG ?= open-component-model COMPONENT = $(PROVIDER)/plugins/$(NAME) OCMREPO ?= ghcr.io/$(GITHUBORG)/ocm PLATFORMS = linux/amd64 linux/arm64 +CTF_TYPE ?= directory REPO_ROOT := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))/../.. VERSION = $(shell go run ../../api/version/generate/release_generate.go print-rc-version $(CANDIDATE)) @@ -12,7 +13,7 @@ EFFECTIVE_VERSION = $(VERSION)+$(COMMIT) GIT_TREE_STATE := $(shell [ -z "$$(git status --porcelain 2>/dev/null)" ] && echo clean || echo dirty) CMDSRCS=$(shell find $(REPO_ROOT)/cmds/$(NAME) -type f) -OCMSRCS=$(shell find $(REPO_ROOT)/pkg -type f) $(REPO_ROOT)/go.* +OCMSRCS=$(shell find $(REPO_ROOT)/api -type f) $(REPO_ROOT)/go.* CREDS ?= # Define the path to the binary @@ -28,6 +29,9 @@ OCM = $(OCM_BIN) $(CREDS) GEN = $(REPO_ROOT)/gen/$(NAME) + $(GEN): + @mkdir -p $(GEN) + NOW := $(shell date -u +%FT%T%z) BUILD_FLAGS := "-s -w \ -X ocm.software/ocm/api/version.gitVersion=$(EFFECTIVE_VERSION) \ @@ -35,11 +39,10 @@ BUILD_FLAGS := "-s -w \ -X ocm.software/ocm/api/version.gitCommit=$(COMMIT) \ -X ocm.software/ocm/api/version.buildDate=$(NOW)" - .PHONY: build build: $(GEN)/build -$(GEN)/build: $(CMDSRCS) $(OCMSRCS) +$(GEN)/build: $(GEN) $(CMDSRCS) $(OCMSRCS) @for i in $(PLATFORMS); do \ tag=$$(echo $$i | sed -e s:/:-:g); \ echo GOARCH=$$(basename $$i) GOOS=$$(dirname $$i) CGO_ENABLED=0 go build -ldflags $(BUILD_FLAGS) -o $(GEN)/$(NAME).$$tag ../../cmds/$(NAME); \ @@ -51,23 +54,27 @@ $(GEN)/build: $(CMDSRCS) $(OCMSRCS) .PHONY: ctf ctf: $(GEN)/ctf -$(GEN)/ctf: $(GEN)/ca.done $(OCM_BIN) +$(GEN)/ctf: $(OCM_BIN) $(GEN)/.exists $(GEN)/build component-constructor.yaml $(CHARTSRCS) @rm -rf "$(GEN)/ctf" - $(OCM) transfer ca $(GEN)/ca $(GEN)/ctf + $(OCM) add componentversions \ + --create \ + --file $(GEN)/ctf \ + --type $(CTF_TYPE) \ + --templater=spiff \ + COMPONENT="$(COMPONENT)" \ + NAME="$(NAME)" \ + VERSION="$(VERSION)" \ + PROVIDER="$(PROVIDER)" \ + COMMIT="$(COMMIT)" \ + GEN="$(GEN)" \ + PLATFORMS="$(PLATFORMS)" \ + component-constructor.yaml touch "$(GEN)/ctf" .PHONY: version version: @echo $(VERSION) -.PHONY: ca -ca: $(GEN)/ca.done - -$(GEN)/ca.done: $(GEN)/.exists $(GEN)/build resources.yaml $(CHARTSRCS) $(OCM_BIN) - $(OCM) create ca -f $(COMPONENT) "$(VERSION)" --provider $(PROVIDER) --file $(GEN)/ca - $(OCM) add resources --templater=spiff --file $(GEN)/ca NAME="$(NAME)" VERSION="$(VERSION)" COMMIT="$(COMMIT)" GEN="$(GEN)" PLATFORMS="$(PLATFORMS)" resources.yaml - @touch $(GEN)/ca.done - .PHONY: push push: $(GEN)/ctf $(GEN)/push.$(NAME) @@ -97,12 +104,12 @@ info: @echo "COMMIT; $(COMMIT)" .PHONY: describe -describe: $(GEN)/ctf - ocm get resources --lookup $(OCMREPO) -c -o treewide $(GEN)/ctf +describe: $(GEN)/ctf $(OCM_BIN) + $(OCM) get resources --lookup $(OCMREPO) -c -o treewide $(GEN)/ctf .PHONY: descriptor -descriptor: $(GEN)/ctf - ocm get component -S v3alpha1 -o yaml $(GEN)/ctf +descriptor: $(GEN)/ctf $(OCM_BIN) + $(OCM) get component -S v3alpha1 -o yaml $(GEN)/ctf .PHONY: clean clean: diff --git a/components/demoplugin/component-constructor.yaml b/components/demoplugin/component-constructor.yaml new file mode 100644 index 0000000000..253566936f --- /dev/null +++ b/components/demoplugin/component-constructor.yaml @@ -0,0 +1,23 @@ +--- +helper: + <<<: (( &temporary )) + executable: + <<<: (( &template )) + name: demo + type: ocmPlugin + version: (( values.VERSION )) + extraIdentity: + os: ((dirname(p) )) + architecture: (( basename(p) )) + input: + type: file + # Generate the path to the plugin binary by looking into the base path and encoding the platform + path: (( values.GEN "/" values.NAME "." replace(p,"/","-") )) + +components: + - name: (( values.COMPONENT)) + version: (( values.VERSION)) + provider: + name: (( values.PROVIDER)) + # use all platforms and create a resource for each + resources: (( map[split(" ", values.PLATFORMS)|p|-> *helper.executable] )) \ No newline at end of file diff --git a/components/demoplugin/resources.yaml b/components/demoplugin/resources.yaml deleted file mode 100644 index ed51a5f1e9..0000000000 --- a/components/demoplugin/resources.yaml +++ /dev/null @@ -1,18 +0,0 @@ ---- -helper: - <<<: (( &temporary )) - executable: - <<<: (( &template )) - name: demo - type: ocmPlugin - version: (( values.VERSION )) - extraIdentity: - os: ((dirname(p) )) - architecture: (( basename(p) )) - input: - type: file - path: (( values.GEN "/" values.NAME "." replace(p,"/","-") )) - - -resources: (( map[split(" ", values.PLATFORMS)|p|-> *helper.executable] )) - diff --git a/components/ecrplugin/Makefile b/components/ecrplugin/Makefile index 2034ac669e..5a2175c995 100644 --- a/components/ecrplugin/Makefile +++ b/components/ecrplugin/Makefile @@ -4,6 +4,7 @@ GITHUBORG ?= open-component-model COMPONENT = $(PROVIDER)/plugins/$(NAME) OCMREPO ?= ghcr.io/$(GITHUBORG)/ocm PLATFORMS = linux/amd64 linux/arm64 darwin/amd64 darwin/arm64 +CTF_TYPE ?= directory REPO_ROOT := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))/../.. @@ -13,7 +14,7 @@ EFFECTIVE_VERSION = $(VERSION)+$(COMMIT) GIT_TREE_STATE := $(shell [ -z "$$(git status --porcelain 2>/dev/null)" ] && echo clean || echo dirty) CMDSRCS=$(shell find $(REPO_ROOT)/cmds/$(NAME) -type f) -OCMSRCS=$(shell find $(REPO_ROOT)/pkg -type f) $(REPO_ROOT)/go.* +OCMSRCS=$(shell find $(REPO_ROOT)/api -type f) $(REPO_ROOT)/go.* CREDS ?= # Define the path to the binary @@ -29,6 +30,9 @@ OCM = $(OCM_BIN) $(CREDS) GEN = $(REPO_ROOT)/gen/$(NAME) + $(GEN): + @mkdir -p $(GEN) + NOW := $(shell date -u +%FT%T%z) BUILD_FLAGS := "-s -w \ -X ocm.software/ocm/api/version.gitVersion=$(EFFECTIVE_VERSION) \ @@ -36,11 +40,10 @@ BUILD_FLAGS := "-s -w \ -X ocm.software/ocm/api/version.gitCommit=$(COMMIT) \ -X ocm.software/ocm/api/version.buildDate=$(NOW)" - .PHONY: build build: $(GEN)/build -$(GEN)/build: $(CMDSRCS) $(OCMSRCS) +$(GEN)/build: $(GEN) $(CMDSRCS) $(OCMSRCS) @for i in $(PLATFORMS); do \ tag=$$(echo $$i | sed -e s:/:-:g); \ echo GOARCH=$$(basename $$i) GOOS=$$(dirname $$i) CGO_ENABLED=0 go build -ldflags $(BUILD_FLAGS) -o $(GEN)/$(NAME).$$tag ../../cmds/$(NAME); \ @@ -53,28 +56,27 @@ $(GEN)/build: $(CMDSRCS) $(OCMSRCS) .PHONY: ctf ctf: $(GEN)/ctf -$(GEN)/ctf: $(GEN)/ca.done $(OCM_BIN) +$(GEN)/ctf: $(OCM_BIN) $(GEN)/.exists $(GEN)/build component-constructor.yaml $(CHARTSRCS) @rm -rf "$(GEN)/ctf" - $(OCM) transfer ca $(GEN)/ca $(GEN)/ctf + $(OCM) add componentversions \ + --create \ + --file $(GEN)/ctf \ + --type $(CTF_TYPE) \ + --templater=spiff \ + COMPONENT="$(COMPONENT)" \ + NAME="$(NAME)" \ + VERSION="$(VERSION)" \ + PROVIDER="$(PROVIDER)" \ + COMMIT="$(COMMIT)" \ + GEN="$(GEN)" \ + PLATFORMS="$(PLATFORMS)" \ + component-constructor.yaml touch "$(GEN)/ctf" .PHONY: version version: @echo $(VERSION) -.PHONY: ca -ca: $(GEN)/ca.done - -$(GEN)/ca.done: $(GEN)/.exists $(GEN)/build resources.yaml $(CHARTSRCS) $(OCM_BIN) - $(OCM) create ca -f $(COMPONENT) "$(VERSION)" --provider $(PROVIDER) --file $(GEN)/ca - $(OCM) add resources --templater=spiff --file $(GEN)/ca NAME="$(NAME)" VERSION="$(VERSION)" COMMIT="$(COMMIT)" GEN="$(GEN)" PLATFORMS="$(PLATFORMS)" resources.yaml - @touch $(GEN)/ca.done - -.PHONY: plain-ca -plain-ca: $(GEN)/.exists resources.yaml $(CHARTSRCS) $(OCM_BIN) - $(OCM) create ca -f $(COMPONENT) "$(VERSION)" --provider $(PROVIDER) --file $(GEN)/ca - $(OCM) add resources --templater=spiff --file $(GEN)/ca NAME="$(NAME)" VERSION="$(VERSION)" COMMIT="$(COMMIT)" GEN="$(GEN)" PLATFORMS="$(PLATFORMS)" resources.yaml - .PHONY: push push: $(GEN)/ctf $(GEN)/push.$(NAME) @@ -104,12 +106,12 @@ info: @echo "COMMIT; $(COMMIT)" .PHONY: describe -describe: $(GEN)/ctf - ocm get resources --lookup $(OCMREPO) -c -o treewide $(GEN)/ctf +describe: $(GEN)/ctf $(OCM_BIN) + $(OCM) get resources --lookup $(OCMREPO) -c -o treewide $(GEN)/ctf .PHONY: descriptor -descriptor: $(GEN)/ctf - ocm get component -S v3alpha1 -o yaml $(GEN)/ctf +descriptor: $(GEN)/ctf $(OCM_BIN) + $(OCM) get component -S v3alpha1 -o yaml $(GEN)/ctf .PHONY: clean clean: diff --git a/components/ecrplugin/component-constructor.yaml b/components/ecrplugin/component-constructor.yaml new file mode 100644 index 0000000000..253566936f --- /dev/null +++ b/components/ecrplugin/component-constructor.yaml @@ -0,0 +1,23 @@ +--- +helper: + <<<: (( &temporary )) + executable: + <<<: (( &template )) + name: demo + type: ocmPlugin + version: (( values.VERSION )) + extraIdentity: + os: ((dirname(p) )) + architecture: (( basename(p) )) + input: + type: file + # Generate the path to the plugin binary by looking into the base path and encoding the platform + path: (( values.GEN "/" values.NAME "." replace(p,"/","-") )) + +components: + - name: (( values.COMPONENT)) + version: (( values.VERSION)) + provider: + name: (( values.PROVIDER)) + # use all platforms and create a resource for each + resources: (( map[split(" ", values.PLATFORMS)|p|-> *helper.executable] )) \ No newline at end of file diff --git a/components/ecrplugin/resources.yaml b/components/ecrplugin/resources.yaml deleted file mode 100644 index 69e59a7b55..0000000000 --- a/components/ecrplugin/resources.yaml +++ /dev/null @@ -1,18 +0,0 @@ ---- -helper: - <<<: (( &temporary )) - executable: - <<<: (( &template )) - name: (( values.NAME )) - type: ocmPlugin - version: (( values.VERSION )) - extraIdentity: - os: ((dirname(p) )) - architecture: (( basename(p) )) - input: - type: file - path: (( values.GEN "/" values.NAME "." replace(p,"/","-") )) - - -resources: (( map[split(" ", values.PLATFORMS)|p|-> *helper.executable] )) - diff --git a/components/helmdemo/Makefile b/components/helmdemo/Makefile index 12d858db1f..4ceba662ff 100644 --- a/components/helmdemo/Makefile +++ b/components/helmdemo/Makefile @@ -3,6 +3,7 @@ PROVIDER ?= ocm.software GITHUBORG ?= open-component-model COMPONENT = $(PROVIDER)/toi/demo/$(NAME) OCMREPO ?= ghcr.io/$(GITHUBORG)/ocm +CTF_TYPE ?= directory HELMINSTCOMP = $(PROVIDER)/toi/installers/helminstaller @@ -26,6 +27,9 @@ OCM = $(OCM_BIN) $(CREDS) GEN := $(REPO_ROOT)/gen/$(NAME) +$(GEN): + @mkdir -p $(GEN) + NOW := $(shell date -u +%FT%T%z) BUILD_FLAGS := "-s -w \ -X ocm.software/ocm/api/version.gitVersion=$(EFFECTIVE_VERSION) \ @@ -38,29 +42,28 @@ CHARTSRCS=$(shell find echoserver -type f) .PHONY: ctf ctf: $(GEN)/ctf -$(GEN)/ctf: $(GEN)/ca $(OCM_BIN) +$(GEN)/ctf: $(OCM_BIN) $(GEN)/.exists $(CHARTSRCS) $(GEN) component-constructor.yaml packagespec.yaml examples/* helmconfig.yaml @rm -rf $(GEN)/ctf - $(OCM) -X keeplocalblob=true transfer ca $(GEN)/ca $(GEN)/ctf + $(OCM) add componentversions \ + --create \ + --file $(GEN)/ctf \ + --type $(CTF_TYPE) \ + --templater=spiff \ + COMPONENT="$(COMPONENT)" \ + NAME="$(NAME)" \ + VERSION="$(VERSION)" \ + PROVIDER="$(PROVIDER)" \ + COMMIT="$(COMMIT)" \ + GEN="$(GEN)" \ + HELMINSTCOMP=$(HELMINSTCOMP) \ + HELMINSTVERSION=$(HELMINSTVERSION) \ + component-constructor.yaml touch $(GEN)/ctf .PHONY: version version: @echo $(VERSION) -.PHONY: ca -ca: $(GEN)/ca - -$(GEN)/ca: $(GEN)/.exists sources.yaml resources.yaml references.yaml $(CHARTSRCS) packagespec.yaml examples/* helmconfig.yaml $(OCM_BIN) - $(OCM) create ca -f $(COMPONENT) "$(VERSION)" --provider $(PROVIDER) --file $(GEN)/ca - $(OCM) add sources $(GEN)/ca VERSION="$(VERSION)" COMMIT="$(COMMIT)" sources.yaml - $(OCM) add resources $(GEN)/ca VERSION="$(VERSION)" COMMIT="$(COMMIT)" resources.yaml - $(OCM) add references $(GEN)/ca VERSION="$(VERSION)" COMMIT="$(COMMIT)" HELMINSTCOMP=$(HELMINSTCOMP) HELMINSTVERSION=$(HELMINSTVERSION) references.yaml - @touch $(GEN)/ca - -.PHONY: eval-resources -eval-resources: $(OCM_BIN) - $(OCM) add resources --dry-run VERSION="$(VERSION)" COMMIT="$(COMMIT)" resources.yaml -O "$(GEN)/resources.yaml" - .PHONY: push push: $(GEN)/ctf $(GEN)/push.$(NAME) @@ -74,7 +77,7 @@ plain-push: $(GEN) $(OCM_BIN) @touch $(GEN)/push.$(NAME) .PHONY: transport -transport: $(OCM_BIN) +transport: ifneq ($(TARGETREPO),) $(OCM) -X keeplocalblob=true transfer component -Vc $(OCMREPO)//$(COMPONENT):$(VERSION) $(TARGETREPO) endif diff --git a/components/helmdemo/component-constructor.yaml b/components/helmdemo/component-constructor.yaml new file mode 100644 index 0000000000..11f1c78a65 --- /dev/null +++ b/components/helmdemo/component-constructor.yaml @@ -0,0 +1,58 @@ +components: + - name: (( values.COMPONENT)) + version: (( values.VERSION)) + provider: + name: (( values.PROVIDER)) + # use all platforms and create a resource for each +# ADD back once https://github.com/open-component-model/ocm/issues/1041 is fixed + componentReferences: + - name: installer + componentName: (( values.HELMINSTCOMP )) + version: (( values.HELMINSTVERSION )) + sources: + - name: source + type: filesytem + access: + type: github + repoUrl: github.com/open-component-model/ocm + commit: (( values.COMMIT )) + version: (( values.VERSION )) + resources: + - name: creds-example + type: yaml + labels: + - name: commit + value: (( values.COMMIT )) + input: + type: file + mediaType: application/vnd.toi.ocm.software.credentials.v1+yaml + path: examples/creds.yaml + - name: config-example + type: yaml + labels: + - name: commit + value: (( values.COMMIT )) + input: + type: file + mediaType: application/vnd.toi.ocm.software.config.v1+yaml + path: examples/config.yaml + - name: image + type: ociImage + version: "1.0" + access: + type: ociArtifact + imageReference: gcr.io/google-containers/echoserver:1.10 + - name: chart + type: helmChart + input: + type: helm + path: echoserver + - name: package + type: toiPackage + labels: + - name: commit + value: (( values.COMMIT )) + input: + type: spiff + mediaType: application/vnd.toi.ocm.software.package.v1+yaml + path: packagespec.yaml \ No newline at end of file diff --git a/components/helmdemo/references.yaml b/components/helmdemo/references.yaml deleted file mode 100644 index 6c0cf353b5..0000000000 --- a/components/helmdemo/references.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -name: installer -componentName: ${HELMINSTCOMP} -version: ${HELMINSTVERSION} diff --git a/components/helmdemo/resources.yaml b/components/helmdemo/resources.yaml deleted file mode 100644 index cec2758956..0000000000 --- a/components/helmdemo/resources.yaml +++ /dev/null @@ -1,43 +0,0 @@ ---- -name: package -type: toiPackage -labels: - - name: commit - value: ${COMMIT} -input: - type: spiff - mediaType: application/vnd.toi.ocm.software.package.v1+yaml - path: packagespec.yaml ---- -name: chart -type: helmChart -input: - type: helm - path: echoserver ---- -name: image -type: ociImage -version: "1.0" -access: - type: ociArtifact - imageReference: gcr.io/google-containers/echoserver:1.10 ---- -name: config-example -type: yaml -labels: - - name: commit - value: ${COMMIT} -input: - type: file - mediaType: application/vnd.toi.ocm.software.config.v1+yaml - path: examples/config.yaml ---- -name: creds-example -type: yaml -labels: - - name: commit - value: ${COMMIT} -input: - type: file - mediaType: application/vnd.toi.ocm.software.credentials.v1+yaml - path: examples/creds.yaml diff --git a/components/helmdemo/sources.yaml b/components/helmdemo/sources.yaml deleted file mode 100644 index dcc9c5f896..0000000000 --- a/components/helmdemo/sources.yaml +++ /dev/null @@ -1,7 +0,0 @@ -name: source -type: filesytem -access: - type: github - repoUrl: github.com/open-component-model/ocm - commit: ${COMMIT} -version: ${VERSION} diff --git a/components/helminstaller/Makefile b/components/helminstaller/Makefile index 24513b618c..ed3d368daa 100644 --- a/components/helminstaller/Makefile +++ b/components/helminstaller/Makefile @@ -6,6 +6,7 @@ COMPONENT := $(PROVIDER)/toi/installers/$(NAME) OCMREPO ?= ghcr.io/$(GITHUBORG)/ocm MULTI ?= true PLATFORMS ?= linux/amd64 linux/arm64 +CTF_TYPE ?= directory REPO_ROOT := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))/../.. VERSION := $(shell go run ../../api/version/generate/release_generate.go print-rc-version $(CANDIDATE)) @@ -30,6 +31,9 @@ OCM = $(OCM_BIN) $(CREDS) GEN = $(REPO_ROOT)/gen/$(NAME) +$(GEN): + @mkdir -p $(GEN) + NOW := $(shell date -u +%FT%T%z) BUILD_FLAGS := "-s -w \ -X ocm.software/ocm/api/version.gitVersion=$(EFFECTIVE_VERSION) \ @@ -40,8 +44,6 @@ BUILD_FLAGS := "-s -w \ CMDSRCS=$(shell find $(REPO_ROOT)/cmds/$(NAME) -type f) OCMSRCS=$(shell find $(REPO_ROOT)/pkg -type f) $(REPO_ROOT)/go.* -ATTRIBUTES = VERSION="$(VERSION)" COMMIT="$(COMMIT)" IMAGE="$(IMAGE):$(VERSION)" PLATFORMS="$(PLATFORMS)" MULTI=$(MULTI) - ifeq ($(MULTI),true) FLAGSUF = .multi endif @@ -49,39 +51,29 @@ endif .PHONY: ctf ctf: $(GEN)/ctf -$(GEN)/ctf: $(GEN)/ca $(OCM_BIN) +$(GEN)/ctf: $(OCM_BIN) $(GEN)/.exists $(GEN)/image.$(NAME)$(FLAGSUF) component-constructor.yaml executorspec.yaml @rm -rf "$(GEN)/ctf" - $(OCM) transfer ca $(GEN)/ca $(GEN)/ctf - touch $(GEN)/ctf - -.PHONY: plain-ctf -plain-ctf: $(OCM_BIN) - $(OCM) transfer ca $(GEN)/ca $(GEN)/ctf - touch $(GEN)/ctf + $(OCM) add componentversions \ + --create \ + --file $(GEN)/ctf \ + --type $(CTF_TYPE) \ + --templater=spiff \ + COMPONENT="$(COMPONENT)" \ + NAME="$(NAME)" \ + VERSION="$(VERSION)" \ + PROVIDER="$(PROVIDER)" \ + COMMIT="$(COMMIT)" \ + GEN="$(GEN)" \ + PLATFORMS="$(PLATFORMS)" \ + MULTI="$(MULTI)" \ + IMAGE="$(IMAGE):$(VERSION)" \ + component-constructor.yaml + touch "$(GEN)/ctf" .PHONY: version version: @echo $(VERSION) -.PHONY: ca -ca: $(GEN)/ca - -$(GEN)/ca: $(GEN)/.exists $(GEN)/image.$(NAME)$(FLAGSUF) resources.yaml executorspec.yaml $(OCM_BIN) - $(OCM) create ca -f $(COMPONENT) "$(VERSION)" --provider $(PROVIDER) --file $(GEN)/ca - $(OCM) add resources --templater spiff $(GEN)/ca $(ATTRIBUTES) resources.yaml - @touch $(GEN)/ca - - -.PHONY: plain-ca -plain-ca: $(GEN)/.exists $(OCM_BIN) - $(OCM) create ca -f $(COMPONENT) "$(VERSION)" --provider $(PROVIDER) --file $(GEN)/ca - $(OCM) add resources --templater spiff $(GEN)/ca $(ATTRIBUTES) resources.yaml - @touch $(GEN)/ca - -.PHONY: eval-resources -eval-resources: $(OCM_BIN) - $(OCM) add resources --dry-run --templater spiff $(ATTRIBUTES) resources.yaml - .PHONY: build build: $(GEN)/image.$(NAME)$(FLAGSUF) @@ -145,12 +137,12 @@ info: @echo "PATFORM: $(PLATFORM)" .PHONY: describe -describe: $(GEN)/ctf - ocm get resources --lookup $(OCMREPO) -r -o treewide $(GEN)/ctf +describe: $(OCM_BIN) $(GEN)/ctf + $(OCM) get resources --lookup $(OCMREPO) -r -o treewide $(GEN)/ctf .PHONY: descriptor -descriptor: $(GEN)/ctf - ocm get component -S v3alpha1 -o yaml $(GEN)/ctf +descriptor: $(OCM_BIN) $(GEN)/ctf + $(OCM) get component -S v3alpha1 -o yaml $(GEN)/ctf .PHONY: setup setup: diff --git a/components/helminstaller/a.yaml b/components/helminstaller/a.yaml deleted file mode 100644 index 21ceec38d8..0000000000 --- a/components/helminstaller/a.yaml +++ /dev/null @@ -1 +0,0 @@ -flag: (( flag ? "yes" :"no" )) diff --git a/components/helminstaller/component-constructor.yaml b/components/helminstaller/component-constructor.yaml new file mode 100644 index 0000000000..a2223653ad --- /dev/null +++ b/components/helminstaller/component-constructor.yaml @@ -0,0 +1,25 @@ +--- +components: + - name: (( values.COMPONENT)) + version: (( values.VERSION)) + provider: + name: (( values.PROVIDER)) + # use all platforms and create a resource for each + resources: + - name: toiexecutor + type: toiExecutor + labels: + - name: commit + value: (( values.COMMIT )) + input: + type: file + mediaType: application/x-yaml + path: executorspec.yaml + - name: toiimage + type: ociImage + version: (( values.VERSION )) + input: + type: (( bool(values.MULTI) ? "dockermulti" :"docker" )) + repository: (( index(values.IMAGE, ":") >= 0 ? substr(values.IMAGE,0,index(values.IMAGE,":")) :values.IMAGE )) + variants: (( bool(values.MULTI) ? map[split(" ", values.PLATFORMS)|v|-> values.IMAGE "-" replace(v,"/","-")] :~~ )) + path: (( !bool(values.MULTI) ? values.IMAGE :~~ )) \ No newline at end of file diff --git a/components/helminstaller/resources.yaml b/components/helminstaller/resources.yaml deleted file mode 100644 index 9a6f2ef0eb..0000000000 --- a/components/helminstaller/resources.yaml +++ /dev/null @@ -1,20 +0,0 @@ ---- -name: toiimage -type: ociImage -version: (( values.VERSION )) -input: - type: (( bool(values.MULTI) ? "dockermulti" :"docker" )) - repository: (( index(values.IMAGE, ":") >= 0 ? substr(values.IMAGE,0,index(values.IMAGE,":")) :values.IMAGE )) - variants: (( bool(values.MULTI) ? map[split(" ", values.PLATFORMS)|v|-> values.IMAGE "-" replace(v,"/","-")] :~~ )) - path: (( !bool(values.MULTI) ? values.IMAGE :~~ )) ---- -name: toiexecutor -type: toiExecutor -labels: - - name: commit - value: (( values.COMMIT )) -input: - type: file - mediaType: application/x-yaml - path: executorspec.yaml - diff --git a/components/ocmcli/Makefile b/components/ocmcli/Makefile index 418712ca37..2502ef16e3 100644 --- a/components/ocmcli/Makefile +++ b/components/ocmcli/Makefile @@ -8,6 +8,7 @@ OCMREPO ?= ghcr.io/$(GITHUBORG)/ocm MULTI ?= true IMAGE_PLATFORMS ?= linux/amd64 linux/arm64 PLATFORMS = $(IMAGE_PLATFORMS) darwin/arm64 darwin/amd64 windows/amd64 +CTF_TYPE ?= directory REPO_ROOT := $(dir $(realpath $(lastword $(MAKEFILE_LIST))))../.. GIT_TREE_STATE = $(shell [ -z "$$(git status --porcelain 2>/dev/null)" ] && echo clean || echo dirty) @@ -18,9 +19,7 @@ PLATFORM_OS := $(shell go env GOOS) PLATFORM_ARCH := $(shell go env GOARCH) CMDSRCS=$(shell find $(REPO_ROOT)/cmds/$(CMD) -type f) Makefile -OCMSRCS=$(shell find $(REPO_ROOT)/pkg -type f) $(REPO_ROOT)/go.* - -ATTRIBUTES = VERSION="$(VERSION)" NAME="$(NAME)" COMMIT="$(COMMIT)" IMAGE="$(IMAGE):$(VERSION)" PLATFORMS="$(PLATFORMS)" IMAGE_PLATFORMS="$(IMAGE_PLATFORMS)" GEN="$(GEN)" MULTI=$(MULTI) +OCMSRCS=$(shell find $(REPO_ROOT)/api -type f) $(REPO_ROOT)/go.* ifeq ($(MULTI),true) FLAGSUF = .multi @@ -38,7 +37,10 @@ $(OCM_BIN): $(REPO_ROOT)/cmds/ocm/main.go # Use the binary for the OCM command OCM = $(OCM_BIN) $(CREDS) -GEN = $(REPO_ROOT)/gen/$(shell basename $(realpath .)) +GEN = $(REPO_ROOT)/gen/$(NAME) + + $(GEN): + @mkdir -p $(GEN) NOW := $(shell date -u +%FT%T%z) BUILD_FLAGS := "-s -w \ @@ -52,7 +54,7 @@ ALPINE_LATEST_VER=$(shell curl -s https://registry.hub.docker.com/v2/repositorie .PHONY: build build: $(GEN)/build -$(GEN)/build: $(GEN)/.exists $(CMDSRCS) $(OCMSRCS) +$(GEN)/build: $(GEN) $(GEN)/.exists $(CMDSRCS) $(OCMSRCS) @for i in $(PLATFORMS); do \ tag=$$(echo $$i | sed -e s:/:-:g); \ echo GOARCH=$$(basename $$i) GOOS=$$(dirname $$i) CGO_ENABLED=0 go build -ldflags $(BUILD_FLAGS) -o $(GEN)/$(NAME).$$tag ../../cmds/$(CMD); \ @@ -99,24 +101,30 @@ $(GEN)/image.multi: Dockerfile $(GEN)/build .PHONY: ctf ctf: $(GEN)/ctf -$(GEN)/ctf: $(GEN)/ca.done $(OCM_BIN) +$(GEN)/ctf: $(OCM_BIN) $(GEN)/.exists $(GEN)/build $(GEN)/image$(FLAGSUF) component-constructor.yaml $(CHARTSRCS) Makefile @rm -rf "$(GEN)/ctf" - $(OCM) transfer ca $(GEN)/ca $(GEN)/ctf - touch $(GEN)/ctf + $(OCM) add componentversions \ + --create \ + --file $(GEN)/ctf \ + --type $(CTF_TYPE) \ + --templater=spiff \ + COMPONENT="$(COMPONENT)" \ + NAME="$(NAME)" \ + VERSION="$(VERSION)" \ + PROVIDER="$(PROVIDER)" \ + COMMIT="$(COMMIT)" \ + GEN="$(GEN)" \ + PLATFORMS="$(PLATFORMS)" \ + IMAGE_PLATFORMS="$(IMAGE_PLATFORMS)" \ + MULTI=$(MULTI) \ + IMAGE="$(IMAGE):$(VERSION)" \ + component-constructor.yaml + touch "$(GEN)/ctf" .PHONY: version version: @echo $(VERSION) -.PHONY: ca -ca: $(GEN)/ca.done - -$(GEN)/ca.done: $(GEN)/.exists $(GEN)/build $(GEN)/image$(FLAGSUF) resources.yaml $(CHARTSRCS) Makefile $(OCM_BIN) - $(OCM) create ca -f $(COMPONENT) "$(VERSION)" --provider $(PROVIDER) --file $(GEN)/ca - $(OCM) add resources --templater=spiff --file $(GEN)/ca $(ATTRIBUTES) resources.yaml - $(OCM) add sources $(GEN)/ca VERSION="$(VERSION)" COMMIT="$(COMMIT)" sources.yaml - @touch $(GEN)/ca.done - .PHONY: push push: $(GEN)/ctf $(GEN)/push.$(NAME) @@ -147,12 +155,12 @@ info: @echo "GIT_TREE: $(GIT_TREE_STATE)" .PHONY: describe -describe: $(GEN)/ctf - ocm get resources --lookup $(OCMREPO) -c -o treewide $(GEN)/ctf +describe: $(GEN)/ctf $(OCM_BIN) + $(OCM) get resources --lookup $(OCMREPO) -c -o treewide $(GEN)/ctf .PHONY: descriptor -descriptor: $(GEN)/ctf - ocm get component -S v3alpha1 -o yaml $(GEN)/ctf +descriptor: $(GEN)/ctf $(OCM_BIN) + $(OCM) get component -S v3alpha1 -o yaml $(GEN)/ctf .PHONY: clean clean: diff --git a/components/ocmcli/resources.yaml b/components/ocmcli/component-constructor.yaml similarity index 63% rename from components/ocmcli/resources.yaml rename to components/ocmcli/component-constructor.yaml index ac152b9b83..11eb4bcecb 100644 --- a/components/ocmcli/resources.yaml +++ b/components/ocmcli/component-constructor.yaml @@ -26,6 +26,21 @@ helper: variants: (( bool(values.MULTI) ? map[split(" ", values.IMAGE_PLATFORMS)|v|-> values.IMAGE "-" replace(v,"/","-")] :~~ )) path: (( !bool(values.MULTI) ? values.IMAGE :~~ )) +components: + - name: (( values.COMPONENT)) + version: (( values.VERSION)) + provider: + name: (( values.PROVIDER)) + # use all platforms and create a resource for each + resources: (( map[split(" ", values.PLATFORMS)|p|-> *helper.executable] *helper.image )) + sources: + - name: source + type: filesytem + access: + type: github + repoUrl: github.com/open-component-model/ocm + commit: (( values.COMMIT )) + version: (( values.VERSION )) + -resources: (( map[split(" ", values.PLATFORMS)|p|-> *helper.executable] *helper.image )) diff --git a/components/ocmcli/sources.yaml b/components/ocmcli/sources.yaml deleted file mode 100644 index dcc9c5f896..0000000000 --- a/components/ocmcli/sources.yaml +++ /dev/null @@ -1,7 +0,0 @@ -name: source -type: filesytem -access: - type: github - repoUrl: github.com/open-component-model/ocm - commit: ${COMMIT} -version: ${VERSION} From f2f7b769f52e9063984162d035a37749d826f3f8 Mon Sep 17 00:00:00 2001 From: Hilmar Falkenberg Date: Tue, 5 Nov 2024 10:59:25 +0100 Subject: [PATCH 22/58] chore: enhance the publishing to other repositories then github (#1028) #### What this PR does / why we need it Publishing to external repositories might fail for various reasons, therefore we should be able to easily trigger the publishing to those repositories again and again without the need to rebuild a new release from scratch. --- .../publish-to-other-than-github.yaml | 56 +++-------------- .github/workflows/release.yaml | 6 +- .../workflows/retrigger-publish-to-other.yaml | 60 +++++++++++++++++++ 3 files changed, 72 insertions(+), 50 deletions(-) create mode 100644 .github/workflows/retrigger-publish-to-other.yaml diff --git a/.github/workflows/publish-to-other-than-github.yaml b/.github/workflows/publish-to-other-than-github.yaml index 4e3d951398..4648c8261a 100644 --- a/.github/workflows/publish-to-other-than-github.yaml +++ b/.github/workflows/publish-to-other-than-github.yaml @@ -8,34 +8,18 @@ name: Publish Release to other package registries than Github on: - workflow_dispatch: - inputs: - version: - type: string - description: 'Version of the latest release (e.g. v0.42.0)' - required: false - default: '' repository_dispatch: - types: [ocm-cli-release] + types: [publish-ocm-cli] jobs: push-to-aur: name: Update Arch Linux User Repository + if: github.event.client_payload.push-to-aur && github.event.client_payload.version != '' runs-on: ubuntu-latest steps: - name: Ensure proper version - run: | - if [ -n "${{ github.event.inputs.version }}" ]; then - echo "RELEASE_VERSION=$(echo ${{ github.event.inputs.version }} | tr -d ['v'])" >> $GITHUB_ENV - exit 0 - fi - if [ -n "${{ github.event.client_payload.version }}" ]; then - echo "RELEASE_VERSION=$(echo ${{ github.event.client_payload.version }} | tr -d ['v'])" >> $GITHUB_ENV - exit 0 - fi - echo "Version not provided" - exit 1 + run: echo "RELEASE_VERSION=$(echo ${{ github.event.client_payload.version }} | tr -d ['v'])" >> $GITHUB_ENV - name: Install SSH key uses: shimataro/ssh-key-action@v2 with: @@ -56,24 +40,13 @@ jobs: push-to-chocolatey: name: Update Chocolatey + if: github.event.client_payload.push-to-chocolatey && github.event.client_payload.version != '' runs-on: windows-latest steps: - name: Ensure proper version run: | - $workflow_version = "${{ github.event.inputs.version }}" - $repository_version = "${{ github.event.client_payload.version }}" - if (-not ([string]::IsNullOrEmpty($workflow_version))) { - $workflow_version = "$workflow_version" -replace 'v' - echo "RELEASE_VERSION=$workflow_version" | Out-File $env:GITHUB_ENV - exit 0 - } - if (-not ([string]::IsNullOrEmpty($repository_version))) { - $repository_version = "$repository_version" -replace 'v' - echo "RELEASE_VERSION=($repository_version -replace 'v')" | Out-File $env:GITHUB_ENV - exit 0 - } - Write-Host "Version not provided" - exit 1 + $version = "${{ github.event.client_payload.version }}" -replace 'v' + echo "RELEASE_VERSION=$version" | Out-File $env:GITHUB_ENV - name: Generate token id: generate_token uses: tibdex/github-app-token@v2 @@ -91,24 +64,13 @@ jobs: push-to-winget: name: Update Winget + if: github.event.client_payload.push-to-winget && github.event.client_payload.version != '' runs-on: windows-latest steps: - name: Ensure proper version run: | - $workflow_version = "${{ github.event.inputs.version }}" - $repository_version = "${{ github.event.client_payload.version }}" - if (-not ([string]::IsNullOrEmpty($workflow_version))) { - $workflow_version = "$workflow_version" -replace 'v' - echo "RELEASE_VERSION=$workflow_version" | Out-File $env:GITHUB_ENV - exit 0 - } - if (-not ([string]::IsNullOrEmpty($repository_version))) { - $repository_version = "$repository_version" -replace 'v' - echo "RELEASE_VERSION=$repository_version" | Out-File $env:GITHUB_ENV - exit 0 - } - Write-Host "Version not provided" - exit 1 + $version = "${{ github.event.client_payload.version }}" -replace 'v' + echo "RELEASE_VERSION=$version" | Out-File $env:GITHUB_ENV - name: Generate token id: generate_token uses: tibdex/github-app-token@v2 diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 5091f797ab..c834a6500b 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -280,6 +280,6 @@ jobs: uses: peter-evans/repository-dispatch@v3 with: token: ${{ steps.generate_token.outputs.token }} - repository: open-component-model/ocm - event-type: ocm-cli-release - client-payload: '{"version": "${{ env.RELEASE_VERSION }}"}' \ No newline at end of file + repository: ${{ github.repository_owner }}/ocm + event-type: publish-ocm-cli + client-payload: '{"version":"${{ env.RELEASE_VERSION }}","push-to-aur":true,"push-to-chocolatey":true,"push-to-winget":true}' diff --git a/.github/workflows/retrigger-publish-to-other.yaml b/.github/workflows/retrigger-publish-to-other.yaml new file mode 100644 index 0000000000..6226bf3eb4 --- /dev/null +++ b/.github/workflows/retrigger-publish-to-other.yaml @@ -0,0 +1,60 @@ +name: Manually retrigger the publishing of ocm-cli to other repositories + +on: + workflow_dispatch: + inputs: + version: + type: string + description: Which version (e.g. v0.42.0) do you want to publish? + required: true + default: '' + push-to-aur: + type: boolean + description: Do you want to push to the Arch Linux User Repository? + required: false + default: false + push-to-chocolatey: + type: boolean + description: Do you want to push to Chocolatey? + required: false + default: false + push-to-winget: + type: boolean + description: Do you want to push to Winget? + required: false + default: false + +jobs: + retrigger: + name: Create new "Release Publish Event" + runs-on: ubuntu-latest + permissions: + contents: write + id-token: write + packages: write + steps: + - name: Generate token + id: generate_token + uses: tibdex/github-app-token@v2 + with: + app_id: ${{ secrets.OCMBOT_APP_ID }} + private_key: ${{ secrets.OCMBOT_PRIV_KEY }} + - name: Ensure proper version + run: | + curl -sSL -H "Accept: application/vnd.github+json" -H "Authorization: Bearer ${{ steps.generate_token.outputs.token }}" -H "X-GitHub-Api-Version: 2022-11-28" https://api.github.com/repos/open-component-model/ocm/releases > releases.json + jq -r '.[] | .tag_name' releases.json | grep -v -E '.*-rc|latest' > versions.txt + if grep -Fxq '${{ github.event.inputs.version }}' versions.txt; then + echo "Version (${{ github.event.inputs.version }}) found!" + else + echo "Version (${{ github.event.inputs.version }}) not found! This are the availble ones:" + cat versions.txt + exit 1 + fi + echo "RELEASE_VERSION=$(echo ${{ github.event.inputs.version }} )" >> $GITHUB_ENV + - name: Publish Event + uses: peter-evans/repository-dispatch@v3 + with: + token: ${{ steps.generate_token.outputs.token }} + repository: ${{ github.repository_owner }}/ocm + event-type: publish-ocm-cli + client-payload: '{"version":"${{ env.RELEASE_VERSION }}","push-to-aur":${{ github.event.inputs.push-to-aur }},"push-to-chocolatey":${{ github.event.inputs.push-to-chocolatey }},"push-to-winget":${{ github.event.inputs.push-to-winget }}}' From f4758424638e952ec741e807aea019bee637e008 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Nov 2024 11:27:56 +0100 Subject: [PATCH 23/58] chore(deps): bump github.com/golang-jwt/jwt/v4 from 4.5.0 to 4.5.1 in the go_modules group (#1048) Bumps the go_modules group with 1 update: [github.com/golang-jwt/jwt/v4](https://github.com/golang-jwt/jwt). Updates `github.com/golang-jwt/jwt/v4` from 4.5.0 to 4.5.1
Release notes

Sourced from github.com/golang-jwt/jwt/v4's releases.

v4.5.1

Security

Unclear documentation of the error behavior in ParseWithClaims in <= 4.5.0 could lead to situation where users are potentially not checking errors in the way they should be. Especially, if a token is both expired and invalid, the errors returned by ParseWithClaims return both error codes. If users only check for the jwt.ErrTokenExpired using error.Is, they will ignore the embedded jwt.ErrTokenSignatureInvalid and thus potentially accept invalid tokens.

This issue was documented in https://github.com/golang-jwt/jwt/security/advisories/GHSA-29wx-vh33-7x7r and fixed in this release.

Note: v5 was not affected by this issue. So upgrading to this release version is also recommended.

What's Changed

Full Changelog: https://github.com/golang-jwt/jwt/compare/v4.5.0...v4.5.1

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=github.com/golang-jwt/jwt/v4&package-manager=go_modules&previous-version=4.5.0&new-version=4.5.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/open-component-model/ocm/network/alerts).
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 348d27999e..c15b9c39f6 100644 --- a/go.mod +++ b/go.mod @@ -202,7 +202,7 @@ require ( github.com/goccy/go-json v0.10.3 // indirect github.com/goccy/go-yaml v1.12.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang-jwt/jwt/v4 v4.5.0 // indirect + github.com/golang-jwt/jwt/v4 v4.5.1 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/golang/snappy v0.0.4 // indirect diff --git a/go.sum b/go.sum index ea161dd7a6..81418473b1 100644 --- a/go.sum +++ b/go.sum @@ -481,8 +481,9 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= -github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v4 v4.5.1 h1:JdqV9zKUdtaa9gdPlywC3aeoEsR681PlKC+4F5gQgeo= +github.com/golang-jwt/jwt/v4 v4.5.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= From f8f565cac53682dbee543a48ac7793df7bb602b6 Mon Sep 17 00:00:00 2001 From: "ocmbot[bot]" <125909804+ocmbot[bot]@users.noreply.github.com> Date: Tue, 5 Nov 2024 11:47:12 +0100 Subject: [PATCH 24/58] chore: update 'flake.nix' (#1049) Update OCM CLI vendor hash (see: .github/workflows/flake_vendorhash.yaml) Co-authored-by: ocmbot[bot] <125909804+ocmbot[bot]@users.noreply.github.com> --- flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index acacc3b717..5cd8986466 100644 --- a/flake.nix +++ b/flake.nix @@ -35,7 +35,7 @@ state = if (self ? rev) then "clean" else "dirty"; # This vendorHash represents a derivative of all go.mod dependencies and needs to be adjusted with every change - vendorHash = "sha256-rn2toYSngdWuLWgWLDIykAVz66HljQcS1VK8Fd0fCLc="; + vendorHash = "sha256-jKjWnyok8n1UAh03wmfSwZADCWdzhDVKVhyowdhOEqU="; src = ./.; From 06bc4214bbfb9293705e0b84d46811f404720647 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakob=20M=C3=B6ller?= Date: Tue, 5 Nov 2024 11:57:49 +0100 Subject: [PATCH 25/58] fix: set tlskyber=0 (#1047) #### What this PR does / why we need it #### Which issue(s) this PR fixes Fixes https://github.com/open-component-model/ocm/issues/1027 --- go.mod | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/go.mod b/go.mod index c15b9c39f6..9ec857ae53 100644 --- a/go.mod +++ b/go.mod @@ -369,3 +369,10 @@ require ( ) retract [v0.16.0, v0.16.9] // Retract all from v0.16 due to https://github.com/open-component-model/ocm-project/issues/293 + +// crypto/tls: Client Hello is always sent in 2 TCP frames if GODEBUG=tlskyber=1 (default) which causes +// issues with various enterprise network gateways such as Palo Alto Networks. We have been reported issues +// such as https://github.com/open-component-model/ocm/issues/1027 and do not want to pin our crypto/tls version. +// As such we have decided to globally override tlskyber=0 +// For more info, see https://github.com/golang/go/issues/70047 +godebug tlskyber=0 From c722d03f1812eab41b554c2fd2964720b69b7cdd Mon Sep 17 00:00:00 2001 From: Uwe Krueger Date: Tue, 5 Nov 2024 12:06:55 +0100 Subject: [PATCH 26/58] priority for CLI registration options (#1045) #### What this PR does / why we need it The CLI registration options (--downloader, --uploader) now support an additional optional priority segment. The new format is `[:[:[:]]]=` The priority so far was the default priority also used for the builtin registrations. There competing registrations from the CLI (or config) were never used. Therefore - the priority can now be specified on the command line - the default priority is three times the default priority (300) - the default priority for config objects is increased to twice the default priority (200) #### Which issue(s) this PR fixes Fixes #1046 --- api/ocm/extensions/blobhandler/config/type.go | 13 ++- .../extensions/blobhandler/registration.go | 3 + api/ocm/extensions/download/config/type.go | 13 ++- .../common/options/downloaderoption/option.go | 2 +- .../options/downloaderoption/option_test.go | 80 +++++++++++++++++++ .../options/downloaderoption/suite_test.go | 13 +++ .../common/options/optutils/reg_test.go | 2 +- .../common/options/optutils/registration.go | 41 +++++++--- .../common/options/uploaderoption/option.go | 2 +- .../options/uploaderoption/option_test.go | 80 +++++++++++++++++++ .../options/uploaderoption/uploader_test.go | 4 +- docs/reference/ocm_add_componentversions.md | 2 +- docs/reference/ocm_configfile.md | 6 +- docs/reference/ocm_download_resources.md | 2 +- .../ocm_transfer_commontransportarchive.md | 2 +- .../ocm_transfer_componentversions.md | 2 +- 16 files changed, 241 insertions(+), 26 deletions(-) create mode 100644 cmds/ocm/commands/ocmcmds/common/options/downloaderoption/option_test.go create mode 100644 cmds/ocm/commands/ocmcmds/common/options/downloaderoption/suite_test.go create mode 100644 cmds/ocm/commands/ocmcmds/common/options/uploaderoption/option_test.go diff --git a/api/ocm/extensions/blobhandler/config/type.go b/api/ocm/extensions/blobhandler/config/type.go index 211108164c..01a2054412 100644 --- a/api/ocm/extensions/blobhandler/config/type.go +++ b/api/ocm/extensions/blobhandler/config/type.go @@ -64,7 +64,13 @@ func (a *Config) ApplyTo(ctx cfgcpi.Context, target interface{}) error { } reg := blobhandler.For(t) for _, h := range a.Registrations { - accepted, err := reg.RegisterByName(h.Name, t, h.Config, &h.HandlerOptions) + opts := h.HandlerOptions + if opts.Priority == 0 { + // config objects have higher prio than builtin defaults + // CLI options get even higher prio. + opts.Priority = blobhandler.DEFAULT_BLOBHANDLER_PRIO * 2 + } + accepted, err := reg.RegisterByName(h.Name, t, h.Config, &opts) if err != nil { return errors.Wrapf(err, "registering upload handler %q[%s]", h.Name, h.Description) } @@ -75,9 +81,10 @@ func (a *Config) ApplyTo(ctx cfgcpi.Context, target interface{}) error { return nil } -const usage = ` +var usage = ` The config type ` + ConfigType + ` can be used to define a list -of preconfigured upload handler registrations (see ocm ocm-uploadhandlers): +of preconfigured upload handler registrations (see ocm ocm-uploadhandlers), +the default priority is ` + fmt.Sprintf("%d", download.DEFAULT_BLOBHANDLER_PRIO*2) + `:
     type: ` + ConfigType + `
diff --git a/api/ocm/extensions/blobhandler/registration.go b/api/ocm/extensions/blobhandler/registration.go
index 83a1763517..308a06765c 100644
--- a/api/ocm/extensions/blobhandler/registration.go
+++ b/api/ocm/extensions/blobhandler/registration.go
@@ -4,8 +4,11 @@ import (
 	"fmt"
 
 	"ocm.software/ocm/api/ocm/cpi"
+	"ocm.software/ocm/api/ocm/internal"
 )
 
+const DEFAULT_BLOBHANDLER_PRIO = internal.DEFAULT_BLOBHANDLER_PRIO
+
 func RegisterHandlerByName(ctx cpi.ContextProvider, name string, config HandlerConfig, opts ...HandlerOption) error {
 	o, err := For(ctx).RegisterByName(name, ctx.OCMContext(), config, opts...)
 	if err != nil {
diff --git a/api/ocm/extensions/download/config/type.go b/api/ocm/extensions/download/config/type.go
index c29fa3eeee..868fe46a28 100644
--- a/api/ocm/extensions/download/config/type.go
+++ b/api/ocm/extensions/download/config/type.go
@@ -63,7 +63,13 @@ func (a *Config) ApplyTo(ctx cfgcpi.Context, target interface{}) error {
 	}
 	reg := download.For(t)
 	for _, h := range a.Registrations {
-		accepted, err := reg.RegisterByName(h.Name, t, h.Config, &h.HandlerOptions)
+		opts := h.HandlerOptions
+		if opts.Priority == 0 {
+			// config objects have higher prio than builtin defaults
+			// CLI options get even higher prio.
+			opts.Priority = download.DEFAULT_BLOBHANDLER_PRIO * 2
+		}
+		accepted, err := reg.RegisterByName(h.Name, t, h.Config, &opts)
 		if err != nil {
 			return errors.Wrapf(err, "registering download handler %q[%s]", h.Name, h.Description)
 		}
@@ -74,9 +80,10 @@ func (a *Config) ApplyTo(ctx cfgcpi.Context, target interface{}) error {
 	return nil
 }
 
-const usage = `
+var usage = `
 The config type ` + ConfigType + ` can be used to define a list
-of preconfigured download handler registrations (see ocm ocm-downloadhandlers):
+of preconfigured download handler registrations (see ocm ocm-downloadhandlers),
+the default priority is ` + fmt.Sprintf("%d", download.DEFAULT_BLOBHANDLER_PRIO*2) + `:
 
 
     type: ` + ConfigType + `
diff --git a/cmds/ocm/commands/ocmcmds/common/options/downloaderoption/option.go b/cmds/ocm/commands/ocmcmds/common/options/downloaderoption/option.go
index 3c214aa4b7..0552c854c1 100644
--- a/cmds/ocm/commands/ocmcmds/common/options/downloaderoption/option.go
+++ b/cmds/ocm/commands/ocmcmds/common/options/downloaderoption/option.go
@@ -31,7 +31,7 @@ type Option struct {
 func (o *Option) Register(ctx ocm.ContextProvider) error {
 	for _, s := range o.Registrations {
 		err := download.RegisterHandlerByName(ctx.OCMContext(), s.Name, s.Config,
-			download.ForArtifactType(s.ArtifactType), download.ForMimeType(s.MediaType))
+			download.ForArtifactType(s.ArtifactType), download.ForMimeType(s.MediaType), download.WithPrio(s.GetPriority(download.DEFAULT_BLOBHANDLER_PRIO*3)))
 		if err != nil {
 			return err
 		}
diff --git a/cmds/ocm/commands/ocmcmds/common/options/downloaderoption/option_test.go b/cmds/ocm/commands/ocmcmds/common/options/downloaderoption/option_test.go
new file mode 100644
index 0000000000..6cdfa5a10c
--- /dev/null
+++ b/cmds/ocm/commands/ocmcmds/common/options/downloaderoption/option_test.go
@@ -0,0 +1,80 @@
+package downloaderoption_test
+
+import (
+	. "github.com/mandelsoft/goutils/testutils"
+	. "github.com/onsi/ginkgo/v2"
+	. "github.com/onsi/gomega"
+
+	"github.com/mandelsoft/goutils/generics"
+	"github.com/spf13/pflag"
+
+	"ocm.software/ocm/api/ocm"
+	me "ocm.software/ocm/cmds/ocm/commands/ocmcmds/common/options/downloaderoption"
+)
+
+var _ = Describe("Downloader Option Test Environment", func() {
+	var o *me.Option
+	var fs *pflag.FlagSet
+
+	BeforeEach(func() {
+		o = me.New(ocm.DefaultContext())
+		fs = &pflag.FlagSet{}
+		o.AddFlags(fs)
+	})
+
+	It("handles all parts", func() {
+		MustBeSuccessful(fs.Parse([]string{"--downloader", `bla/blub:a:b:10={"k":"v"}`}))
+		MustBeSuccessful(o.Configure(nil))
+		Expect(len(o.Registrations)).To(Equal(1))
+		Expect(o.Registrations[0].Prio).To(Equal(generics.Pointer(10)))
+		Expect(o.Registrations[0].Name).To(Equal("bla/blub"))
+		Expect(o.Registrations[0].ArtifactType).To(Equal("a"))
+		Expect(o.Registrations[0].MediaType).To(Equal("b"))
+		Expect(o.Registrations[0].Config).To(Equal([]byte(`{"k":"v"}`)))
+		Expect("").To(Equal(""))
+	})
+
+	It("handles empty parts", func() {
+		MustBeSuccessful(fs.Parse([]string{"--downloader", `bla/blub:::10={"k":"v"}`}))
+		MustBeSuccessful(o.Configure(nil))
+		Expect(len(o.Registrations)).To(Equal(1))
+		Expect(o.Registrations[0].Prio).To(Equal(generics.Pointer(10)))
+		Expect(o.Registrations[0].Name).To(Equal("bla/blub"))
+		Expect(o.Registrations[0].ArtifactType).To(Equal(""))
+		Expect(o.Registrations[0].MediaType).To(Equal(""))
+		Expect(o.Registrations[0].Config).To(Equal([]byte(`{"k":"v"}`)))
+	})
+
+	It("handles art/media/config", func() {
+		MustBeSuccessful(fs.Parse([]string{"--downloader", `bla/blub:a:b={"k":"v"}`}))
+		MustBeSuccessful(o.Configure(nil))
+		Expect(len(o.Registrations)).To(Equal(1))
+		Expect(o.Registrations[0].Prio).To(BeNil())
+		Expect(o.Registrations[0].Name).To(Equal("bla/blub"))
+		Expect(o.Registrations[0].ArtifactType).To(Equal("a"))
+		Expect(o.Registrations[0].MediaType).To(Equal("b"))
+		Expect(o.Registrations[0].Config).To(Equal([]byte(`{"k":"v"}`)))
+	})
+
+	It("handles art/media/empty config", func() {
+		MustBeSuccessful(fs.Parse([]string{"--downloader", `bla/blub:a:b`}))
+		MustBeSuccessful(o.Configure(nil))
+		Expect(len(o.Registrations)).To(Equal(1))
+		Expect(o.Registrations[0].Prio).To(BeNil())
+		Expect(o.Registrations[0].Name).To(Equal("bla/blub"))
+		Expect(o.Registrations[0].ArtifactType).To(Equal("a"))
+		Expect(o.Registrations[0].MediaType).To(Equal("b"))
+		Expect(o.Registrations[0].Config).To(BeNil())
+	})
+
+	It("handles empty config", func() {
+		MustBeSuccessful(fs.Parse([]string{"--downloader", `bla/blub`}))
+		MustBeSuccessful(o.Configure(nil))
+		Expect(len(o.Registrations)).To(Equal(1))
+		Expect(o.Registrations[0].Prio).To(BeNil())
+		Expect(o.Registrations[0].Name).To(Equal("bla/blub"))
+		Expect(o.Registrations[0].ArtifactType).To(Equal(""))
+		Expect(o.Registrations[0].MediaType).To(Equal(""))
+		Expect(o.Registrations[0].Config).To(BeNil())
+	})
+})
diff --git a/cmds/ocm/commands/ocmcmds/common/options/downloaderoption/suite_test.go b/cmds/ocm/commands/ocmcmds/common/options/downloaderoption/suite_test.go
new file mode 100644
index 0000000000..7774df74a1
--- /dev/null
+++ b/cmds/ocm/commands/ocmcmds/common/options/downloaderoption/suite_test.go
@@ -0,0 +1,13 @@
+package downloaderoption_test
+
+import (
+	"testing"
+
+	. "github.com/onsi/ginkgo/v2"
+	. "github.com/onsi/gomega"
+)
+
+func TestConfig(t *testing.T) {
+	RegisterFailHandler(Fail)
+	RunSpecs(t, "downloader option Test Suite")
+}
diff --git a/cmds/ocm/commands/ocmcmds/common/options/optutils/reg_test.go b/cmds/ocm/commands/ocmcmds/common/options/optutils/reg_test.go
index cb15c02251..829b42c17e 100644
--- a/cmds/ocm/commands/ocmcmds/common/options/optutils/reg_test.go
+++ b/cmds/ocm/commands/ocmcmds/common/options/optutils/reg_test.go
@@ -105,6 +105,6 @@ var _ = Describe("registration options", func() {
 
 	It("fails", func() {
 		MustBeSuccessful(flags.Parse([]string{`--test`, `plugin/name:::=Name`}))
-		MustFailWithMessage(opt.Configure(ctx), "invalid test registration plugin/name::: must be of "+optutils.RegistrationFormat)
+		MustFailWithMessage(opt.Configure(ctx), "invalid test registration plugin/name::: (invalid priority) must be of "+optutils.RegistrationFormat)
 	})
 })
diff --git a/cmds/ocm/commands/ocmcmds/common/options/optutils/registration.go b/cmds/ocm/commands/ocmcmds/common/options/optutils/registration.go
index a83fe2b1fd..44b0da8344 100644
--- a/cmds/ocm/commands/ocmcmds/common/options/optutils/registration.go
+++ b/cmds/ocm/commands/ocmcmds/common/options/optutils/registration.go
@@ -3,9 +3,11 @@ package optutils
 import (
 	"encoding/json"
 	"fmt"
+	"strconv"
 	"strings"
 
 	"github.com/mandelsoft/goutils/errors"
+	"github.com/mandelsoft/goutils/generics"
 	"github.com/spf13/pflag"
 	"sigs.k8s.io/yaml"
 
@@ -18,9 +20,17 @@ type Registration struct {
 	Name         string
 	ArtifactType string
 	MediaType    string
+	Prio         *int
 	Config       interface{}
 }
 
+func (r *Registration) GetPriority(def int) int {
+	if r.Prio != nil {
+		return *r.Prio
+	}
+	return def
+}
+
 func NewRegistrationOption(name, short, desc, usage string) RegistrationOption {
 	return RegistrationOption{name: name, short: short, desc: desc, usage: usage}
 }
@@ -34,7 +44,7 @@ type RegistrationOption struct {
 	Registrations []*Registration
 }
 
-const RegistrationFormat = "[:[:]]== 0 {
 			art = nam[i+1:]
 			nam = nam[:i]
-			i = strings.Index(art, ":")
-			if i >= 0 {
-				med = art[i+1:]
-				art = art[:i]
-				i = strings.Index(med, ":")
-				if i >= 0 {
-					return fmt.Errorf("invalid %s registration %s must be of %s", o.name, n, RegistrationFormat)
-				}
+		}
+		i = strings.Index(art, ":")
+		if i >= 0 {
+			med = art[i+1:]
+			art = art[:i]
+		}
+		i = strings.Index(med, ":")
+		if i >= 0 {
+			p := med[i+1:]
+			med = med[:i]
+
+			v, err := strconv.ParseInt(p, 10, 32)
+			if err != nil {
+				return fmt.Errorf("invalid %s registration %s (invalid priority) must be of %s", o.name, n, RegistrationFormat)
 			}
+			prio = generics.Pointer(int(v))
+		}
+		i = strings.Index(med, ":")
+		if i >= 0 {
+			return fmt.Errorf("invalid %s registration %s must be of %s", o.name, n, RegistrationFormat)
 		}
 
 		var data interface{}
@@ -93,6 +115,7 @@ func (o *RegistrationOption) Configure(ctx clictx.Context) error {
 			Name:         nam,
 			ArtifactType: art,
 			MediaType:    med,
+			Prio:         prio,
 			Config:       data,
 		})
 	}
diff --git a/cmds/ocm/commands/ocmcmds/common/options/uploaderoption/option.go b/cmds/ocm/commands/ocmcmds/common/options/uploaderoption/option.go
index 4386201744..a5fa584f05 100644
--- a/cmds/ocm/commands/ocmcmds/common/options/uploaderoption/option.go
+++ b/cmds/ocm/commands/ocmcmds/common/options/uploaderoption/option.go
@@ -29,7 +29,7 @@ type Option struct {
 func (o *Option) Register(ctx ocm.ContextProvider) error {
 	for _, s := range o.Registrations {
 		err := blobhandler.RegisterHandlerByName(ctx.OCMContext(), s.Name, s.Config,
-			blobhandler.ForArtifactType(s.ArtifactType), blobhandler.ForMimeType(s.MediaType))
+			blobhandler.ForArtifactType(s.ArtifactType), blobhandler.ForMimeType(s.MediaType), blobhandler.WithPrio(s.GetPriority(blobhandler.DEFAULT_BLOBHANDLER_PRIO*3)))
 		if err != nil {
 			return err
 		}
diff --git a/cmds/ocm/commands/ocmcmds/common/options/uploaderoption/option_test.go b/cmds/ocm/commands/ocmcmds/common/options/uploaderoption/option_test.go
new file mode 100644
index 0000000000..91a4fd78c9
--- /dev/null
+++ b/cmds/ocm/commands/ocmcmds/common/options/uploaderoption/option_test.go
@@ -0,0 +1,80 @@
+package uploaderoption_test
+
+import (
+	. "github.com/mandelsoft/goutils/testutils"
+	. "github.com/onsi/ginkgo/v2"
+	. "github.com/onsi/gomega"
+
+	"github.com/mandelsoft/goutils/generics"
+	"github.com/spf13/pflag"
+
+	"ocm.software/ocm/api/ocm"
+	me "ocm.software/ocm/cmds/ocm/commands/ocmcmds/common/options/uploaderoption"
+)
+
+var _ = Describe("Downloader Option Test Environment", func() {
+	var o *me.Option
+	var fs *pflag.FlagSet
+
+	BeforeEach(func() {
+		o = me.New(ocm.DefaultContext())
+		fs = &pflag.FlagSet{}
+		o.AddFlags(fs)
+	})
+
+	It("handles all parts", func() {
+		MustBeSuccessful(fs.Parse([]string{"--uploader", `bla/blub:a:b:10={"k":"v"}`}))
+		MustBeSuccessful(o.Configure(nil))
+		Expect(len(o.Registrations)).To(Equal(1))
+		Expect(o.Registrations[0].Prio).To(Equal(generics.Pointer(10)))
+		Expect(o.Registrations[0].Name).To(Equal("bla/blub"))
+		Expect(o.Registrations[0].ArtifactType).To(Equal("a"))
+		Expect(o.Registrations[0].MediaType).To(Equal("b"))
+		Expect(o.Registrations[0].Config).To(Equal([]byte(`{"k":"v"}`)))
+		Expect("").To(Equal(""))
+	})
+
+	It("handles empty parts", func() {
+		MustBeSuccessful(fs.Parse([]string{"--uploader", `bla/blub:::10={"k":"v"}`}))
+		MustBeSuccessful(o.Configure(nil))
+		Expect(len(o.Registrations)).To(Equal(1))
+		Expect(o.Registrations[0].Prio).To(Equal(generics.Pointer(10)))
+		Expect(o.Registrations[0].Name).To(Equal("bla/blub"))
+		Expect(o.Registrations[0].ArtifactType).To(Equal(""))
+		Expect(o.Registrations[0].MediaType).To(Equal(""))
+		Expect(o.Registrations[0].Config).To(Equal([]byte(`{"k":"v"}`)))
+	})
+
+	It("handles art/media/config", func() {
+		MustBeSuccessful(fs.Parse([]string{"--uploader", `bla/blub:a:b={"k":"v"}`}))
+		MustBeSuccessful(o.Configure(nil))
+		Expect(len(o.Registrations)).To(Equal(1))
+		Expect(o.Registrations[0].Prio).To(BeNil())
+		Expect(o.Registrations[0].Name).To(Equal("bla/blub"))
+		Expect(o.Registrations[0].ArtifactType).To(Equal("a"))
+		Expect(o.Registrations[0].MediaType).To(Equal("b"))
+		Expect(o.Registrations[0].Config).To(Equal([]byte(`{"k":"v"}`)))
+	})
+
+	It("handles art/media/empty config", func() {
+		MustBeSuccessful(fs.Parse([]string{"--uploader", `bla/blub:a:b`}))
+		MustBeSuccessful(o.Configure(nil))
+		Expect(len(o.Registrations)).To(Equal(1))
+		Expect(o.Registrations[0].Prio).To(BeNil())
+		Expect(o.Registrations[0].Name).To(Equal("bla/blub"))
+		Expect(o.Registrations[0].ArtifactType).To(Equal("a"))
+		Expect(o.Registrations[0].MediaType).To(Equal("b"))
+		Expect(o.Registrations[0].Config).To(BeNil())
+	})
+
+	It("handles empty config", func() {
+		MustBeSuccessful(fs.Parse([]string{"--uploader", `bla/blub`}))
+		MustBeSuccessful(o.Configure(nil))
+		Expect(len(o.Registrations)).To(Equal(1))
+		Expect(o.Registrations[0].Prio).To(BeNil())
+		Expect(o.Registrations[0].Name).To(Equal("bla/blub"))
+		Expect(o.Registrations[0].ArtifactType).To(Equal(""))
+		Expect(o.Registrations[0].MediaType).To(Equal(""))
+		Expect(o.Registrations[0].Config).To(BeNil())
+	})
+})
diff --git a/cmds/ocm/commands/ocmcmds/common/options/uploaderoption/uploader_test.go b/cmds/ocm/commands/ocmcmds/common/options/uploaderoption/uploader_test.go
index fbc5e9f99d..5942457560 100644
--- a/cmds/ocm/commands/ocmcmds/common/options/uploaderoption/uploader_test.go
+++ b/cmds/ocm/commands/ocmcmds/common/options/uploaderoption/uploader_test.go
@@ -84,7 +84,7 @@ var _ = Describe("uploader option", func() {
 	})
 
 	It("fails", func() {
-		MustBeSuccessful(flags.Parse([]string{`--uploader`, `plugin/name:::=Name`}))
-		MustFailWithMessage(opt.Configure(ctx), "invalid uploader registration plugin/name::: must be of "+optutils.RegistrationFormat)
+		MustBeSuccessful(flags.Parse([]string{`--uploader`, `plugin/name:::0:=Name`}))
+		MustFailWithMessage(opt.Configure(ctx), "invalid uploader registration plugin/name:::0: (invalid priority) must be of "+optutils.RegistrationFormat)
 	})
 })
diff --git a/docs/reference/ocm_add_componentversions.md b/docs/reference/ocm_add_componentversions.md
index 91ae988a4a..b95988d4ac 100644
--- a/docs/reference/ocm_add_componentversions.md
+++ b/docs/reference/ocm_add_componentversions.md
@@ -31,7 +31,7 @@ componentversions, componentversion, cv, components, component, comps, comp, c
   -s, --settings stringArray      settings file with variable settings (yaml)
       --templater string          templater to use (go, none, spiff, subst) (default "subst")
   -t, --type string               archive format (directory, tar, tgz) (default "directory")
-      --uploader =   repository uploader ([:[:]]==   repository uploader ([:[:[:]]]=) (default [])
   -v, --version string            default version for components
 ```
 
diff --git a/docs/reference/ocm_configfile.md b/docs/reference/ocm_configfile.md
index e92a1ba5e6..ae9e51920d 100644
--- a/docs/reference/ocm_configfile.md
+++ b/docs/reference/ocm_configfile.md
@@ -61,7 +61,8 @@ The following configuration types are supported:
   
- downloader.ocm.config.ocm.software The config type downloader.ocm.config.ocm.software can be used to define a list - of preconfigured download handler registrations (see [ocm ocm-downloadhandlers](ocm_ocm-downloadhandlers.md)): + of preconfigured download handler registrations (see [ocm ocm-downloadhandlers](ocm_ocm-downloadhandlers.md)), + the default priority is 200:
       type: downloader.ocm.config.ocm.software
@@ -314,7 +315,8 @@ The following configuration types are supported:
   
- uploader.ocm.config.ocm.software The config type uploader.ocm.config.ocm.software can be used to define a list - of preconfigured upload handler registrations (see [ocm ocm-uploadhandlers](ocm_ocm-uploadhandlers.md)): + of preconfigured upload handler registrations (see [ocm ocm-uploadhandlers](ocm_ocm-uploadhandlers.md)), + the default priority is 200:
       type: uploader.ocm.config.ocm.software
diff --git a/docs/reference/ocm_download_resources.md b/docs/reference/ocm_download_resources.md
index 1e81643411..fd14528178 100644
--- a/docs/reference/ocm_download_resources.md
+++ b/docs/reference/ocm_download_resources.md
@@ -18,7 +18,7 @@ resources, resource, res, r
       --check-verified              enable verification store
   -c, --constraints constraints     version constraint
   -d, --download-handlers           use download handler if possible
-      --downloader =   artifact downloader ([:[:]]==   artifact downloader ([:[:[:]]]=) (default [])
   -x, --executable                  download executable for local platform
   -h, --help                        help for resources
       --latest                      restrict component versions to latest
diff --git a/docs/reference/ocm_transfer_commontransportarchive.md b/docs/reference/ocm_transfer_commontransportarchive.md
index 17ec4d89e6..799b4d1d35 100644
--- a/docs/reference/ocm_transfer_commontransportarchive.md
+++ b/docs/reference/ocm_transfer_commontransportarchive.md
@@ -29,7 +29,7 @@ commontransportarchive, ctf
   -s, --scriptFile string           filename of transfer handler script
   -E, --stop-on-existing            stop on existing component version in target repository
   -t, --type string                 archive format (directory, tar, tgz) (default "directory")
-      --uploader =     repository uploader ([:[:]]==     repository uploader ([:[:[:]]]=) (default [])
 ```
 
 ### Description
diff --git a/docs/reference/ocm_transfer_componentversions.md b/docs/reference/ocm_transfer_componentversions.md
index f335ae5629..86af0d1002 100644
--- a/docs/reference/ocm_transfer_componentversions.md
+++ b/docs/reference/ocm_transfer_componentversions.md
@@ -34,7 +34,7 @@ componentversions, componentversion, cv, components, component, comps, comp, c
   -s, --scriptFile string           filename of transfer handler script
   -E, --stop-on-existing            stop on existing component version in target repository
   -t, --type string                 archive format (directory, tar, tgz) (default "directory")
-      --uploader =     repository uploader ([:[:]]==     repository uploader ([:[:[:]]]=) (default [])
 ```
 
 ### Description

From 9f7a730ca7143ce1e5173480f105f9bd4de37b05 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jakob=20M=C3=B6ller?= 
Date: Tue, 5 Nov 2024 13:38:15 +0100
Subject: [PATCH 27/58] chore: disable runner cache for release note drafter
 (#1051)


#### What this PR does / why we need it

Disables the go cache for the release note drafter to avoid pulling in
4gi of cached data onto our instances (so we avoid no space left on
device issues)

#### Which issue(s) this PR fixes

---
 .github/workflows/release-drafter.yaml | 22 ----------------------
 1 file changed, 22 deletions(-)

diff --git a/.github/workflows/release-drafter.yaml b/.github/workflows/release-drafter.yaml
index 59e819bed0..0b531836e7 100644
--- a/.github/workflows/release-drafter.yaml
+++ b/.github/workflows/release-drafter.yaml
@@ -25,28 +25,6 @@ jobs:
           go-version-file: '${{ github.workspace }}/go.mod'
           cache: false
 
-      - name: Get go environment for use with cache
-        run: |
-          echo "go_cache=$(go env GOCACHE)" >> $GITHUB_ENV
-          echo "go_modcache=$(go env GOMODCACHE)" >> $GITHUB_ENV
-
-      # This step will only reuse the go mod and build cache from main made during the Build,
-      # see push_ocm.yaml => "ocm-cli-latest" Job
-      # This means it never caches by itself and PRs cannot cause cache pollution / thrashing
-      # This is because we have huge storage requirements for our cache because of the mass of dependencies
-      - name: Restore / Reuse Cache from central build
-        id: cache-golang-restore
-        uses: actions/cache/restore@v4 # Only Restore, not build another cache (too big)
-        with:
-          path: |
-            ${{ env.go_cache }}
-            ${{ env.go_modcache }}
-          key: ${{ env.cache_name }}-${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}-${{ hashFiles('**/go.mod') }}
-          restore-keys: |
-            ${{ env.cache_name }}-${{ runner.os }}-go-
-        env:
-          cache_name: ocm-cli-latest-go-cache # needs to be the same key in the end as in the build step
-
       - name: Set Version
         run: |
           RELEASE_VERSION=v$(go run $GITHUB_WORKSPACE/api/version/generate print-version)

From 9e27f160d65b494c6dc7aacf91392d1b475a7654 Mon Sep 17 00:00:00 2001
From: Uwe Krueger 
Date: Wed, 6 Nov 2024 09:22:21 +0100
Subject: [PATCH 28/58] component constructor with references field (#1054)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit


#### What this PR does / why we need it
The component constructor used the field `componentReferences` from the
v2 version of the component descriptor.
in v3 this has been corrected to `references` (it described component
version references and no component references).
This should reflected in the constructor files, also.

the old field is now deprecated (but still works). Instead, the field
`references` is supported, now.
It is not possible to use both fields at the same time.

#### Which issue(s) this PR fixes


Fixes https://github.com/open-component-model/ocm/issues/1041

Co-authored-by: Jakob Möller 
---
 .../common/addhdlrs/comp/components.go        |  6 ++++
 .../ocmcmds/common/addhdlrs/comp/elements.go  | 13 ++++++-
 .../ocmcmds/components/add/cmd_test.go        |  8 ++++-
 .../testdata/component-constructor-old.yaml   | 34 +++++++++++++++++++
 .../add/testdata/component-constructor.yaml   |  2 +-
 .../add/testdata/component-dup-ref.yaml       |  2 +-
 .../add/testdata/component-dup-res.yaml       |  2 +-
 .../add/testdata/component-dup-src.yaml       |  2 +-
 .../add/testdata/components-dup.yaml          |  2 +-
 .../components/add/testdata/components.yaml   |  2 +-
 .../helmdemo/component-constructor.yaml       |  2 +-
 .../subchartsdemo/component-constructor.yaml  |  2 +-
 12 files changed, 67 insertions(+), 10 deletions(-)
 create mode 100644 cmds/ocm/commands/ocmcmds/components/add/testdata/component-constructor-old.yaml

diff --git a/cmds/ocm/commands/ocmcmds/common/addhdlrs/comp/components.go b/cmds/ocm/commands/ocmcmds/common/addhdlrs/comp/components.go
index 7f423468fc..05d6139249 100644
--- a/cmds/ocm/commands/ocmcmds/common/addhdlrs/comp/components.go
+++ b/cmds/ocm/commands/ocmcmds/common/addhdlrs/comp/components.go
@@ -1,6 +1,8 @@
 package comp
 
 import (
+	"fmt"
+
 	"github.com/mandelsoft/goutils/errors"
 	"github.com/mandelsoft/goutils/finalizer"
 	"github.com/mandelsoft/goutils/set"
@@ -21,9 +23,13 @@ func ProcessComponents(ctx clictx.Context, ictx inputs.Context, repo ocm.Reposit
 
 	for _, elem := range elems {
 		if r, ok := elem.Spec().(*ResourceSpec); ok {
+			if len(r.References) > 0 && len(r.OldReferences) > 0 {
+				return fmt.Errorf("only field references or componentReferences (deprecated) is possible")
+			}
 			list.Add(addhdlrs.ValidateElementSpecIdentities("resource", elem.Source().String(), sliceutils.Convert[addhdlrs.ElementSpec](r.Resources)))
 			list.Add(addhdlrs.ValidateElementSpecIdentities("source", elem.Source().String(), sliceutils.Convert[addhdlrs.ElementSpec](r.Sources)))
 			list.Add(addhdlrs.ValidateElementSpecIdentities("reference", elem.Source().String(), sliceutils.Convert[addhdlrs.ElementSpec](r.References)))
+			list.Add(addhdlrs.ValidateElementSpecIdentities("reference", elem.Source().String(), sliceutils.Convert[addhdlrs.ElementSpec](r.OldReferences)))
 		}
 	}
 	if err := list.Result(); err != nil {
diff --git a/cmds/ocm/commands/ocmcmds/common/addhdlrs/comp/elements.go b/cmds/ocm/commands/ocmcmds/common/addhdlrs/comp/elements.go
index bd47976aae..c0634d8630 100644
--- a/cmds/ocm/commands/ocmcmds/common/addhdlrs/comp/elements.go
+++ b/cmds/ocm/commands/ocmcmds/common/addhdlrs/comp/elements.go
@@ -143,10 +143,18 @@ func (h *ResourceSpecHandler) Add(ctx clictx.Context, ictx inputs.Context, elem
 	if err != nil {
 		return err
 	}
+
+	if len(r.References) > 0 && len(r.OldReferences) > 0 {
+		return fmt.Errorf("only field references or componentReferences (deprecated) is possible")
+	}
 	err = handle(ctx, ictx, elem.Source(), cv, r.References, h.refhandler)
 	if err != nil {
 		return err
 	}
+	err = handle(ctx, ictx, elem.Source(), cv, r.OldReferences, h.refhandler)
+	if err != nil {
+		return err
+	}
 	return comp.AddVersion(cv)
 }
 
@@ -169,7 +177,10 @@ type ResourceSpec struct {
 	// Sources defines sources that produced the component
 	Sources []*srcs.ResourceSpec `json:"sources"`
 	// References references component dependencies that can be resolved in the current context.
-	References []*refs.ResourceSpec `json:"componentReferences"`
+	References []*refs.ResourceSpec `json:"references"`
+	// OldReferences references component dependencies that can be resolved in the current context.
+	// Deprecated: use field References.
+	OldReferences []*refs.ResourceSpec `json:"componentReferences"`
 	// Resources defines all resources that are created by the component and by a third party.
 	Resources []*rscs.ResourceSpec `json:"resources"`
 }
diff --git a/cmds/ocm/commands/ocmcmds/components/add/cmd_test.go b/cmds/ocm/commands/ocmcmds/components/add/cmd_test.go
index 22435d1afb..a225d098ba 100644
--- a/cmds/ocm/commands/ocmcmds/components/add/cmd_test.go
+++ b/cmds/ocm/commands/ocmcmds/components/add/cmd_test.go
@@ -16,7 +16,7 @@ import (
 	"ocm.software/ocm/api/ocm/extensions/accessmethods/ociartifact"
 	resourcetypes "ocm.software/ocm/api/ocm/extensions/artifacttypes"
 	"ocm.software/ocm/api/ocm/extensions/repositories/ctf"
-	ocmutils "ocm.software/ocm/api/ocm/ocmutils"
+	"ocm.software/ocm/api/ocm/ocmutils"
 	"ocm.software/ocm/api/ocm/valuemergehandler/handlers/defaultmerge"
 	"ocm.software/ocm/api/utils/accessio"
 	"ocm.software/ocm/api/utils/accessobj"
@@ -92,6 +92,12 @@ var _ = Describe("Test Environment", func() {
 		CheckComponent(env, nil)
 	})
 
+	It("creates ctf and adds component (deprecated)", func() {
+		Expect(env.Execute("add", "c", "-fc", "--file", ARCH, "testdata/component-constructor-old.yaml")).To(Succeed())
+		Expect(env.DirExists(ARCH)).To(BeTrue())
+		CheckComponent(env, nil)
+	})
+
 	It("creates ctf and adds components", func() {
 		Expect(env.Execute("add", "c", "-fc", "--file", ARCH, "--version", "1.0.0", "testdata/component-constructor.yaml")).To(Succeed())
 		Expect(env.DirExists(ARCH)).To(BeTrue())
diff --git a/cmds/ocm/commands/ocmcmds/components/add/testdata/component-constructor-old.yaml b/cmds/ocm/commands/ocmcmds/components/add/testdata/component-constructor-old.yaml
new file mode 100644
index 0000000000..fe09093721
--- /dev/null
+++ b/cmds/ocm/commands/ocmcmds/components/add/testdata/component-constructor-old.yaml
@@ -0,0 +1,34 @@
+name: ocm.software/demo/test
+version: 1.0.0
+provider:
+  name: ocm.software
+  labels:
+    - name: city
+      value: Karlsruhe
+labels:
+  - name: purpose
+    value: test
+
+resources:
+  - name: text
+    type: PlainText
+    labels:
+      - name: city
+        value: Karlsruhe
+        merge:
+          algorithm: default
+          config:
+            overwrite: inbound
+    input:
+      type: file
+      path: testdata
+  - name: data
+    type: PlainText
+    input:
+      type: binary
+      data: IXN0cmluZ2RhdGE=
+
+componentReferences:
+  - name: ref
+    version: v1
+    componentName: github.com/mandelsoft/test2
diff --git a/cmds/ocm/commands/ocmcmds/components/add/testdata/component-constructor.yaml b/cmds/ocm/commands/ocmcmds/components/add/testdata/component-constructor.yaml
index fe09093721..5145f331ed 100644
--- a/cmds/ocm/commands/ocmcmds/components/add/testdata/component-constructor.yaml
+++ b/cmds/ocm/commands/ocmcmds/components/add/testdata/component-constructor.yaml
@@ -28,7 +28,7 @@ resources:
       type: binary
       data: IXN0cmluZ2RhdGE=
 
-componentReferences:
+references:
   - name: ref
     version: v1
     componentName: github.com/mandelsoft/test2
diff --git a/cmds/ocm/commands/ocmcmds/components/add/testdata/component-dup-ref.yaml b/cmds/ocm/commands/ocmcmds/components/add/testdata/component-dup-ref.yaml
index e8bd8c4a6c..c1969bf374 100644
--- a/cmds/ocm/commands/ocmcmds/components/add/testdata/component-dup-ref.yaml
+++ b/cmds/ocm/commands/ocmcmds/components/add/testdata/component-dup-ref.yaml
@@ -28,7 +28,7 @@ resources:
       type: binary
       data: IXN0cmluZ2RhdGE=
 
-componentReferences:
+references:
   - name: ref
     version: v1
     componentName: github.com/mandelsoft/test2
diff --git a/cmds/ocm/commands/ocmcmds/components/add/testdata/component-dup-res.yaml b/cmds/ocm/commands/ocmcmds/components/add/testdata/component-dup-res.yaml
index e7349b9876..b314503dac 100644
--- a/cmds/ocm/commands/ocmcmds/components/add/testdata/component-dup-res.yaml
+++ b/cmds/ocm/commands/ocmcmds/components/add/testdata/component-dup-res.yaml
@@ -33,7 +33,7 @@ resources:
       type: binary
       data: IXN0cmluZ2RhdGE=
 
-componentReferences:
+references:
   - name: ref
     version: v1
     componentName: github.com/mandelsoft/test2
diff --git a/cmds/ocm/commands/ocmcmds/components/add/testdata/component-dup-src.yaml b/cmds/ocm/commands/ocmcmds/components/add/testdata/component-dup-src.yaml
index 5179cb01ff..05444e9c9b 100644
--- a/cmds/ocm/commands/ocmcmds/components/add/testdata/component-dup-src.yaml
+++ b/cmds/ocm/commands/ocmcmds/components/add/testdata/component-dup-src.yaml
@@ -40,7 +40,7 @@ resources:
       type: binary
       data: IXN0cmluZ2RhdGE=
 
-componentReferences:
+references:
   - name: ref
     version: v1
     componentName: github.com/mandelsoft/test2
diff --git a/cmds/ocm/commands/ocmcmds/components/add/testdata/components-dup.yaml b/cmds/ocm/commands/ocmcmds/components/add/testdata/components-dup.yaml
index 7b48dec46f..d887b96007 100644
--- a/cmds/ocm/commands/ocmcmds/components/add/testdata/components-dup.yaml
+++ b/cmds/ocm/commands/ocmcmds/components/add/testdata/components-dup.yaml
@@ -27,7 +27,7 @@ components:
       input:
         type: binary
         data: IXN0cmluZ2RhdGE=
-  componentReferences:
+  references:
     - name: ref
       version: v1
       componentName: github.com/mandelsoft/test2
diff --git a/cmds/ocm/commands/ocmcmds/components/add/testdata/components.yaml b/cmds/ocm/commands/ocmcmds/components/add/testdata/components.yaml
index c19b40404e..3933e6a4fd 100644
--- a/cmds/ocm/commands/ocmcmds/components/add/testdata/components.yaml
+++ b/cmds/ocm/commands/ocmcmds/components/add/testdata/components.yaml
@@ -27,7 +27,7 @@ components:
       input:
         type: binary
         data: IXN0cmluZ2RhdGE=
-  componentReferences:
+  references:
     - name: ref
       version: v1
       componentName: github.com/mandelsoft/test2
\ No newline at end of file
diff --git a/components/helmdemo/component-constructor.yaml b/components/helmdemo/component-constructor.yaml
index 11f1c78a65..36725845e8 100644
--- a/components/helmdemo/component-constructor.yaml
+++ b/components/helmdemo/component-constructor.yaml
@@ -5,7 +5,7 @@ components:
       name: (( values.PROVIDER))
     # use all platforms and create a resource for each
 # ADD back once https://github.com/open-component-model/ocm/issues/1041 is fixed
-    componentReferences:
+    references:
       - name: installer
         componentName: (( values.HELMINSTCOMP ))
         version: (( values.HELMINSTVERSION ))
diff --git a/components/subchartsdemo/component-constructor.yaml b/components/subchartsdemo/component-constructor.yaml
index 7f0a7ec51f..8a469048d7 100644
--- a/components/subchartsdemo/component-constructor.yaml
+++ b/components/subchartsdemo/component-constructor.yaml
@@ -7,7 +7,7 @@ components:
   version: ${VERSION}
   provider:
     name: ${PROVIDER}
-  componentReferences:
+  references:
   - name: echoserver
     componentName:  ${COMPONENT_PREFIX}/echoserver
     version: "${ECHO_VERSION}"

From d6a59943ef48178783ffd28b862c5e1c62ca50ca Mon Sep 17 00:00:00 2001
From: Uwe Krueger 
Date: Wed, 6 Nov 2024 12:00:00 +0100
Subject: [PATCH 29/58] fix artifact set tagging (#1033)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit


#### What this PR does / why we need it
Because the new OCI references now always contain the digest in addition
to the tag, the artifactset creation
is not able anymore to provide appropriate meta data.

This is fixed by a new ArtVersion type able to handle the combination of
digest and tag.

#### Which issue(s) this PR fixes


---------

Co-authored-by: Jakob Möller 
---
 api/oci/art_test.go                           |  8 +-
 .../artifactset/utils_synthesis.go            | 10 +-
 api/oci/ociutils/ref.go                       | 97 +++++++++++++++++++
 api/oci/ref.go                                | 48 +++++----
 api/oci/ref_test.go                           | 83 +++++++++++-----
 api/oci/testhelper/manifests.go               |  6 +-
 .../accessmethods/ociartifact/method.go       |  4 +-
 .../relativeociref/method_test.go             |  2 +-
 .../handlers/oci/ocirepo/handler_test.go      |  2 +-
 .../download/handlers/ocirepo/handler.go      | 25 ++---
 api/ocm/tools/signing/transport_test.go       |  2 +-
 .../common/handlers/artifacthdlr/closure.go   |  2 +-
 .../handlers/artifacthdlr/typehandler.go      |  2 +-
 13 files changed, 214 insertions(+), 77 deletions(-)
 create mode 100644 api/oci/ociutils/ref.go

diff --git a/api/oci/art_test.go b/api/oci/art_test.go
index d118fb22ab..5305930dc4 100644
--- a/api/oci/art_test.go
+++ b/api/oci/art_test.go
@@ -15,7 +15,7 @@ func CheckArt(ref string, exp *oci.ArtSpec) {
 		Expect(err).To(HaveOccurred())
 	} else {
 		Expect(err).To(Succeed())
-		Expect(spec).To(Equal(*exp))
+		Expect(spec).To(Equal(exp))
 	}
 }
 
@@ -26,9 +26,9 @@ var _ = Describe("art parsing", func() {
 	It("succeeds", func() {
 		CheckArt("ubuntu", &oci.ArtSpec{Repository: "ubuntu"})
 		CheckArt("ubuntu/test", &oci.ArtSpec{Repository: "ubuntu/test"})
-		CheckArt("ubuntu/test@"+digest.String(), &oci.ArtSpec{Repository: "ubuntu/test", Digest: &digest})
-		CheckArt("ubuntu/test:"+tag, &oci.ArtSpec{Repository: "ubuntu/test", Tag: &tag})
-		CheckArt("ubuntu/test:"+tag+"@"+digest.String(), &oci.ArtSpec{Repository: "ubuntu/test", Digest: &digest, Tag: &tag})
+		CheckArt("ubuntu/test@"+digest.String(), &oci.ArtSpec{Repository: "ubuntu/test", ArtVersion: oci.ArtVersion{Digest: &digest}})
+		CheckArt("ubuntu/test:"+tag, &oci.ArtSpec{Repository: "ubuntu/test", ArtVersion: oci.ArtVersion{Tag: &tag}})
+		CheckArt("ubuntu/test:"+tag+"@"+digest.String(), &oci.ArtSpec{Repository: "ubuntu/test", ArtVersion: oci.ArtVersion{Digest: &digest, Tag: &tag}})
 	})
 
 	It("fails", func() {
diff --git a/api/oci/extensions/repositories/artifactset/utils_synthesis.go b/api/oci/extensions/repositories/artifactset/utils_synthesis.go
index 2a6bd5641b..74165c1154 100644
--- a/api/oci/extensions/repositories/artifactset/utils_synthesis.go
+++ b/api/oci/extensions/repositories/artifactset/utils_synthesis.go
@@ -11,6 +11,7 @@ import (
 
 	"ocm.software/ocm/api/oci/artdesc"
 	"ocm.software/ocm/api/oci/cpi"
+	"ocm.software/ocm/api/oci/ociutils"
 	"ocm.software/ocm/api/oci/tools/transfer"
 	"ocm.software/ocm/api/oci/tools/transfer/filters"
 	"ocm.software/ocm/api/utils/accessio"
@@ -92,14 +93,19 @@ func SynthesizeArtifactBlobForArtifact(art cpi.ArtifactAccess, ref string, filte
 		return nil, err
 	}
 
+	vers, err := ociutils.ParseVersion(ref)
+	if err != nil {
+		return nil, err
+	}
+
 	return SythesizeArtifactSet(func(set *ArtifactSet) (string, error) {
 		dig, err := transfer.TransferArtifactWithFilter(art, set, filters.And(filter...))
 		if err != nil {
 			return "", fmt.Errorf("failed to transfer artifact: %w", err)
 		}
 
-		if ok, _ := artdesc.IsDigest(ref); !ok {
-			err = set.AddTags(*dig, ref)
+		if ok := vers.IsTagged(); ok {
+			err = set.AddTags(*dig, vers.GetTag())
 			if err != nil {
 				return "", fmt.Errorf("failed to add tag: %w", err)
 			}
diff --git a/api/oci/ociutils/ref.go b/api/oci/ociutils/ref.go
new file mode 100644
index 0000000000..50f7675264
--- /dev/null
+++ b/api/oci/ociutils/ref.go
@@ -0,0 +1,97 @@
+package ociutils
+
+import (
+	"strings"
+
+	"github.com/mandelsoft/goutils/generics"
+	"github.com/opencontainers/go-digest"
+)
+
+// ParseVersion parses the version part of an OCI reference consisting
+// of an optional tag and/or digest.
+func ParseVersion(vers string) (*ArtVersion, error) {
+	if strings.HasPrefix(vers, "@") {
+		dig, err := digest.Parse(vers[1:])
+		if err != nil {
+			return nil, err
+		}
+		return &ArtVersion{
+			Digest: &dig,
+		}, nil
+	}
+
+	i := strings.Index(vers, "@")
+	if i > 0 {
+		dig, err := digest.Parse(vers[i+1:])
+		if err != nil {
+			return nil, err
+		}
+		return &ArtVersion{
+			Tag:    generics.Pointer(vers[:i]),
+			Digest: &dig,
+		}, nil
+	}
+	return &ArtVersion{
+		Tag: &vers,
+	}, nil
+}
+
+// ArtVersion is the version part of an OCI reference consisting of an
+// optional tag and/or digest. Both parts may be nil, if a reference
+// does not include a version part.
+// Such objects are sub objects of (oci.)ArtSpec, which has be moved
+// to separate package to avoid package cycles. The methods are
+// derived from ArtSpec.
+type ArtVersion struct {
+	// +optional
+	Tag *string `json:"tag,omitempty"`
+	// +optional
+	Digest *digest.Digest `json:"digest,omitempty"`
+}
+
+func (v *ArtVersion) VersionSpec() string {
+	if v != nil {
+		return ""
+	}
+
+	vers := ""
+	if v.Tag != nil {
+		vers = *v.Tag
+	}
+
+	if v.Digest != nil {
+		vers += "@" + string(*v.Digest)
+	}
+	if vers == "" {
+		return "latest"
+	}
+	return vers
+}
+
+// IsVersion returns true, if the object ref is given
+// and describes a dedicated version, either by tag or digest.
+// As part of the ArtSpec type in oci, it might describe
+// no version part. THis method indicates, whether a version part
+// is present.
+func (v *ArtVersion) IsVersion() bool {
+	if v == nil {
+		return false
+	}
+	return v.Tag != nil || v.Digest != nil
+}
+
+func (v *ArtVersion) IsTagged() bool {
+	return v != nil && v.Tag != nil
+}
+
+func (v *ArtVersion) IsDigested() bool {
+	return v != nil && v.Digest != nil
+}
+
+func (v *ArtVersion) GetTag() string {
+	if v != nil &&
+		v.Tag != nil {
+		return *v.Tag
+	}
+	return ""
+}
diff --git a/api/oci/ref.go b/api/oci/ref.go
index 457eef3f1e..20186d78c9 100644
--- a/api/oci/ref.go
+++ b/api/oci/ref.go
@@ -8,6 +8,7 @@ import (
 	"github.com/opencontainers/go-digest"
 
 	"ocm.software/ocm/api/oci/grammar"
+	"ocm.software/ocm/api/oci/ociutils"
 )
 
 // to find a suitable secret for images on Docker Hub, we need its two domains to do matching.
@@ -224,11 +225,18 @@ func (r RefSpec) DeepCopy() RefSpec {
 
 ////////////////////////////////////////////////////////////////////////////////
 
-func ParseArt(art string) (ArtSpec, error) {
+// ParseVersion parses an OCI version part of an OCI reference.
+// It has to be placed in a utils package to avoid package cycles
+// for particular users.
+func ParseVersion(vers string) (*ArtVersion, error) {
+	return ociutils.ParseVersion(vers)
+}
+
+func ParseArt(art string) (*ArtSpec, error) {
 	match := grammar.AnchoredArtifactVersionRegexp.FindSubmatch([]byte(art))
 
 	if match == nil {
-		return ArtSpec{}, errors.ErrInvalid(KIND_ARETEFACT_REFERENCE, art)
+		return nil, errors.ErrInvalid(KIND_ARETEFACT_REFERENCE, art)
 	}
 	var tag *string
 	var dig *digest.Digest
@@ -241,25 +249,27 @@ func ParseArt(art string) (ArtSpec, error) {
 		t := string(match[3])
 		d, err := digest.Parse(t)
 		if err != nil {
-			return ArtSpec{}, errors.ErrInvalidWrap(err, KIND_ARETEFACT_REFERENCE, art)
+			return nil, errors.ErrInvalidWrap(err, KIND_ARETEFACT_REFERENCE, art)
 		}
 		dig = &d
 	}
-	return ArtSpec{
+	return &ArtSpec{
 		Repository: string(match[1]),
-		Tag:        tag,
-		Digest:     dig,
+		ArtVersion: ArtVersion{
+			Tag:    tag,
+			Digest: dig,
+		},
 	}, nil
 }
 
+type ArtVersion = ociutils.ArtVersion
+
 // ArtSpec is a go internal representation of a oci reference.
 type ArtSpec struct {
 	// Repository is the part of a reference without its hostname
 	Repository string `json:"repository"`
-	// +optional
-	Tag *string `json:"tag,omitempty"`
-	// +optional
-	Digest *digest.Digest `json:"digest,omitempty"`
+	// artifact version
+	ArtVersion `json:",inline"`
 }
 
 func (r *ArtSpec) Version() string {
@@ -276,22 +286,10 @@ func (r *ArtSpec) IsRegistry() bool {
 	return r.Repository == ""
 }
 
-func (r *ArtSpec) IsVersion() bool {
-	return r.Tag != nil || r.Digest != nil
-}
-
-func (r *ArtSpec) IsTagged() bool {
-	return r.Tag != nil
-}
-
-func (r *ArtSpec) GetTag() string {
-	if r.Tag != nil {
-		return *r.Tag
-	}
-	return ""
-}
-
 func (r *ArtSpec) String() string {
+	if r == nil {
+		return ""
+	}
 	s := r.Repository
 	if r.Tag != nil {
 		s += fmt.Sprintf(":%s", *r.Tag)
diff --git a/api/oci/ref_test.go b/api/oci/ref_test.go
index a62abd3c18..f0d27516c5 100644
--- a/api/oci/ref_test.go
+++ b/api/oci/ref_test.go
@@ -3,6 +3,7 @@ package oci_test
 import (
 	"strings"
 
+	"github.com/mandelsoft/goutils/generics"
 	. "github.com/mandelsoft/goutils/testutils"
 	. "github.com/onsi/ginkgo/v2"
 	. "github.com/onsi/gomega"
@@ -143,8 +144,7 @@ var _ = Describe("ref parsing", func() {
 											},
 											ArtSpec: oci.ArtSpec{
 												Repository: r,
-												Tag:        Pointer([]byte(uv)),
-												Digest:     Dig([]byte(ud)),
+												ArtVersion: oci.ArtVersion{Tag: Pointer([]byte(uv)), Digest: Dig([]byte(ud))},
 											},
 										})
 									})
@@ -192,8 +192,10 @@ var _ = Describe("ref parsing", func() {
 													},
 													ArtSpec: oci.ArtSpec{
 														Repository: r,
-														Tag:        Pointer([]byte(uv)),
-														Digest:     Dig([]byte(ud)),
+														ArtVersion: oci.ArtVersion{
+															Tag:    Pointer([]byte(uv)),
+															Digest: Dig([]byte(ud)),
+														},
 													},
 												})
 											})
@@ -253,8 +255,8 @@ var _ = Describe("ref parsing", func() {
 												},
 												ArtSpec: oci.ArtSpec{
 													Repository: r,
-													Tag:        Pointer([]byte(uv)),
-													Digest:     Dig([]byte(ud)),
+													ArtVersion: oci.ArtVersion{Tag: Pointer([]byte(uv)),
+														Digest: Dig([]byte(ud))},
 												},
 											})
 										})
@@ -291,8 +293,8 @@ var _ = Describe("ref parsing", func() {
 												},
 												ArtSpec: oci.ArtSpec{
 													Repository: r,
-													Tag:        Pointer([]byte(uv)),
-													Digest:     Dig([]byte(ud)),
+													ArtVersion: oci.ArtVersion{Tag: Pointer([]byte(uv)),
+														Digest: Dig([]byte(ud))},
 												},
 											})
 										})
@@ -341,8 +343,8 @@ var _ = Describe("ref parsing", func() {
 										},
 										ArtSpec: oci.ArtSpec{
 											Repository: r,
-											Tag:        Pointer([]byte(uv)),
-											Digest:     Dig([]byte(ud)),
+											ArtVersion: oci.ArtVersion{Tag: Pointer([]byte(uv)),
+												Digest: Dig([]byte(ud))},
 										},
 									})
 								})
@@ -380,8 +382,8 @@ var _ = Describe("ref parsing", func() {
 							},
 							ArtSpec: oci.ArtSpec{
 								Repository: "library/" + r,
-								Tag:        Pointer([]byte(uv)),
-								Digest:     Dig([]byte(ud)),
+								ArtVersion: oci.ArtVersion{Tag: Pointer([]byte(uv)),
+									Digest: Dig([]byte(ud))},
 							},
 						})
 					})
@@ -416,8 +418,8 @@ var _ = Describe("ref parsing", func() {
 							},
 							ArtSpec: oci.ArtSpec{
 								Repository: r,
-								Tag:        Pointer([]byte(uv)),
-								Digest:     Dig([]byte(ud)),
+								ArtVersion: oci.ArtVersion{Tag: Pointer([]byte(uv)),
+									Digest: Dig([]byte(ud))},
 							},
 						})
 					})
@@ -565,20 +567,20 @@ var _ = Describe("ref parsing", func() {
 	})
 	It("succeeds", func() {
 		CheckRef("ubuntu", &oci.RefSpec{UniformRepositorySpec: docker, ArtSpec: oci.ArtSpec{Repository: "library/ubuntu"}})
-		CheckRef("ubuntu:v1", &oci.RefSpec{UniformRepositorySpec: docker, ArtSpec: oci.ArtSpec{Repository: "library/ubuntu", Tag: &tag}})
+		CheckRef("ubuntu:v1", &oci.RefSpec{UniformRepositorySpec: docker, ArtSpec: oci.ArtSpec{Repository: "library/ubuntu", ArtVersion: oci.ArtVersion{Tag: &tag}}})
 		CheckRef("test/ubuntu", &oci.RefSpec{UniformRepositorySpec: docker, ArtSpec: oci.ArtSpec{Repository: "test/ubuntu"}})
 		CheckRef("test_test/ubuntu", &oci.RefSpec{UniformRepositorySpec: docker, ArtSpec: oci.ArtSpec{Repository: "test_test/ubuntu"}})
 		CheckRef("test__test/ubuntu", &oci.RefSpec{UniformRepositorySpec: docker, ArtSpec: oci.ArtSpec{Repository: "test__test/ubuntu"}})
 		CheckRef("test-test/ubuntu", &oci.RefSpec{UniformRepositorySpec: docker, ArtSpec: oci.ArtSpec{Repository: "test-test/ubuntu"}})
 		CheckRef("test--test/ubuntu", &oci.RefSpec{UniformRepositorySpec: docker, ArtSpec: oci.ArtSpec{Repository: "test--test/ubuntu"}})
 		CheckRef("test-----test/ubuntu", &oci.RefSpec{UniformRepositorySpec: docker, ArtSpec: oci.ArtSpec{Repository: "test-----test/ubuntu"}})
-		CheckRef("test/ubuntu:v1", &oci.RefSpec{UniformRepositorySpec: docker, ArtSpec: oci.ArtSpec{Repository: "test/ubuntu", Tag: &tag}})
+		CheckRef("test/ubuntu:v1", &oci.RefSpec{UniformRepositorySpec: docker, ArtSpec: oci.ArtSpec{Repository: "test/ubuntu", ArtVersion: oci.ArtVersion{Tag: &tag}}})
 		CheckRef("ghcr.io/test/ubuntu", &oci.RefSpec{UniformRepositorySpec: ghcr, ArtSpec: oci.ArtSpec{Repository: "test/ubuntu"}})
 		CheckRef("ghcr.io/test", &oci.RefSpec{UniformRepositorySpec: ghcr, ArtSpec: oci.ArtSpec{Repository: "test"}})
 		CheckRef("ghcr.io:8080/test/ubuntu", &oci.RefSpec{UniformRepositorySpec: oci.UniformRepositorySpec{Host: "ghcr.io:8080"}, ArtSpec: oci.ArtSpec{Repository: "test/ubuntu"}})
-		CheckRef("ghcr.io/test/ubuntu:v1", &oci.RefSpec{UniformRepositorySpec: ghcr, ArtSpec: oci.ArtSpec{Repository: "test/ubuntu", Tag: &tag}})
-		CheckRef("ghcr.io/test/ubuntu@sha256:3d05e105e350edf5be64fe356f4906dd3f9bf442a279e4142db9879bba8e677a", &oci.RefSpec{UniformRepositorySpec: ghcr, ArtSpec: oci.ArtSpec{Repository: "test/ubuntu", Digest: &digest}})
-		CheckRef("ghcr.io/test/ubuntu:v1@sha256:3d05e105e350edf5be64fe356f4906dd3f9bf442a279e4142db9879bba8e677a", &oci.RefSpec{UniformRepositorySpec: ghcr, ArtSpec: oci.ArtSpec{Repository: "test/ubuntu", Tag: &tag, Digest: &digest}})
+		CheckRef("ghcr.io/test/ubuntu:v1", &oci.RefSpec{UniformRepositorySpec: ghcr, ArtSpec: oci.ArtSpec{Repository: "test/ubuntu", ArtVersion: oci.ArtVersion{Tag: &tag}}})
+		CheckRef("ghcr.io/test/ubuntu@sha256:3d05e105e350edf5be64fe356f4906dd3f9bf442a279e4142db9879bba8e677a", &oci.RefSpec{UniformRepositorySpec: ghcr, ArtSpec: oci.ArtSpec{Repository: "test/ubuntu", ArtVersion: oci.ArtVersion{Digest: &digest}}})
+		CheckRef("ghcr.io/test/ubuntu:v1@sha256:3d05e105e350edf5be64fe356f4906dd3f9bf442a279e4142db9879bba8e677a", &oci.RefSpec{UniformRepositorySpec: ghcr, ArtSpec: oci.ArtSpec{Repository: "test/ubuntu", ArtVersion: oci.ArtVersion{Tag: &tag, Digest: &digest}}})
 		CheckRef("test___test/ubuntu", &oci.RefSpec{
 			UniformRepositorySpec: oci.UniformRepositorySpec{
 				Info: "test___test/ubuntu",
@@ -594,8 +596,8 @@ var _ = Describe("ref parsing", func() {
 			},
 			ArtSpec: oci.ArtSpec{
 				Repository: "repo/repo",
-				Tag:        &tag,
-				Digest:     &digest,
+				ArtVersion: oci.ArtVersion{Tag: &tag,
+					Digest: &digest},
 			},
 		})
 		CheckRef("http://127.0.0.1:443/repo/repo:v1@"+digest.String(), &oci.RefSpec{
@@ -607,8 +609,8 @@ var _ = Describe("ref parsing", func() {
 			},
 			ArtSpec: oci.ArtSpec{
 				Repository: "repo/repo",
-				Tag:        &tag,
-				Digest:     &digest,
+				ArtVersion: oci.ArtVersion{Tag: &tag,
+					Digest: &digest},
 			},
 		})
 		CheckRef("directory::a/b", &oci.RefSpec{
@@ -695,7 +697,7 @@ var _ = Describe("ref parsing", func() {
 			},
 			ArtSpec: oci.ArtSpec{
 				Repository: "mandelsoft/test",
-				Tag:        &tag,
+				ArtVersion: oci.ArtVersion{Tag: &tag},
 			},
 		})
 		CheckRef("/tmp/ctf", &oci.RefSpec{
@@ -722,7 +724,7 @@ var _ = Describe("ref parsing", func() {
 			},
 			ArtSpec: oci.ArtSpec{
 				Repository: "repo",
-				Tag:        &tag,
+				ArtVersion: oci.ArtVersion{Tag: &tag},
 			},
 		})
 		ref := Must(oci.ParseRef("OCIRegistry::{\"type\":\"OCIRegistry\", \"baseUrl\": \"test.com\"}//repo:1.0.0"))
@@ -745,7 +747,7 @@ var _ = Describe("ref parsing", func() {
 			},
 			ArtSpec: oci.ArtSpec{
 				Repository: "repo",
-				Tag:        &tag,
+				ArtVersion: oci.ArtVersion{Tag: &tag},
 			},
 		})
 		ref := Must(oci.ParseRef("oci::{\"type\":\"OCIRegistry\", \"baseUrl\": \"test.com\"}//repo:1.0.0"))
@@ -826,4 +828,33 @@ var _ = Describe("ref parsing", func() {
 		spec := Must(ctx.MapUniformRepositorySpec(&ref))
 		Expect(spec).To(Equal(Must(ctf.NewRepositorySpec(accessobj.ACC_WRITABLE, "./file/path"))))
 	})
+
+	Context("version", func() {
+		It("parses tag", func() {
+			v := Must(oci.ParseVersion("tag"))
+
+			Expect(v).To(Equal(&oci.ArtVersion{
+				Tag:    generics.Pointer("tag"),
+				Digest: nil,
+			}))
+		})
+
+		It("parses digest", func() {
+			v := Must(oci.ParseVersion("@sha256:3d05e105e350edf5be64fe356f4906dd3f9bf442a279e4142db9879bba8e677a"))
+
+			Expect(v).To(Equal(&oci.ArtVersion{
+				Tag:    nil,
+				Digest: generics.Pointer(godigest.Digest("sha256:3d05e105e350edf5be64fe356f4906dd3f9bf442a279e4142db9879bba8e677a")),
+			}))
+		})
+
+		It("parses tag+digest", func() {
+			v := Must(oci.ParseVersion("tag@sha256:3d05e105e350edf5be64fe356f4906dd3f9bf442a279e4142db9879bba8e677a"))
+
+			Expect(v).To(Equal(&oci.ArtVersion{
+				Tag:    generics.Pointer("tag"),
+				Digest: generics.Pointer(godigest.Digest("sha256:3d05e105e350edf5be64fe356f4906dd3f9bf442a279e4142db9879bba8e677a")),
+			}))
+		})
+	})
 })
diff --git a/api/oci/testhelper/manifests.go b/api/oci/testhelper/manifests.go
index 824ab871fd..44b92c12cd 100644
--- a/api/oci/testhelper/manifests.go
+++ b/api/oci/testhelper/manifests.go
@@ -64,7 +64,8 @@ func OCIArtifactResource1(env *builder.Builder, name string, host string, funcs
 
 const (
 	D_OCIMANIFEST1     = "0c4abdb72cf59cb4b77f4aacb4775f9f546ebc3face189b2224a966c8826ca9f"
-	H_OCIARCHMANIFEST1 = "b0692bcec00e0a875b6b280f3209d6776f3eca128adcb7e81e82fd32127c0c62"
+	H_OCIARCHMANIFEST1 = "818fb6a69a5f55e8b3dbc921a61fdd000b9445a745b587ba753a811b02426326"
+	// H_OCIARCHMANIFEST1 = "b0692bcec00e0a875b6b280f3209d6776f3eca128adcb7e81e82fd32127c0c62".
 )
 
 var DS_OCIMANIFEST1 = &metav1.DigestSpec{
@@ -123,7 +124,8 @@ func OCIManifest2For(env *builder.Builder, ns, tag string, nested ...func()) (*a
 
 const (
 	D_OCIMANIFEST2     = "c2d2dca275c33c1270dea6168a002d67c0e98780d7a54960758139ae19984bd7"
-	H_OCIARCHMANIFEST2 = "cb85cd58b10e36343971691abbfe40200cb645c6e95f0bdabd111a30cf794708"
+	H_OCIARCHMANIFEST2 = "2aaf6f8857dcbfa04a72fb98dd53f649b46e5d81aa4fb17330df74b0ffc30839"
+	// H_OCIARCHMANIFEST2 = "cb85cd58b10e36343971691abbfe40200cb645c6e95f0bdabd111a30cf794708".
 )
 
 func HashManifest2(fmt string) string {
diff --git a/api/ocm/extensions/accessmethods/ociartifact/method.go b/api/ocm/extensions/accessmethods/ociartifact/method.go
index b31ca9d611..a8cb908410 100644
--- a/api/ocm/extensions/accessmethods/ociartifact/method.go
+++ b/api/ocm/extensions/accessmethods/ociartifact/method.go
@@ -247,7 +247,7 @@ func (m *accessMethod) eval(relto oci.Repository) error {
 		}
 		ref = oci.RefSpec{
 			UniformRepositorySpec: *repo.GetSpecification().UniformRepositorySpec(),
-			ArtSpec:               art,
+			ArtSpec:               *art,
 		}
 		m.repo = repo
 	}
@@ -355,7 +355,7 @@ func (m *accessMethod) getBlob() (artifactset.ArtifactBlob, error) {
 	}
 	logger := Logger(WrapContextProvider(m.ctx))
 	logger.Info("synthesize artifact blob", "ref", m.reference)
-	m.blob, err = artifactset.SynthesizeArtifactBlobForArtifact(m.art, m.ref.Version())
+	m.blob, err = artifactset.SynthesizeArtifactBlobForArtifact(m.art, m.ref.VersionSpec())
 	logger.Info("synthesize artifact blob done", "ref", m.reference, "error", logging.ErrorMessage(err))
 	if err != nil {
 		m.err = err
diff --git a/api/ocm/extensions/accessmethods/relativeociref/method_test.go b/api/ocm/extensions/accessmethods/relativeociref/method_test.go
index 4634480fc9..2e589770c0 100644
--- a/api/ocm/extensions/accessmethods/relativeociref/method_test.go
+++ b/api/ocm/extensions/accessmethods/relativeociref/method_test.go
@@ -68,7 +68,7 @@ var _ = Describe("Method", func() {
 			return m.Close()
 		})
 		data := Must(m.Get())
-		Expect(len(data)).To(Equal(628))
+		Expect(len(data)).To(Equal(630))
 		Expect(accspeccpi.GetAccessMethodImplementation(m).(blobaccess.DigestSource).Digest().String()).To(Equal("sha256:0c4abdb72cf59cb4b77f4aacb4775f9f546ebc3face189b2224a966c8826ca9f"))
 		Expect(utils.GetOCIArtifactRef(env, res)).To(Equal("ocm/value:v2.0"))
 	})
diff --git a/api/ocm/extensions/blobhandler/handlers/oci/ocirepo/handler_test.go b/api/ocm/extensions/blobhandler/handlers/oci/ocirepo/handler_test.go
index 66fec9df12..6fc5155f25 100644
--- a/api/ocm/extensions/blobhandler/handlers/oci/ocirepo/handler_test.go
+++ b/api/ocm/extensions/blobhandler/handlers/oci/ocirepo/handler_test.go
@@ -125,7 +125,7 @@ var _ = Describe("oci artifact transfer", func() {
 			data := Must(json.Marshal(comp.GetDescriptor().Resources[1].Access))
 
 			fmt.Printf("%s\n", string(data))
-			Expect(string(data)).To(StringEqualWithContext(`{"globalAccess":{"imageReference":"baseurl.io/ocm/value:v2.0@sha256:` + D_OCIMANIFEST1 + `","type":"ociArtifact"},"localReference":"sha256:b0692bcec00e0a875b6b280f3209d6776f3eca128adcb7e81e82fd32127c0c62","mediaType":"application/vnd.oci.image.manifest.v1+tar+gzip","referenceName":"ocm/value:v2.0","type":"localBlob"}`))
+			Expect(string(data)).To(StringEqualWithContext(`{"globalAccess":{"imageReference":"baseurl.io/ocm/value:v2.0@sha256:` + D_OCIMANIFEST1 + `","type":"ociArtifact"},"localReference":"sha256:` + H_OCIARCHMANIFEST1 + `","mediaType":"application/vnd.oci.image.manifest.v1+tar+gzip","referenceName":"ocm/value:v2.0","type":"localBlob"}`))
 			ocirepo := genericocireg.GetOCIRepository(tgt)
 			Expect(ocirepo).NotTo(BeNil())
 
diff --git a/api/ocm/extensions/download/handlers/ocirepo/handler.go b/api/ocm/extensions/download/handlers/ocirepo/handler.go
index 269a9bb0ab..b6b8dcad66 100644
--- a/api/ocm/extensions/download/handlers/ocirepo/handler.go
+++ b/api/ocm/extensions/download/handlers/ocirepo/handler.go
@@ -78,7 +78,7 @@ func (h *handler) Download(p common.Printer, racc cpi.ResourceAccess, path strin
 
 	ocictx := ctx.OCIContext()
 
-	var artspec oci.ArtSpec
+	var artspec *oci.ArtSpec
 	var prefix string
 	var result oci.RefSpec
 
@@ -101,7 +101,7 @@ func (h *handler) Download(p common.Printer, racc cpi.ResourceAccess, path strin
 			return true, "", err
 		}
 		finalize.Close(repo, "repository for downloading OCI artifact")
-		artspec = ref.ArtSpec
+		artspec = &ref.ArtSpec
 	} else {
 		log.Debug("evaluating config")
 		if path != "" {
@@ -117,16 +117,19 @@ func (h *handler) Download(p common.Printer, racc cpi.ResourceAccess, path strin
 		}
 		result.UniformRepositorySpec = *us
 	}
-	log.Debug("using artifact spec", "spec", artspec.String())
-	if artspec.Digest != nil {
-		return true, "", fmt.Errorf("digest not possible for target")
-	}
 
-	if artspec.Repository != "" {
-		namespace = artspec.Repository
-	}
-	if artspec.IsTagged() {
-		tag = *artspec.Tag
+	if artspec != nil {
+		log.Debug("using artifact spec", "spec", artspec.String())
+		if artspec.IsDigested() {
+			return true, "", fmt.Errorf("digest not possible for target")
+		}
+
+		if artspec.Repository != "" {
+			namespace = artspec.Repository
+		}
+		if artspec.IsTagged() {
+			tag = *artspec.Tag
+		}
 	}
 
 	if prefix != "" && namespace != "" {
diff --git a/api/ocm/tools/signing/transport_test.go b/api/ocm/tools/signing/transport_test.go
index 85323ce2bd..c5294e2d1d 100644
--- a/api/ocm/tools/signing/transport_test.go
+++ b/api/ocm/tools/signing/transport_test.go
@@ -168,7 +168,7 @@ var _ = Describe("transport and signing", func() {
 		ra := desc.GetResourceIndexByIdentity(metav1.NewIdentity("image"))
 		Expect(ra).To(BeNumerically(">=", 0))
 		// indeed, the artifact set archive hash seems to be reproducible
-		desc.Resources[ra].Access = localblob.New("sha256:b0692bcec00e0a875b6b280f3209d6776f3eca128adcb7e81e82fd32127c0c62", "ocm/value:v2.0", "application/vnd.oci.image.manifest.v1+tar+gzip", nil)
+		desc.Resources[ra].Access = localblob.New("sha256:"+H_OCIARCHMANIFEST1, "ocm/value:v2.0", "application/vnd.oci.image.manifest.v1+tar+gzip", nil)
 		Expect(tcv.GetDescriptor()).To(YAMLEqual(desc))
 
 		descSigned := tcv.GetDescriptor().Copy()
diff --git a/cmds/ocm/commands/ocicmds/common/handlers/artifacthdlr/closure.go b/cmds/ocm/commands/ocicmds/common/handlers/artifacthdlr/closure.go
index 978515dbe3..129a018a27 100644
--- a/cmds/ocm/commands/ocicmds/common/handlers/artifacthdlr/closure.go
+++ b/cmds/ocm/commands/ocicmds/common/handlers/artifacthdlr/closure.go
@@ -52,7 +52,7 @@ func traverse(hist common.History, o *Object, octx out.Context) []output.Object
 					UniformRepositorySpec: o.Spec.UniformRepositorySpec,
 					ArtSpec: oci.ArtSpec{
 						Repository: o.Spec.Repository,
-						Digest:     &ref.Digest,
+						ArtVersion: oci.ArtVersion{Digest: &ref.Digest},
 					},
 				},
 				Namespace: o.Namespace,
diff --git a/cmds/ocm/commands/ocicmds/common/handlers/artifacthdlr/typehandler.go b/cmds/ocm/commands/ocicmds/common/handlers/artifacthdlr/typehandler.go
index aa8aa34801..5d027b3fd8 100644
--- a/cmds/ocm/commands/ocicmds/common/handlers/artifacthdlr/typehandler.go
+++ b/cmds/ocm/commands/ocicmds/common/handlers/artifacthdlr/typehandler.go
@@ -192,7 +192,7 @@ func (h *TypeHandler) get(repo oci.Repository, elemspec utils.ElemSpec) ([]outpu
 			return result, nil
 		}
 	} else {
-		art := oci.ArtSpec{Repository: ""}
+		art := &oci.ArtSpec{Repository: ""}
 		if name != "" {
 			art, err = oci.ParseArt(name)
 			if err != nil {

From 2188c1ce78e3cf6aaede3d458388fa947891c581 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jakob=20M=C3=B6ller?= 
Date: Wed, 6 Nov 2024 12:17:58 +0100
Subject: [PATCH 30/58] chore: reuse aggregation from ctf during component
 build (#1044)


#### What this PR does / why we need it

this will create an aggregation post build that can be reused during
releases if necessary

#### Which issue(s) this PR fixes


This is a revision of the component build in preparation to reuse the
final CTF artifacts during our release

---------

Co-authored-by: Hilmar Falkenberg 
---
 .github/workflows/components.yaml | 198 +++++++++++-------------------
 Makefile                          |  18 ++-
 components/demoplugin/Makefile    |   2 +-
 components/ecrplugin/Makefile     |   2 +-
 components/ocmcli/Makefile        |   2 +-
 components/subchartsdemo/Makefile |   8 +-
 6 files changed, 89 insertions(+), 141 deletions(-)

diff --git a/.github/workflows/components.yaml b/.github/workflows/components.yaml
index dee82afeb0..ca944d5cfe 100644
--- a/.github/workflows/components.yaml
+++ b/.github/workflows/components.yaml
@@ -1,4 +1,4 @@
-name: component CTFs
+name: Components
 
 on:
   pull_request:
@@ -11,49 +11,33 @@ permissions:
   contents: read
   pull-requests: read
 
+env:
+  CTF_TYPE: directory
+  components: '["ocmcli", "helminstaller", "helmdemo", "subchartsdemo", "ecrplugin"]'
+
 jobs:
-  build-cli:
-    name: Build CLI
-    runs-on: large_runner
+  define-matrix:
+    runs-on: ubuntu-latest
+    outputs:
+      components: ${{ steps.componentMatrix.outputs.matrix }}
     steps:
-      - name: Checkout
-        uses: actions/checkout@v4
-      - name: Setup Go
-        uses: actions/setup-go@v5
-        with:
-          go-version-file: '${{ github.workspace }}/go.mod'
-          cache: false
-
-      - name: Get go environment for use with cache
+      - id: componentMatrix
+        name: Set Components to be used for Build
         run: |
-          echo "go_cache=$(go env GOCACHE)" >> $GITHUB_ENV
-          echo "go_modcache=$(go env GOMODCACHE)" >> $GITHUB_ENV
-      # This step will only reuse the go mod and build cache from main made during the Build,
-      # see push_ocm.yaml => "ocm-cli-latest" Job
-      # This means it never caches by itself and PRs cannot cause cache pollution / thrashing
-      # This is because we have huge storage requirements for our cache because of the mass of dependencies
-      - name: Restore / Reuse Cache from central build
-        id: cache-golang-restore
-        uses: actions/cache/restore@v4 # Only Restore, not build another cache (too big)
-        with:
-          path: |
-            ${{ env.go_cache }}
-            ${{ env.go_modcache }}
-          key: ${{ env.cache_name }}-${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}-${{ hashFiles('**/go.mod') }}
-          restore-keys: |
-            ${{ env.cache_name }}-${{ runner.os }}-go-
+          echo "matrix=$input" >> $GITHUB_OUTPUT
         env:
-          cache_name: ocm-cli-latest-go-cache # needs to be the same key in the end as in the build step
-
-      - name: CTF
-        run: |
-          cd components/ocmcli
-          PATH=$PATH:$(go env GOPATH)/bin make ctf
-
-  build-helminstaller:
-    name: Build HelmInstaller
+          input: ${{ env.components }}
+
+  build:
+    name: "Build"
+    needs: define-matrix
+    strategy:
+      matrix:
+        component: ${{fromJSON(needs.define-matrix.outputs.components)}}
     runs-on: large_runner
     steps:
+      - name: Self Hosted Runner Post Job Cleanup Action
+        uses: TooMuch4U/actions-clean@v2.2
       - name: Checkout
         uses: actions/checkout@v4
       - name: Setup Go
@@ -61,12 +45,10 @@ jobs:
         with:
           go-version-file: '${{ github.workspace }}/go.mod'
           cache: false
-
       - name: Get go environment for use with cache
         run: |
           echo "go_cache=$(go env GOCACHE)" >> $GITHUB_ENV
           echo "go_modcache=$(go env GOMODCACHE)" >> $GITHUB_ENV
-
       # This step will only reuse the go mod and build cache from main made during the Build,
       # see push_ocm.yaml => "ocm-cli-latest" Job
       # This means it never caches by itself and PRs cannot cause cache pollution / thrashing
@@ -83,16 +65,28 @@ jobs:
             ${{ env.cache_name }}-${{ runner.os }}-go-
         env:
           cache_name: ocm-cli-latest-go-cache # needs to be the same key in the end as in the build step
-
       - name: CTF
         run: |
-          cd components/helminstaller
-          PATH=$PATH:$(go env GOPATH)/bin make ctf
-
-  build-helmdemo:
-    name: Build HelmDemo
+          cd components/${{ matrix.component }}
+          PATH=$PATH:$(go env GOPATH)/bin CTF_TYPE=${{ env.CTF_TYPE }} make ctf descriptor describe
+      - name: Upload CTF
+        uses: actions/upload-artifact@v4
+        with:
+          if-no-files-found: error
+          overwrite: true
+          retention-days: 1
+          name: ctf-component-${{ matrix.component }}
+          path: gen/${{ matrix.component }}/ctf
+
+  aggregate:
+    name: "Aggregate"
     runs-on: large_runner
+    needs: [build, define-matrix]
+    env:
+      components: ${{ join(fromJSON(needs.define-matrix.outputs.components), ' ') }}
     steps:
+      - name: Self Hosted Runner Post Job Cleanup Action
+        uses: TooMuch4U/actions-clean@v2.2
       - name: Checkout
         uses: actions/checkout@v4
       - name: Setup Go
@@ -100,12 +94,10 @@ jobs:
         with:
           go-version-file: '${{ github.workspace }}/go.mod'
           cache: false
-
       - name: Get go environment for use with cache
         run: |
           echo "go_cache=$(go env GOCACHE)" >> $GITHUB_ENV
           echo "go_modcache=$(go env GOMODCACHE)" >> $GITHUB_ENV
-
       # This step will only reuse the go mod and build cache from main made during the Build,
       # see push_ocm.yaml => "ocm-cli-latest" Job
       # This means it never caches by itself and PRs cannot cause cache pollution / thrashing
@@ -122,89 +114,37 @@ jobs:
             ${{ env.cache_name }}-${{ runner.os }}-go-
         env:
           cache_name: ocm-cli-latest-go-cache # needs to be the same key in the end as in the build step
-
-      - name: CTF
-        run: |
-          cd components/helmdemo
-          PATH=$PATH:$(go env GOPATH)/bin make ctf
-
-  build-subchartsdemo:
-    name: Build Helm SubChartsDemo
-    runs-on: large_runner
-    steps:
-      - name: Checkout
-        uses: actions/checkout@v4
-      - name: Setup Go
-        uses: actions/setup-go@v5
+      - name: Download CTFs
+        uses: actions/download-artifact@v4
         with:
-          go-version-file: '${{ github.workspace }}/go.mod'
-          cache: false
-
-      - name: Get go environment for use with cache
+          pattern: 'ctf-component-*'
+          path: gen/downloaded-ctfs
+      - name: Move CTFs into correct directory for aggregation
         run: |
-          echo "go_cache=$(go env GOCACHE)" >> $GITHUB_ENV
-          echo "go_modcache=$(go env GOMODCACHE)" >> $GITHUB_ENV
-
-      # This step will only reuse the go mod and build cache from main made during the Build,
-      # see push_ocm.yaml => "ocm-cli-latest" Job
-      # This means it never caches by itself and PRs cannot cause cache pollution / thrashing
-      # This is because we have huge storage requirements for our cache because of the mass of dependencies
-      - name: Restore / Reuse Cache from central build
-        id: cache-golang-restore
-        uses: actions/cache/restore@v4 # Only Restore, not build another cache (too big)
-        with:
-          path: |
-            ${{ env.go_cache }}
-            ${{ env.go_modcache }}
-          key: ${{ env.cache_name }}-${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}-${{ hashFiles('**/go.mod') }}
-          restore-keys: |
-            ${{ env.cache_name }}-${{ runner.os }}-go-
-        env:
-          cache_name: ocm-cli-latest-go-cache # needs to be the same key in the end as in the build step
-
-      - name: CTF
+          IFS=" " read -a COMPONENTS <<< "${{ env.components }}"
+          for i in "${COMPONENTS[@]}"; do
+            mkdir -p ${{ github.workspace }}/gen/${i}
+            mv ${{ github.workspace }}/gen/downloaded-ctfs/ctf-component-${i} ${{ github.workspace }}/gen/${i}/ctf
+            ls -R ${{ github.workspace }}/gen/${i}
+          done
+      - name: Create aggregated CTF
         run: |
-          cd components/subchartsdemo
-          PATH=$PATH:$(go env GOPATH)/bin make ctf
-
-  build-ecrplugin:
-    name: Build ECR Plugin
-    runs-on: large_runner
-    steps:
-      - name: Self Hosted Runner Post Job Cleanup Action
-        uses: TooMuch4U/actions-clean@v2.2
-
-      - name: Checkout
-        uses: actions/checkout@v4
-      - name: Setup Go
-        uses: actions/setup-go@v5
+          PATH=$PATH:$(go env GOPATH)/bin \
+          CTF_TYPE=${{ env.CTF_TYPE }} \
+          COMPONENTS="${{ env.components }}" \
+          make plain-ctf
+      - name: Upload aggregated CTF
+        # only upload the artifact if we are not on a PR
+        if: needs.pr-check.outputs.number != 'null'
+        uses: actions/upload-artifact@v4
         with:
-          go-version-file: '${{ github.workspace }}/go.mod'
-          cache: false
-
-      - name: Get go environment for use with cache
-        run: |
-          echo "go_cache=$(go env GOCACHE)" >> $GITHUB_ENV
-          echo "go_modcache=$(go env GOMODCACHE)" >> $GITHUB_ENV
-
-      # This step will only reuse the go mod and build cache from main made during the Build,
-      # see push_ocm.yaml => "ocm-cli-latest" Job
-      # This means it never caches by itself and PRs cannot cause cache pollution / thrashing
-      # This is because we have huge storage requirements for our cache because of the mass of dependencies
-      - name: Restore / Reuse Cache from central build
-        id: cache-golang-restore
-        uses: actions/cache/restore@v4 # Only Restore, not build another cache (too big)
+          if-no-files-found: error
+          overwrite: true
+          retention-days: 60
+          name: ctf-aggregated
+          path: gen/ctf
+      - name: Delete old CTFs that lead up to aggregation
+        uses: geekyeggo/delete-artifact@v5
         with:
-          path: |
-            ${{ env.go_cache }}
-            ${{ env.go_modcache }}
-          key: ${{ env.cache_name }}-${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}-${{ hashFiles('**/go.mod') }}
-          restore-keys: |
-            ${{ env.cache_name }}-${{ runner.os }}-go-
-        env:
-          cache_name: ocm-cli-latest-go-cache # needs to be the same key in the end as in the build step
-
-      - name: CTF
-        run: |
-          cd components/ecrplugin
-          PATH=$PATH:$(go env GOPATH)/bin make ctf
+          name: |
+            ctf-component-*
\ No newline at end of file
diff --git a/Makefile b/Makefile
index e33fb4c075..405434ff37 100644
--- a/Makefile
+++ b/Makefile
@@ -13,7 +13,7 @@ CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen
 PLATFORMS = windows/amd64 darwin/arm64 darwin/amd64 linux/amd64 linux/arm64
 
 CREDS    ?=
-OCM      := go run $(REPO_ROOT)/cmds/ocm $(CREDS)
+OCM := bin/ocm $(CREDS)
 CTF_TYPE ?= directory
 
 GEN := $(REPO_ROOT)/gen
@@ -165,7 +165,7 @@ $(GEN)/.comps: $(GEN)/.exists
 .PHONY: ctf
 ctf: $(GEN)/ctf
 
-$(GEN)/ctf: $(GEN)/.exists $(GEN)/.comps
+$(GEN)/ctf: $(GEN)/.exists $(GEN)/.comps bin/ocm
 	@rm -rf "$(GEN)"/ctf
 	@for i in $(COMPONENTS); do \
       echo "transfering component $$i..."; \
@@ -174,19 +174,27 @@ $(GEN)/ctf: $(GEN)/.exists $(GEN)/.comps
 	done
 	@touch $@
 
+.PHONY: describe
+describe: $(GEN)/ctf bin/ocm
+	$(OCM) get resources --lookup $(OCMREPO) -r -o treewide $(GEN)/ctf
+
+.PHONY: descriptor
+descriptor: $(GEN)/ctf bin/ocm
+	$(OCM) get component -S v3alpha1 -o yaml $(GEN)/ctf
+
 .PHONY: push
 push: $(GEN)/ctf $(GEN)/.push.$(NAME)
 
-$(GEN)/.push.$(NAME): $(GEN)/ctf
+$(GEN)/.push.$(NAME): $(GEN)/ctf bin/ocm
 	$(OCM) transfer ctf -f $(GEN)/ctf $(OCMREPO)
 	@touch $@
 
 .PHONY: plain-push
-plain-push: $(GEN)
+plain-push: $(GEN) bin/ocm
 	$(OCM) transfer ctf -f $(GEN)/ctf $(OCMREPO)
 
 .PHONY: plain-ctf
-plain-ctf: $(GEN)
+plain-ctf: $(GEN) bin/ocm
 	@rm -rf "$(GEN)"/ctf
 	@for i in $(COMPONENTS); do \
        echo "transfering component $$i..."; \
diff --git a/components/demoplugin/Makefile b/components/demoplugin/Makefile
index 4e1a35502f..43b8b58034 100644
--- a/components/demoplugin/Makefile
+++ b/components/demoplugin/Makefile
@@ -105,7 +105,7 @@ info:
 
 .PHONY: describe
 describe: $(GEN)/ctf $(OCM_BIN)
-	$(OCM) get resources --lookup $(OCMREPO) -c -o treewide $(GEN)/ctf
+	$(OCM) get resources --lookup $(OCMREPO) -r -o treewide $(GEN)/ctf
 
 .PHONY: descriptor
 descriptor: $(GEN)/ctf $(OCM_BIN)
diff --git a/components/ecrplugin/Makefile b/components/ecrplugin/Makefile
index 5a2175c995..ff96ab485f 100644
--- a/components/ecrplugin/Makefile
+++ b/components/ecrplugin/Makefile
@@ -107,7 +107,7 @@ info:
 
 .PHONY: describe
 describe: $(GEN)/ctf $(OCM_BIN)
-	$(OCM) get resources --lookup $(OCMREPO) -c -o treewide $(GEN)/ctf
+	$(OCM) get resources --lookup $(OCMREPO) -r -o treewide $(GEN)/ctf
 
 .PHONY: descriptor
 descriptor: $(GEN)/ctf $(OCM_BIN)
diff --git a/components/ocmcli/Makefile b/components/ocmcli/Makefile
index 2502ef16e3..e972f91037 100644
--- a/components/ocmcli/Makefile
+++ b/components/ocmcli/Makefile
@@ -156,7 +156,7 @@ info:
 
 .PHONY: describe
 describe: $(GEN)/ctf $(OCM_BIN)
-	$(OCM) get resources --lookup $(OCMREPO) -c -o treewide $(GEN)/ctf
+	$(OCM) get resources --lookup $(OCMREPO) -r -o treewide $(GEN)/ctf
 
 .PHONY: descriptor
 descriptor: $(GEN)/ctf $(OCM_BIN)
diff --git a/components/subchartsdemo/Makefile b/components/subchartsdemo/Makefile
index 3987b361e1..93ae7b583b 100644
--- a/components/subchartsdemo/Makefile
+++ b/components/subchartsdemo/Makefile
@@ -77,12 +77,12 @@ info:
 	@echo "CREDS:    $(CREDS)"
 
 .PHONY: describe
-describe: $(GEN)/ctf
-	ocm get resources --lookup $(OCMREPO) -o treewide $(GEN)/ctf
+describe: $(GEN)/ctf $(OCM_BIN)
+	$(OCM) get resources --lookup $(OCMREPO) -r -o treewide $(GEN)/ctf
 
 .PHONY: descriptor
-descriptor: $(GEN)/ctf
-	ocm get component -S v3alpha1 -o yaml $(GEN)/ctf
+descriptor: $(GEN)/ctf $(OCM_BIN)
+	$(OCM) get component -S v3alpha1 -o yaml $(GEN)/ctf
 
 .PHONY: clean
 clean:

From 37c6514ee7f0ee517bea5a92317e0e739542ce77 Mon Sep 17 00:00:00 2001
From: Fabian Burth 
Date: Thu, 7 Nov 2024 15:52:31 +0100
Subject: [PATCH 31/58] bug: fix unmarshal consumer identity with empty value
 (#1057)


#### What this PR does / why we need it
Fix empty identity value regression.

The regression was introduced after this
[PR](https://github.com/open-component-model/ocm/pull/927) adding a
custom unmarshaler for consumer identities which allows to specify
values other than string (e.g. port: 5000), even though consumer
identity is a map[string]string.


#### Which issue(s) this PR fixes

---
 api/credentials/internal/identity.go      | 12 +++++++++++-
 api/credentials/internal/identity_test.go | 15 +++++++++++++++
 2 files changed, 26 insertions(+), 1 deletion(-)

diff --git a/api/credentials/internal/identity.go b/api/credentials/internal/identity.go
index d8b3e84d91..6743754550 100644
--- a/api/credentials/internal/identity.go
+++ b/api/credentials/internal/identity.go
@@ -93,6 +93,10 @@ func orMatcher(list []IdentityMatcher) IdentityMatcher {
 // ConsumerIdentity describes the identity of a credential consumer.
 type ConsumerIdentity map[string]string
 
+// UnmarshalJSON allows a yaml specification containing a data type other
+// string, e.g. a hostpath spec with a port. Previously, it would error if the
+// user specified `port: 5000` and instead, the user had to specify
+// `port: "5000"`.
 func (c *ConsumerIdentity) UnmarshalJSON(data []byte) error {
 	var m map[string]interface{}
 	err := runtime.DefaultJSONEncoding.Unmarshal(data, &m)
@@ -100,15 +104,21 @@ func (c *ConsumerIdentity) UnmarshalJSON(data []byte) error {
 		return err
 	}
 
+	if len(m) == 0 {
+		return nil
+	}
 	*c = make(map[string]string, len(m))
 	for k, v := range m {
 		switch v.(type) {
+		case nil:
+			(*c)[k] = ""
 		case map[string]interface{}:
 			return fmt.Errorf("cannot unmarshal complex type into consumer identity")
 		case []interface{}:
 			return fmt.Errorf("cannot unmarshal complex type into consumer identity")
+		default:
+			(*c)[k] = fmt.Sprintf("%v", v)
 		}
-		(*c)[k] = fmt.Sprintf("%v", v)
 	}
 	return nil
 }
diff --git a/api/credentials/internal/identity_test.go b/api/credentials/internal/identity_test.go
index 990a19997a..66633df813 100644
--- a/api/credentials/internal/identity_test.go
+++ b/api/credentials/internal/identity_test.go
@@ -70,4 +70,19 @@ port:
 		cid := internal.ConsumerIdentity{}
 		Expect(yaml.Unmarshal([]byte(data), &cid)).NotTo(Succeed())
 	})
+	It("with nil", func() {
+		data := `
+scheme: http
+hostname: 127.0.0.1
+port:
+`
+		id := internal.ConsumerIdentity{
+			"scheme":   "http",
+			"hostname": "127.0.0.1",
+			"port":     "",
+		}
+		cid := internal.ConsumerIdentity{}
+		Expect(yaml.Unmarshal([]byte(data), &cid)).To(Succeed())
+		Expect(cid).To(Equal(id))
+	})
 })

From 3577e7e9d72f25a84037aa34818a18c735e95d0a Mon Sep 17 00:00:00 2001
From: Fabian Burth 
Date: Thu, 7 Nov 2024 18:09:53 +0100
Subject: [PATCH 32/58] bug: allow http protocol for oci access (#1060)


#### What this PR does / why we need it
Although we allow to fetch components from an `http` registry by
specifying the scheme, we unintentionally didn't enable fetching
artifacts specified in an oci access from an http registries due to this
bug.

#### Which issue(s) this PR fixes

---
 api/ocm/extensions/accessmethods/ociartifact/method.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/api/ocm/extensions/accessmethods/ociartifact/method.go b/api/ocm/extensions/accessmethods/ociartifact/method.go
index a8cb908410..38fef2b5ef 100644
--- a/api/ocm/extensions/accessmethods/ociartifact/method.go
+++ b/api/ocm/extensions/accessmethods/ociartifact/method.go
@@ -227,7 +227,7 @@ func (m *accessMethod) eval(relto oci.Repository) error {
 		ocictx := m.ctx.OCIContext()
 		spec := ocictx.GetAlias(ref.Host)
 		if spec == nil {
-			spec = ocireg.NewRepositorySpec(ref.Host)
+			spec = ocireg.NewRepositorySpec(ref.RepositoryRef())
 		}
 		repo, err := ocictx.RepositoryForSpec(spec)
 		if err != nil {

From beabf65653edb08fff31c056e8645a4fdba75c72 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jakob=20M=C3=B6ller?= 
Date: Fri, 8 Nov 2024 11:34:02 +0100
Subject: [PATCH 33/58] chore: force bump to 0.18.0-dev (#1061)


#### What this PR does / why we need it

this is necessary because
https://github.com/open-component-model/ocm/commit/6a27140afa7084d45032341c94ce2cdb975f1d53
landed in releases/v0.17.0 after a broken github action

#### Which issue(s) this PR fixes

---
 VERSION | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/VERSION b/VERSION
index a0073758b8..498b6fb3d5 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-0.17.0-dev
+0.18.0-dev

From 2ea69c7ecca1e8be7e9d9f94dfdcac6090f1c69d Mon Sep 17 00:00:00 2001
From: Gerald Morrison <67469729+morri-son@users.noreply.github.com>
Date: Fri, 8 Nov 2024 12:28:01 +0100
Subject: [PATCH 34/58] change short text for help topic (#1058)


#### What this PR does / why we need it
Improve short text for help topic

---------

Co-authored-by: Hilmar Falkenberg 
---
 api/oci/ref_test.go                           | 44 ++++++++++++-------
 .../download/config/registration_test.go      |  5 +--
 cmds/ocm/commands/verbs/install/cmd.go        |  2 +-
 docs/reference/ocm.md                         |  2 +-
 docs/reference/ocm_install.md                 |  2 +-
 docs/reference/ocm_install_plugins.md         |  2 +-
 6 files changed, 35 insertions(+), 22 deletions(-)

diff --git a/api/oci/ref_test.go b/api/oci/ref_test.go
index f0d27516c5..c95850ef03 100644
--- a/api/oci/ref_test.go
+++ b/api/oci/ref_test.go
@@ -3,11 +3,11 @@ package oci_test
 import (
 	"strings"
 
-	"github.com/mandelsoft/goutils/generics"
 	. "github.com/mandelsoft/goutils/testutils"
 	. "github.com/onsi/ginkgo/v2"
 	. "github.com/onsi/gomega"
 
+	"github.com/mandelsoft/goutils/generics"
 	godigest "github.com/opencontainers/go-digest"
 
 	"ocm.software/ocm/api/oci"
@@ -255,8 +255,10 @@ var _ = Describe("ref parsing", func() {
 												},
 												ArtSpec: oci.ArtSpec{
 													Repository: r,
-													ArtVersion: oci.ArtVersion{Tag: Pointer([]byte(uv)),
-														Digest: Dig([]byte(ud))},
+													ArtVersion: oci.ArtVersion{
+														Tag:    Pointer([]byte(uv)),
+														Digest: Dig([]byte(ud)),
+													},
 												},
 											})
 										})
@@ -293,8 +295,10 @@ var _ = Describe("ref parsing", func() {
 												},
 												ArtSpec: oci.ArtSpec{
 													Repository: r,
-													ArtVersion: oci.ArtVersion{Tag: Pointer([]byte(uv)),
-														Digest: Dig([]byte(ud))},
+													ArtVersion: oci.ArtVersion{
+														Tag:    Pointer([]byte(uv)),
+														Digest: Dig([]byte(ud)),
+													},
 												},
 											})
 										})
@@ -343,8 +347,10 @@ var _ = Describe("ref parsing", func() {
 										},
 										ArtSpec: oci.ArtSpec{
 											Repository: r,
-											ArtVersion: oci.ArtVersion{Tag: Pointer([]byte(uv)),
-												Digest: Dig([]byte(ud))},
+											ArtVersion: oci.ArtVersion{
+												Tag:    Pointer([]byte(uv)),
+												Digest: Dig([]byte(ud)),
+											},
 										},
 									})
 								})
@@ -382,8 +388,10 @@ var _ = Describe("ref parsing", func() {
 							},
 							ArtSpec: oci.ArtSpec{
 								Repository: "library/" + r,
-								ArtVersion: oci.ArtVersion{Tag: Pointer([]byte(uv)),
-									Digest: Dig([]byte(ud))},
+								ArtVersion: oci.ArtVersion{
+									Tag:    Pointer([]byte(uv)),
+									Digest: Dig([]byte(ud)),
+								},
 							},
 						})
 					})
@@ -418,8 +426,10 @@ var _ = Describe("ref parsing", func() {
 							},
 							ArtSpec: oci.ArtSpec{
 								Repository: r,
-								ArtVersion: oci.ArtVersion{Tag: Pointer([]byte(uv)),
-									Digest: Dig([]byte(ud))},
+								ArtVersion: oci.ArtVersion{
+									Tag:    Pointer([]byte(uv)),
+									Digest: Dig([]byte(ud)),
+								},
 							},
 						})
 					})
@@ -596,8 +606,10 @@ var _ = Describe("ref parsing", func() {
 			},
 			ArtSpec: oci.ArtSpec{
 				Repository: "repo/repo",
-				ArtVersion: oci.ArtVersion{Tag: &tag,
-					Digest: &digest},
+				ArtVersion: oci.ArtVersion{
+					Tag:    &tag,
+					Digest: &digest,
+				},
 			},
 		})
 		CheckRef("http://127.0.0.1:443/repo/repo:v1@"+digest.String(), &oci.RefSpec{
@@ -609,8 +621,10 @@ var _ = Describe("ref parsing", func() {
 			},
 			ArtSpec: oci.ArtSpec{
 				Repository: "repo/repo",
-				ArtVersion: oci.ArtVersion{Tag: &tag,
-					Digest: &digest},
+				ArtVersion: oci.ArtVersion{
+					Tag:    &tag,
+					Digest: &digest,
+				},
 			},
 		})
 		CheckRef("directory::a/b", &oci.RefSpec{
diff --git a/api/ocm/extensions/download/config/registration_test.go b/api/ocm/extensions/download/config/registration_test.go
index e2f81a3f40..f68f6efb41 100644
--- a/api/ocm/extensions/download/config/registration_test.go
+++ b/api/ocm/extensions/download/config/registration_test.go
@@ -6,17 +6,16 @@ import (
 	. "github.com/mandelsoft/goutils/testutils"
 	. "github.com/onsi/ginkgo/v2"
 	. "github.com/onsi/gomega"
+
 	"ocm.software/ocm/api/ocm"
 	"ocm.software/ocm/api/ocm/extensions/download"
+	me "ocm.software/ocm/api/ocm/extensions/download/config"
 	"ocm.software/ocm/api/ocm/ocmutils"
 	"ocm.software/ocm/api/tech/helm"
-
-	me "ocm.software/ocm/api/ocm/extensions/download/config"
 )
 
 var _ = Describe("Download Handler regigistration", func() {
 	It("register by ocm config", func() {
-
 		ctx := ocm.New()
 
 		cfg := me.New()
diff --git a/cmds/ocm/commands/verbs/install/cmd.go b/cmds/ocm/commands/verbs/install/cmd.go
index ea1ca8661f..87cbb3dbb3 100644
--- a/cmds/ocm/commands/verbs/install/cmd.go
+++ b/cmds/ocm/commands/verbs/install/cmd.go
@@ -12,7 +12,7 @@ import (
 // NewCommand creates a new command.
 func NewCommand(ctx clictx.Context) *cobra.Command {
 	cmd := utils.MassageCommand(&cobra.Command{
-		Short: "Install elements.",
+		Short: "Install new OCM CLI components ",
 	}, verbs.Install)
 	cmd.AddCommand(plugins.NewCommand(ctx))
 	return cmd
diff --git a/docs/reference/ocm.md b/docs/reference/ocm.md
index c88be56806..f99a049602 100644
--- a/docs/reference/ocm.md
+++ b/docs/reference/ocm.md
@@ -369,7 +369,7 @@ by a certificate delivered with the signature.
 * [ocm execute](ocm_execute.md)	 — Execute an element.
 * [ocm get](ocm_get.md)	 — Get information about artifacts and components
 * [ocm hash](ocm_hash.md)	 — Hash and normalization operations
-* [ocm install](ocm_install.md)	 — Install elements.
+* [ocm install](ocm_install.md)	 — Install new OCM CLI components
 * [ocm list](ocm_list.md)	 — List information about components
 * [ocm set](ocm_set.md)	 — Set information about OCM repositories
 * [ocm show](ocm_show.md)	 — Show tags or versions
diff --git a/docs/reference/ocm_install.md b/docs/reference/ocm_install.md
index fc01db3356..3646334332 100644
--- a/docs/reference/ocm_install.md
+++ b/docs/reference/ocm_install.md
@@ -1,4 +1,4 @@
-## ocm install — Install Elements.
+## ocm install — Install New OCM CLI Components
 
 ### Synopsis
 
diff --git a/docs/reference/ocm_install_plugins.md b/docs/reference/ocm_install_plugins.md
index 9e501520c0..9c20720c97 100644
--- a/docs/reference/ocm_install_plugins.md
+++ b/docs/reference/ocm_install_plugins.md
@@ -87,6 +87,6 @@ $ ocm install plugin -r demo
 
 #### Parents
 
-* [ocm install](ocm_install.md)	 — Install elements.
+* [ocm install](ocm_install.md)	 — Install new OCM CLI components
 * [ocm](ocm.md)	 — Open Component Model command line client
 

From b711f7eae82c8b17bca71166ea5a066b6061573c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jakob=20M=C3=B6ller?= 
Date: Fri, 8 Nov 2024 20:50:14 +0100
Subject: [PATCH 35/58] chore: change guide for 0.18.0 (#1066)

this will be (hopefully) the last bump before we create an automatically
generated PR after a release which bumps this generation or we decide to
stop updating the tour with the latest release


#### What this PR does / why we need it

#### Which issue(s) this PR fixes

---
 examples/lib/tour/01-getting-started/README.md | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/examples/lib/tour/01-getting-started/README.md b/examples/lib/tour/01-getting-started/README.md
index 1c0b22d69e..5ec9f956ad 100644
--- a/examples/lib/tour/01-getting-started/README.md
+++ b/examples/lib/tour/01-getting-started/README.md
@@ -168,32 +168,32 @@ differ, because the code always describes the latest version):
 
 ```text
 resources of the latest version:
-  version:  0.17.0
+  version:  0.18.0-rc.1
   provider: ocm.software
    1: name:           ocmcli
       extra identity: "architecture"="amd64","os"="linux"
       resource type:  executable
-      access:         Local blob sha256:03a45dcde67ba565fe806cb5db67da3387f772f7c50af711a0edd6f802570c04[]
+      access:         Local blob sha256:74fdf71c5467cacd1cb09d15d6ad4944d60cc8efa1d704a91c337e54dcd03fbc[]
    2: name:           ocmcli
       extra identity: "architecture"="arm64","os"="linux"
       resource type:  executable
-      access:         Local blob sha256:5a622634ae43cf03eac91079389d83266891d1f9b2d8a3884cef6fe639180324[]
+      access:         Local blob sha256:d0022850cce685d48ca589b3b59913ecbc3572f7f5082bca5c086a4bf2b47c5a[]
    3: name:           ocmcli
       extra identity: "architecture"="arm64","os"="darwin"
       resource type:  executable
-      access:         Local blob sha256:1482fe5b764e3a86cf96704d7a839ad7e53dcbfd4f5fce5405abffb1962153dd[]
+      access:         Local blob sha256:1161fc38d0fe78ba3be97783f8676a46afa2baf57c199f937798f791cc4961d3[]
    4: name:           ocmcli
       extra identity: "architecture"="amd64","os"="darwin"
       resource type:  executable
-      access:         Local blob sha256:805f181aff48511eea12c699ed1bbcee8bdc4c5168924e81058aff8715946875[]
+      access:         Local blob sha256:33074ce5cc079ea4fc1dbcc7bd54c27cc93f0e188d9ad8c56ba642c4ba6744af[]
    5: name:           ocmcli
       extra identity: "architecture"="amd64","os"="windows"
       resource type:  executable
-      access:         Local blob sha256:20839c68bf0c4cf99444d78ebb93f53358fa9e95fe806f186220bd21d520efa7[]
+      access:         Local blob sha256:2fbac39d7772ae1cf209aca5bb5efdbb6b91e83aede9464c52304c3ccebb4f67[]
    6: name:           ocmcli-image
       extra identity: 
       resource type:  ociImage
-      access:         OCI artifact ghcr.io/open-component-model/ocm/ocm.software/ocmcli/ocmcli-image:0.17.0@sha256:16fb52a1cb11c867bd058f4124dea53fbab94229842cc14b52653c2e80b1cede
+      access:         OCI artifact ghcr.io/open-component-model/ocm/ocm.software/ocmcli/ocmcli-image:0.18.0-rc.1@sha256:3ba3e8c075f7f91e851ec3ce53da2347fe464b3ac33c6d65cf89a459193bb5cb
 ```
 
 Resources have some metadata, like their identity and a resource type.

From 284e158798079127086eeaef762d61045bc5a583 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 11 Nov 2024 09:03:13 +0100
Subject: [PATCH 36/58] chore(deps): bump the ci group with 2 updates (#1068)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Bumps the ci group with 2 updates:
[DeterminateSystems/nix-installer-action](https://github.com/determinatesystems/nix-installer-action)
and [anchore/sbom-action](https://github.com/anchore/sbom-action).

Updates `DeterminateSystems/nix-installer-action` from 14 to 15
Release notes

Sourced from DeterminateSystems/nix-installer-action's releases.

v15

What's Changed

Full Changelog: https://github.com/DeterminateSystems/nix-installer-action/compare/v14...v15

Commits

Updates `anchore/sbom-action` from 0.17.6 to 0.17.7
Release notes

Sourced from anchore/sbom-action's releases.

v0.17.7

Changes in v0.17.7

Commits

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/flake_vendorhash.yaml | 2 +- .github/workflows/release.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/flake_vendorhash.yaml b/.github/workflows/flake_vendorhash.yaml index 1c8696ebf5..f03948f118 100644 --- a/.github/workflows/flake_vendorhash.yaml +++ b/.github/workflows/flake_vendorhash.yaml @@ -25,7 +25,7 @@ jobs: with: token: ${{ steps.generate_token.outputs.token }} - name: Install Nix - uses: DeterminateSystems/nix-installer-action@v14 + uses: DeterminateSystems/nix-installer-action@v15 - name: Update ocm vendor hash run: nix run .#nixpkgs.nix-update -- --flake --version=skip ocm - name: Check diff and create action summary diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index c834a6500b..95e0971a07 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -141,7 +141,7 @@ jobs: cache_name: ocm-cli-latest-go-cache # needs to be the same key in the end as in the build step - name: Setup Syft - uses: anchore/sbom-action/download-syft@251a468eed47e5082b105c3ba6ee500c0e65a764 # v0.17.6 + uses: anchore/sbom-action/download-syft@fc46e51fd3cb168ffb36c6d1915723c47db58abb # v0.17.7 - name: Setup Cosign uses: sigstore/cosign-installer@v3.7.0 From 4bdd42657537734cb2eb850fb0b9a0f578a7cf06 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Nov 2024 08:19:36 +0000 Subject: [PATCH 37/58] chore(deps): bump the go group with 10 updates (#1067) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps the go group with 10 updates: | Package | From | To | | --- | --- | --- | | [github.com/aws/aws-sdk-go-v2](https://github.com/aws/aws-sdk-go-v2) | `1.32.3` | `1.32.4` | | [github.com/aws/aws-sdk-go-v2/config](https://github.com/aws/aws-sdk-go-v2) | `1.28.1` | `1.28.3` | | [github.com/aws/aws-sdk-go-v2/credentials](https://github.com/aws/aws-sdk-go-v2) | `1.17.42` | `1.17.44` | | [github.com/aws/aws-sdk-go-v2/feature/s3/manager](https://github.com/aws/aws-sdk-go-v2) | `1.17.35` | `1.17.37` | | [github.com/aws/aws-sdk-go-v2/service/ecr](https://github.com/aws/aws-sdk-go-v2) | `1.36.3` | `1.36.5` | | [github.com/aws/aws-sdk-go-v2/service/s3](https://github.com/aws/aws-sdk-go-v2) | `1.66.2` | `1.66.3` | | [github.com/containers/image/v5](https://github.com/containers/image) | `5.32.2` | `5.33.0` | | [golang.org/x/net](https://github.com/golang/net) | `0.30.0` | `0.31.0` | | [golang.org/x/oauth2](https://github.com/golang/oauth2) | `0.23.0` | `0.24.0` | | [golang.org/x/text](https://github.com/golang/text) | `0.19.0` | `0.20.0` | Updates `github.com/aws/aws-sdk-go-v2` from 1.32.3 to 1.32.4
Commits

Updates `github.com/aws/aws-sdk-go-v2/config` from 1.28.1 to 1.28.3
Commits

Updates `github.com/aws/aws-sdk-go-v2/credentials` from 1.17.42 to 1.17.44
Commits

Updates `github.com/aws/aws-sdk-go-v2/feature/s3/manager` from 1.17.35 to 1.17.37
Commits

Updates `github.com/aws/aws-sdk-go-v2/service/ecr` from 1.36.3 to 1.36.5
Commits

Updates `github.com/aws/aws-sdk-go-v2/service/s3` from 1.66.2 to 1.66.3
Commits

Updates `github.com/containers/image/v5` from 5.32.2 to 5.33.0
Release notes

Sourced from github.com/containers/image/v5's releases.

v5.33.0

What's Changed

... (truncated)

Commits
  • c3a2029 Bump to c/image v5.33.0
  • 04d69d5 Bump to c/storage v1.56.0
  • 59417ae Merge pull request #2609 from mtrmac/copy-resolve-destination
  • 6ba898f HACK: Only return an image ID from ReportResolvedReference for c/storage
  • 125f862 Return a precise reference to the created image when writing to containers-st...
  • 91d22b2 Introduce private.ImageDestination.CommitWithOptions
  • 831269d Rename an options variable to imgOptions
  • ba2a4ae Merge pull request #2616 from containers/renovate/golang.org-x-exp-digest
  • 6bcb929 fix(deps): update golang.org/x/exp digest to f66d83c
  • 228de93 Merge pull request #2615 from containers/renovate/github.com-containers-stora...
  • Additional commits viewable in compare view

Updates `golang.org/x/net` from 0.30.0 to 0.31.0
Commits
  • 334afa0 go.mod: update golang.org/x dependencies
  • d7f220d quic: add LocalAddr and RemoteAddr to quic.Conn
  • 858db1a http2: surface errors occurring very early in a client conn's lifetime
  • 0aa844c http2: support unencrypted HTTP/2 handoff from net/http
  • f35fec9 http2: detect hung client connections by confirming stream resets
  • e883dae README: don't recommend go get
  • 511cc3a html: add Node.{Ancestors,ChildNodes,Descendants}()
  • 4783315 http2: limit 1xx based on size, do not limit when delivered
  • 5716b98 internal/socket: execute gofmt
  • 42b1186 http2: support ResponseController.EnableFullDuplex
  • See full diff in compare view

Updates `golang.org/x/oauth2` from 0.23.0 to 0.24.0
Commits

Updates `golang.org/x/text` from 0.19.0 to 0.20.0
Commits
  • efd25da go.mod: update golang.org/x dependencies
  • 8a0e65e README: don't recommend go get
  • fefda1a internal/texttest: remove Run and Bench helpers
  • a457f47 all: normalize subtest names to NFC
  • See full diff in compare view

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 52 +++++++++++++------------- go.sum | 116 ++++++++++++++++++++++++++++++--------------------------- 2 files changed, 87 insertions(+), 81 deletions(-) diff --git a/go.mod b/go.mod index 9ec857ae53..2e21216e28 100644 --- a/go.mod +++ b/go.mod @@ -8,17 +8,17 @@ require ( github.com/DataDog/gostackparse v0.7.0 github.com/InfiniteLoopSpace/go_S-MIME v0.0.0-20181221134359-3f58f9a4b2b6 github.com/Masterminds/semver/v3 v3.3.0 - github.com/aws/aws-sdk-go-v2 v1.32.3 - github.com/aws/aws-sdk-go-v2/config v1.28.1 - github.com/aws/aws-sdk-go-v2/credentials v1.17.42 - github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.35 - github.com/aws/aws-sdk-go-v2/service/ecr v1.36.3 - github.com/aws/aws-sdk-go-v2/service/s3 v1.66.2 + github.com/aws/aws-sdk-go-v2 v1.32.4 + github.com/aws/aws-sdk-go-v2/config v1.28.3 + github.com/aws/aws-sdk-go-v2/credentials v1.17.44 + github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.37 + github.com/aws/aws-sdk-go-v2/service/ecr v1.36.5 + github.com/aws/aws-sdk-go-v2/service/s3 v1.66.3 github.com/cloudflare/cfssl v1.6.5 github.com/containerd/containerd v1.7.23 github.com/containerd/errdefs v1.0.0 github.com/containerd/log v0.1.0 - github.com/containers/image/v5 v5.32.2 + github.com/containers/image/v5 v5.33.0 github.com/cyberphone/json-canonicalization v0.0.0-20231217050601-ba74d44ecf5f github.com/distribution/reference v0.6.0 github.com/docker/cli v27.3.1+incompatible @@ -70,9 +70,9 @@ require ( github.com/xeipuuv/gojsonschema v1.2.0 golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 - golang.org/x/net v0.30.0 - golang.org/x/oauth2 v0.23.0 - golang.org/x/text v0.19.0 + golang.org/x/net v0.31.0 + golang.org/x/oauth2 v0.24.0 + golang.org/x/text v0.20.0 gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473 gopkg.in/yaml.v3 v3.0.1 helm.sh/helm/v3 v3.16.2 @@ -127,19 +127,19 @@ require ( github.com/aliyun/credentials-go v1.3.10 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.6 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.18 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.22 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.22 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.19 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.23 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.23 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect - github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.22 // indirect + github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.23 // indirect github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.27.2 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.0 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.3 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.3 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.3 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.24.3 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.3 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.32.3 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.4 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.4 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.4 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.24.5 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.4 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.32.4 // indirect github.com/aws/smithy-go v1.22.0 // indirect github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20241009180534-e718692eec62 // indirect github.com/beorn7/perks v1.0.1 // indirect @@ -160,7 +160,7 @@ require ( github.com/containerd/stargz-snapshotter/estargz v0.15.1 // indirect github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01 // indirect github.com/containers/ocicrypt v1.2.0 // indirect - github.com/containers/storage v1.55.0 // indirect + github.com/containers/storage v1.56.0 // indirect github.com/coreos/go-oidc/v3 v3.11.0 // indirect github.com/cyphar/filepath-securejoin v0.3.4 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect @@ -259,6 +259,7 @@ require ( github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/locker v1.0.1 // indirect github.com/moby/spdystream v0.5.0 // indirect + github.com/moby/sys/capability v0.3.0 // indirect github.com/moby/sys/mountinfo v0.7.2 // indirect github.com/moby/sys/sequential v0.6.0 // indirect github.com/moby/sys/user v0.3.0 // indirect @@ -304,7 +305,6 @@ require ( github.com/spf13/viper v1.19.0 // indirect github.com/spiffe/go-spiffe/v2 v2.4.0 // indirect github.com/subosito/gotenv v1.6.0 // indirect - github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 // indirect github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect github.com/thales-e-security/pool v0.0.2 // indirect github.com/theupdateframework/go-tuf v0.7.0 // indirect @@ -337,11 +337,11 @@ require ( go.step.sm/crypto v0.54.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect - golang.org/x/crypto v0.28.0 // indirect + golang.org/x/crypto v0.29.0 // indirect golang.org/x/mod v0.21.0 // indirect - golang.org/x/sync v0.8.0 // indirect - golang.org/x/sys v0.26.0 // indirect - golang.org/x/term v0.25.0 // indirect + golang.org/x/sync v0.9.0 // indirect + golang.org/x/sys v0.27.0 // indirect + golang.org/x/term v0.26.0 // indirect golang.org/x/time v0.7.0 // indirect golang.org/x/tools v0.26.0 // indirect golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect diff --git a/go.sum b/go.sum index 81418473b1..20fd9d62a3 100644 --- a/go.sum +++ b/go.sum @@ -86,8 +86,8 @@ github.com/Masterminds/squirrel v1.5.4 h1:uUcX/aBc8O7Fg9kaISIUsHXdKuqehiXAMQTYX8 github.com/Masterminds/squirrel v1.5.4/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= -github.com/Microsoft/hcsshim v0.12.5 h1:bpTInLlDy/nDRWFVcefDZZ1+U8tS+rz3MxjKgu9boo0= -github.com/Microsoft/hcsshim v0.12.5/go.mod h1:tIUGego4G1EN5Hb6KC90aDYiUI2dqLSTTOCjVNpOgZ8= +github.com/Microsoft/hcsshim v0.12.9 h1:2zJy5KA+l0loz1HzEGqyNnjd3fyZA31ZBCGKacp6lLg= +github.com/Microsoft/hcsshim v0.12.9/go.mod h1:fJ0gkFAna6ukt0bLdKB8djt4XIJhF/vEPuoIWYVvZ8Y= github.com/OneOfOne/xxhash v1.2.8 h1:31czK/TI9sNkxIKfaUfGlU47BAxQ0ztGgd9vPyqimf8= github.com/OneOfOne/xxhash v1.2.8/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= github.com/ProtonMail/go-crypto v1.0.0 h1:LRuvITjQWX+WIfr930YHG2HNfjR1uOfyf5vE0kC2U78= @@ -165,48 +165,48 @@ github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3d github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/aws/aws-sdk-go v1.55.5 h1:KKUZBfBoyqy5d3swXyiC7Q76ic40rYcbqH7qjh59kzU= github.com/aws/aws-sdk-go v1.55.5/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU= -github.com/aws/aws-sdk-go-v2 v1.32.3 h1:T0dRlFBKcdaUPGNtkBSwHZxrtis8CQU17UpNBZYd0wk= -github.com/aws/aws-sdk-go-v2 v1.32.3/go.mod h1:2SK5n0a2karNTv5tbP1SjsX0uhttou00v/HpXKM1ZUo= +github.com/aws/aws-sdk-go-v2 v1.32.4 h1:S13INUiTxgrPueTmrm5DZ+MiAo99zYzHEFh1UNkOxNE= +github.com/aws/aws-sdk-go-v2 v1.32.4/go.mod h1:2SK5n0a2karNTv5tbP1SjsX0uhttou00v/HpXKM1ZUo= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.6 h1:pT3hpW0cOHRJx8Y0DfJUEQuqPild8jRGmSFmBgvydr0= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.6/go.mod h1:j/I2++U0xX+cr44QjHay4Cvxj6FUbnxrgmqN3H1jTZA= -github.com/aws/aws-sdk-go-v2/config v1.28.1 h1:oxIvOUXy8x0U3fR//0eq+RdCKimWI900+SV+10xsCBw= -github.com/aws/aws-sdk-go-v2/config v1.28.1/go.mod h1:bRQcttQJiARbd5JZxw6wG0yIK3eLeSCPdg6uqmmlIiI= -github.com/aws/aws-sdk-go-v2/credentials v1.17.42 h1:sBP0RPjBU4neGpIYyx8mkU2QqLPl5u9cmdTWVzIpHkM= -github.com/aws/aws-sdk-go-v2/credentials v1.17.42/go.mod h1:FwZBfU530dJ26rv9saAbxa9Ej3eF/AK0OAY86k13n4M= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.18 h1:68jFVtt3NulEzojFesM/WVarlFpCaXLKaBxDpzkQ9OQ= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.18/go.mod h1:Fjnn5jQVIo6VyedMc0/EhPpfNlPl7dHV916O6B+49aE= -github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.35 h1:ihPPdcCVSN0IvBByXwqVp28/l4VosBZ6sDulcvU2J7w= -github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.35/go.mod h1:JkgEhs3SVF51Dj3m1Bj+yL8IznpxzkwlA3jLg3x7Kls= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.22 h1:Jw50LwEkVjuVzE1NzkhNKkBf9cRN7MtE1F/b2cOKTUM= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.22/go.mod h1:Y/SmAyPcOTmpeVaWSzSKiILfXTVJwrGmYZhcRbhWuEY= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.22 h1:981MHwBaRZM7+9QSR6XamDzF/o7ouUGxFzr+nVSIhrs= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.22/go.mod h1:1RA1+aBEfn+CAB/Mh0MB6LsdCYCnjZm7tKXtnk499ZQ= +github.com/aws/aws-sdk-go-v2/config v1.28.3 h1:kL5uAptPcPKaJ4q0sDUjUIdueO18Q7JDzl64GpVwdOM= +github.com/aws/aws-sdk-go-v2/config v1.28.3/go.mod h1:SPEn1KA8YbgQnwiJ/OISU4fz7+F6Fe309Jf0QTsRCl4= +github.com/aws/aws-sdk-go-v2/credentials v1.17.44 h1:qqfs5kulLUHUEXlHEZXLJkgGoF3kkUeFUTVA585cFpU= +github.com/aws/aws-sdk-go-v2/credentials v1.17.44/go.mod h1:0Lm2YJ8etJdEdw23s+q/9wTpOeo2HhNE97XcRa7T8MA= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.19 h1:woXadbf0c7enQ2UGCi8gW/WuKmE0xIzxBF/eD94jMKQ= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.19/go.mod h1:zminj5ucw7w0r65bP6nhyOd3xL6veAUMc3ElGMoLVb4= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.37 h1:jHKR76E81sZvz1+x1vYYrHMxphG5LFBJPhSqEr4CLlE= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.37/go.mod h1:iMkyPkmoJWQKzSOtaX+8oEJxAuqr7s8laxcqGDSHeII= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.23 h1:A2w6m6Tmr+BNXjDsr7M90zkWjsu4JXHwrzPg235STs4= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.23/go.mod h1:35EVp9wyeANdujZruvHiQUAo9E3vbhnIO1mTCAxMlY0= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.23 h1:pgYW9FCabt2M25MoHYCfMrVY2ghiiBKYWUVXfwZs+sU= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.23/go.mod h1:c48kLgzO19wAu3CPkDWC28JbaJ+hfQlsdl7I2+oqIbk= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 h1:VaRN3TlFdd6KxX1x3ILT5ynH6HvKgqdiXoTxAF4HQcQ= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.22 h1:yV+hCAHZZYJQcwAaszoBNwLbPItHvApxT0kVIw6jRgs= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.22/go.mod h1:kbR1TL8llqB1eGnVbybcA4/wgScxdylOdyAd51yxPdw= -github.com/aws/aws-sdk-go-v2/service/ecr v1.36.3 h1:bqmoQEKpWFRDRxOv4lC5yZLc+N1cogZHPLeQACfVUJo= -github.com/aws/aws-sdk-go-v2/service/ecr v1.36.3/go.mod h1:KwOqlt4MOBK9EpOGkj8RU9fqfTEae5AOUHi1pDEZ3OQ= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.23 h1:1SZBDiRzzs3sNhOMVApyWPduWYGAX0imGy06XiBnCAM= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.23/go.mod h1:i9TkxgbZmHVh2S0La6CAXtnyFhlCX/pJ0JsOvBAS6Mk= +github.com/aws/aws-sdk-go-v2/service/ecr v1.36.5 h1:FMF/uaTcIdhvOwZXJfzpwanx2m4Dd6IcN4vDnAn7NAA= +github.com/aws/aws-sdk-go-v2/service/ecr v1.36.5/go.mod h1:xhf509Ba+rG5whtO7w46O0raVzu1Og3Aba80LSvHbbQ= github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.27.2 h1:Zru9Iy2JPM5+uRnFnoqeOZzi8JIVIHJ0ua6JdeDHcyg= github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.27.2/go.mod h1:PtQC3XjutCYFCn1+i8+wtpDaXvEK+vXF2gyLIKAmh4A= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.0 h1:TToQNkvGguu209puTojY/ozlqy2d/SFNcoLIqTFi42g= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.0/go.mod h1:0jp+ltwkf+SwG2fm/PKo8t4y8pJSgOCO4D8Lz3k0aHQ= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.3 h1:kT6BcZsmMtNkP/iYMcRG+mIEA/IbeiUimXtGmqF39y0= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.3/go.mod h1:Z8uGua2k4PPaGOYn66pK02rhMrot3Xk3tpBuUFPomZU= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.3 h1:qcxX0JYlgWH3hpPUnd6U0ikcl6LLA9sLkXE2w1fpMvY= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.3/go.mod h1:cLSNEmI45soc+Ef8K/L+8sEA3A3pYFEYf5B5UI+6bH4= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.3 h1:ZC7Y/XgKUxwqcdhO5LE8P6oGP1eh6xlQReWNKfhvJno= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.3/go.mod h1:WqfO7M9l9yUAw0HcHaikwRd/H6gzYdz7vjejCA5e2oY= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.4 h1:aaPpoG15S2qHkWm4KlEyF01zovK1nW4BBbyXuHNSE90= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.4/go.mod h1:eD9gS2EARTKgGr/W5xwgY/ik9z/zqpW+m/xOQbVxrMk= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.4 h1:tHxQi/XHPK0ctd/wdOw0t7Xrc2OxcRCnVzv8lwWPu0c= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.4/go.mod h1:4GQbF1vJzG60poZqWatZlhP31y8PGCCVTvIGPdaaYJ0= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.4 h1:E5ZAVOmI2apR8ADb72Q63KqwwwdW1XcMeXIlrZ1Psjg= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.4/go.mod h1:wezzqVUOVVdk+2Z/JzQT4NxAU0NbhRe5W8pIE72jsWI= github.com/aws/aws-sdk-go-v2/service/kms v1.37.0 h1:ovrHGOiNu4S0GSMeexZlsMhBkUb3bCE3iOktFZ7rmBU= github.com/aws/aws-sdk-go-v2/service/kms v1.37.0/go.mod h1:YLqfMkq9GWbICgqT5XMIzT8I2+MxVKodTnNBo3BONgE= -github.com/aws/aws-sdk-go-v2/service/s3 v1.66.2 h1:p9TNFL8bFUMd+38YIpTAXpoxyz0MxC7FlbFEH4P4E1U= -github.com/aws/aws-sdk-go-v2/service/s3 v1.66.2/go.mod h1:fNjyo0Coen9QTwQLWeV6WO2Nytwiu+cCcWaTdKCAqqE= -github.com/aws/aws-sdk-go-v2/service/sso v1.24.3 h1:UTpsIf0loCIWEbrqdLb+0RxnTXfWh2vhw4nQmFi4nPc= -github.com/aws/aws-sdk-go-v2/service/sso v1.24.3/go.mod h1:FZ9j3PFHHAR+w0BSEjK955w5YD2UwB/l/H0yAK3MJvI= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.3 h1:2YCmIXv3tmiItw0LlYf6v7gEHebLY45kBEnPezbUKyU= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.3/go.mod h1:u19stRyNPxGhj6dRm+Cdgu6N75qnbW7+QN0q0dsAk58= -github.com/aws/aws-sdk-go-v2/service/sts v1.32.3 h1:wVnQ6tigGsRqSWDEEyH6lSAJ9OyFUsSnbaUWChuSGzs= -github.com/aws/aws-sdk-go-v2/service/sts v1.32.3/go.mod h1:VZa9yTFyj4o10YGsmDO4gbQJUvvhY72fhumT8W4LqsE= +github.com/aws/aws-sdk-go-v2/service/s3 v1.66.3 h1:neNOYJl72bHrz9ikAEED4VqWyND/Po0DnEx64RW6YM4= +github.com/aws/aws-sdk-go-v2/service/s3 v1.66.3/go.mod h1:TMhLIyRIyoGVlaEMAt+ITMbwskSTpcGsCPDq91/ihY0= +github.com/aws/aws-sdk-go-v2/service/sso v1.24.5 h1:HJwZwRt2Z2Tdec+m+fPjvdmkq2s9Ra+VR0hjF7V2o40= +github.com/aws/aws-sdk-go-v2/service/sso v1.24.5/go.mod h1:wrMCEwjFPms+V86TCQQeOxQF/If4vT44FGIOFiMC2ck= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.4 h1:zcx9LiGWZ6i6pjdcoE9oXAB6mUdeyC36Ia/QEiIvYdg= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.4/go.mod h1:Tp/ly1cTjRLGBBmNccFumbZ8oqpZlpdhFf80SrRh4is= +github.com/aws/aws-sdk-go-v2/service/sts v1.32.4 h1:yDxvkz3/uOKfxnv8YhzOi9m+2OGIxF+on3KOISbK5IU= +github.com/aws/aws-sdk-go-v2/service/sts v1.32.4/go.mod h1:9XEUty5v5UAsMiFOBJrNibZgwCeOma73jgGwwhgffa8= github.com/aws/smithy-go v1.22.0 h1:uunKnWlcoL3zO7q+gG2Pk53joueEOsnNB28QdMsmiMM= github.com/aws/smithy-go v1.22.0/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20241009180534-e718692eec62 h1:T5b8GwBFIlqQzAbqTNcyLvzcAvJ09MXrF6zyUlIic8A= @@ -286,20 +286,25 @@ github.com/containerd/continuity v0.4.2 h1:v3y/4Yz5jwnvqPKJJ+7Wf93fyWoCB3F5EclWG github.com/containerd/continuity v0.4.2/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ= github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI= github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M= +github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE= +github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk= github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A= github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw= github.com/containerd/stargz-snapshotter/estargz v0.15.1 h1:eXJjw9RbkLFgioVaTG+G/ZW/0kEe2oEKCdS/ZxIyoCU= github.com/containerd/stargz-snapshotter/estargz v0.15.1/go.mod h1:gr2RNwukQ/S9Nv33Lt6UC7xEx58C+LHRdoqbEKjz1Kk= -github.com/containers/image/v5 v5.32.2 h1:SzNE2Y6sf9b1GJoC8qjCuMBXwQrACFp4p0RK15+4gmQ= -github.com/containers/image/v5 v5.32.2/go.mod h1:v1l73VeMugfj/QtKI+jhYbwnwFCFnNGckvbST3rQ5Hk= +github.com/containerd/typeurl v1.0.2 h1:Chlt8zIieDbzQFzXzAeBEF92KhExuE4p9p92/QmY7aY= +github.com/containerd/typeurl/v2 v2.2.0 h1:6NBDbQzr7I5LHgp34xAXYF5DOTQDn05X58lsPEmzLso= +github.com/containerd/typeurl/v2 v2.2.0/go.mod h1:8XOOxnyatxSWuG8OfsZXVnAF4iZfedjS/8UHSPJnX4g= +github.com/containers/image/v5 v5.33.0 h1:6oPEFwTurf7pDTGw7TghqGs8K0+OvPtY/UyzU0B2DfE= +github.com/containers/image/v5 v5.33.0/go.mod h1:T7HpASmvnp2H1u4cyckMvCzLuYgpD18dSmabSw0AcHk= github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01 h1:Qzk5C6cYglewc+UyGf6lc8Mj2UaPTHy/iF2De0/77CA= github.com/containers/libtrust v0.0.0-20230121012942-c1716e8a8d01/go.mod h1:9rfv8iPl1ZP7aqh9YA68wnZv2NUDbXdcdPHVz0pFbPY= github.com/containers/ocicrypt v1.2.0 h1:X14EgRK3xNFvJEfI5O4Qn4T3E25ANudSOZz/sirVuPM= github.com/containers/ocicrypt v1.2.0/go.mod h1:ZNviigQajtdlxIZGibvblVuIFBKIuUI2M0QM12SD31U= -github.com/containers/storage v1.55.0 h1:wTWZ3YpcQf1F+dSP4KxG9iqDfpQY1otaUXjPpffuhgg= -github.com/containers/storage v1.55.0/go.mod h1:28cB81IDk+y7ok60Of6u52RbCeBRucbFOeLunhER1RQ= +github.com/containers/storage v1.56.0 h1:DZ9KSkj6M2tvj/4bBoaJu3QDHRl35BwsZ4kmLJS97ZI= +github.com/containers/storage v1.56.0/go.mod h1:c6WKowcAlED/DkWGNuL9bvGYqIWCVy7isRMdCSKWNjk= github.com/coreos/go-oidc/v3 v3.11.0 h1:Ia3MxdwpSw702YW0xgfmP1GVCMA9aEFWu12XUZ3/OtI= github.com/coreos/go-oidc/v3 v3.11.0/go.mod h1:gE3LgjOgFoHi9a4ce4/tJczr0Ai2/BoDhf0r5lltWI0= github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= @@ -714,8 +719,9 @@ github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-sqlite3 v1.6.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= -github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +github.com/mattn/go-sqlite3 v1.14.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBWDRM= +github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/miekg/dns v1.1.61 h1:nLxbwF3XxhwVSm8g9Dghm9MHPaUZuqhPiGL+675ZmEs= github.com/miekg/dns v1.1.61/go.mod h1:mnAarhS3nWaW+NVP2wTkYVIZyHNJ098SJZUki3eykwQ= @@ -744,6 +750,8 @@ github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg= github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc= github.com/moby/spdystream v0.5.0 h1:7r0J1Si3QO/kjRitvSLVVFUjxMEb/YLj6S9FF62JBCU= github.com/moby/spdystream v0.5.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI= +github.com/moby/sys/capability v0.3.0 h1:kEP+y6te0gEXIaeQhIi0s7vKs/w0RPoH1qPa6jROcVg= +github.com/moby/sys/capability v0.3.0/go.mod h1:4g9IK291rVkms3LKCDOoYlnV8xKwoDTpIrNEE35Wq0I= github.com/moby/sys/mountinfo v0.7.2 h1:1shs6aH5s4o5H2zQLn796ADW1wMrIwHsyJ2v9KouLrg= github.com/moby/sys/mountinfo v0.7.2/go.mod h1:1YOa8w8Ih7uW0wALDUgT1dTTSBrZ+HiBLGws92L2RU4= github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU= @@ -971,8 +979,6 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= -github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 h1:kdXcSzyDtseVEc4yCz2qF8ZrQvIDBJLl4S1c3GCXmoI= -github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d h1:vfofYNRScrDdvS342BElfbETmL1Aiz3i2t0zfRj16Hs= github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48= github.com/tchap/go-patricia/v2 v2.3.1 h1:6rQp39lgIYZ+MHmdEq4xzuk1t7OdC35z/xm0BGhTkes= @@ -1110,8 +1116,8 @@ golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= -golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= -golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= +golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ= +golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c h1:7dEasQXItcW1xKJ2+gg5VOiBnqWrJc+rq0DPKyvvdbY= golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c/go.mod h1:NQtJDoLvd6faHhE7m4T/1IY708gDefGGjR/iUW8yQQ8= @@ -1155,11 +1161,11 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= -golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= -golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= +golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo= +golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= -golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE= +golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1171,8 +1177,8 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= -golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= +golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1209,8 +1215,8 @@ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= -golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= +golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -1221,8 +1227,8 @@ golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= -golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24= -golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M= +golang.org/x/term v0.26.0 h1:WEQa6V3Gja/BhNxg540hBip/kkaYtRg3cxg4oXSw4AU= +golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -1233,8 +1239,8 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= -golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= +golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ= golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= From d115a37ea75f6c59861643844249c063fed9385a Mon Sep 17 00:00:00 2001 From: "ocmbot[bot]" <125909804+ocmbot[bot]@users.noreply.github.com> Date: Mon, 11 Nov 2024 09:37:08 +0100 Subject: [PATCH 38/58] chore: update 'flake.nix' (#1069) Update OCM CLI vendor hash (see: .github/workflows/flake_vendorhash.yaml) Co-authored-by: ocmbot[bot] <125909804+ocmbot[bot]@users.noreply.github.com> --- flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index 5cd8986466..1f55c69617 100644 --- a/flake.nix +++ b/flake.nix @@ -35,7 +35,7 @@ state = if (self ? rev) then "clean" else "dirty"; # This vendorHash represents a derivative of all go.mod dependencies and needs to be adjusted with every change - vendorHash = "sha256-jKjWnyok8n1UAh03wmfSwZADCWdzhDVKVhyowdhOEqU="; + vendorHash = "sha256-a4es06aTjdnSXV9Xseh3WZ6zprWGM/Yk2PNhQwUZnxM="; src = ./.; From edacaa2a45932fb03e511517f72231821eac9217 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakob=20M=C3=B6ller?= Date: Mon, 11 Nov 2024 10:28:59 +0100 Subject: [PATCH 39/58] chore: allow publishing to Brew via custom script (#1059) #### What this PR does / why we need it Part of the release rework (https://github.com/open-component-model/ocm/issues/995) that will allow us to move away from goreleaser for actual release work. This fully replaces the goreleaser workflow of updating the brew TAP with a PR that creates a versioned link in a PR towards the TAP repository. This allows - versioned brew installations like `brew install open-component-model/tap/ocm@0.17.0` instead of just the latest release - Allows us to run the goreleaser process without ever publishing any artifact externally #### Which issue(s) this PR fixes --- .github/config/goreleaser.yaml | 12 -- .../publish-to-other-than-github.yaml | 59 +++++++ .../workflows/retrigger-publish-to-other.yaml | 7 +- hack/brew/go.mod | 3 + hack/brew/internal/generate.go | 116 ++++++++++++++ hack/brew/internal/generate_test.go | 145 ++++++++++++++++++ .../brew/internal/ocm_formula_template.rb.tpl | 55 +++++++ .../internal/testdata/expected_formula.rb | 54 +++++++ hack/brew/main.go | 41 +++++ 9 files changed, 479 insertions(+), 13 deletions(-) create mode 100644 hack/brew/go.mod create mode 100644 hack/brew/internal/generate.go create mode 100644 hack/brew/internal/generate_test.go create mode 100644 hack/brew/internal/ocm_formula_template.rb.tpl create mode 100644 hack/brew/internal/testdata/expected_formula.rb create mode 100644 hack/brew/main.go diff --git a/.github/config/goreleaser.yaml b/.github/config/goreleaser.yaml index 60696bf9f3..351813dd65 100644 --- a/.github/config/goreleaser.yaml +++ b/.github/config/goreleaser.yaml @@ -90,18 +90,6 @@ changelog: - '^docs:' - '^test:' -brews: - - name: ocm - repository: - owner: open-component-model - name: homebrew-tap - token: "{{ .Env.HOMEBREW_TAP_GITHUB_TOKEN }}" - directory: Formula - homepage: "https://ocm.software/" - description: "The OCM CLI makes it easy to create component versions and embed them in build processes." - test: | - system "#{bin}/ocm --version" - nfpms: - id: debian package_name: ocm-cli diff --git a/.github/workflows/publish-to-other-than-github.yaml b/.github/workflows/publish-to-other-than-github.yaml index 4648c8261a..012821ff04 100644 --- a/.github/workflows/publish-to-other-than-github.yaml +++ b/.github/workflows/publish-to-other-than-github.yaml @@ -12,6 +12,65 @@ on: types: [publish-ocm-cli] jobs: + push-to-brew-tap: + name: Update Homebrew Tap + if: github.event.client_payload.push-to-brew-tap && github.event.client_payload.version != '' + runs-on: ubuntu-latest + env: + REPO: open-component-model/homebrew-tap + steps: + - name: Ensure proper version + run: echo "RELEASE_VERSION=$(echo ${{ github.event.client_payload.version }} | tr -d ['v'])" >> $GITHUB_ENV + - name: Generate token + id: generate_token + uses: tibdex/github-app-token@v2 + with: + app_id: ${{ secrets.OCMBOT_APP_ID }} + private_key: ${{ secrets.OCMBOT_PRIV_KEY }} + - name: Checkout + uses: actions/checkout@v4 + with: + path: tap + repository: ${{ env.REPO }} + token: ${{ steps.generate_token.outputs.token }} + - name: Get Update Script + uses: actions/checkout@v4 + with: + path: scripts + sparse-checkout: | + hack/brew + - name: Setup Go + uses: actions/setup-go@v5 + with: + go-version-file: ${{ github.workspace }}/scripts/hack/brew/go.mod + cache: false + - name: Build Script + working-directory: ${{ github.workspace }}/scripts/hack/brew + run: go build -o script + - name: Update Homebrew Tap + run: | + formula=$(${{ github.workspace }}/scripts/hack/brew/script \ + --version ${{ env.RELEASE_VERSION }} \ + --template ${{ github.workspace }}/scripts/hack/brew/internal/ocm_formula_template.rb.tpl \ + --outputDirectory ${{ github.workspace }}/tap/Formula) + mkdir -p ${{ github.workspace }}/tap/Aliases + cd ${{ github.workspace }}/tap/Aliases + ln -s ../Formula/$(basename $formula) ./ocm + - name: Create Pull Request + uses: peter-evans/create-pull-request@v7 + with: + path: tap + token: ${{ steps.generate_token.outputs.token }} + title: "chore: update OCM CLI to v${{ env.RELEASE_VERSION }}" + commit-message: "[github-actions] update OCM CLI to v${{ env.RELEASE_VERSION }}" + branch: chore/update-ocm-cli/${{ env.RELEASE_VERSION }} + delete-branch: true + sign-commits: true + add-paths: | + Formula/* + Aliases/* + body: | + Update OCM CLI to v${{ env.RELEASE_VERSION }}. push-to-aur: name: Update Arch Linux User Repository diff --git a/.github/workflows/retrigger-publish-to-other.yaml b/.github/workflows/retrigger-publish-to-other.yaml index 6226bf3eb4..57219180d2 100644 --- a/.github/workflows/retrigger-publish-to-other.yaml +++ b/.github/workflows/retrigger-publish-to-other.yaml @@ -23,6 +23,11 @@ on: description: Do you want to push to Winget? required: false default: false + push-to-brew-tap: + type: boolean + description: Do you want to push to the Homebrew Tap at https://github.com/open-component-model/homebrew-tap? + required: false + default: false jobs: retrigger: @@ -57,4 +62,4 @@ jobs: token: ${{ steps.generate_token.outputs.token }} repository: ${{ github.repository_owner }}/ocm event-type: publish-ocm-cli - client-payload: '{"version":"${{ env.RELEASE_VERSION }}","push-to-aur":${{ github.event.inputs.push-to-aur }},"push-to-chocolatey":${{ github.event.inputs.push-to-chocolatey }},"push-to-winget":${{ github.event.inputs.push-to-winget }}}' + client-payload: '{"version":"${{ env.RELEASE_VERSION }}","push-to-aur":${{ github.event.inputs.push-to-aur }},"push-to-chocolatey":${{ github.event.inputs.push-to-chocolatey }},"push-to-winget":${{ github.event.inputs.push-to-winget }},"push-to-brew-tap":${{ github.event.inputs.push-to-brew-tap }}}' diff --git a/hack/brew/go.mod b/hack/brew/go.mod new file mode 100644 index 0000000000..e68d38213a --- /dev/null +++ b/hack/brew/go.mod @@ -0,0 +1,3 @@ +module ocm.software/ocm/hack/brew + +go 1.23.2 \ No newline at end of file diff --git a/hack/brew/internal/generate.go b/hack/brew/internal/generate.go new file mode 100644 index 0000000000..2c9f68d1a9 --- /dev/null +++ b/hack/brew/internal/generate.go @@ -0,0 +1,116 @@ +package internal + +import ( + "errors" + "fmt" + "io" + "net/http" + "os" + "path/filepath" + "strings" + "text/template" +) + +const ClassName = "Ocm" + +// GenerateVersionedHomebrewFormula generates a Homebrew formula for a specific version, +// architecture, and operating system. It fetches the SHA256 digest for each combination +// and uses a template to create the formula file. +func GenerateVersionedHomebrewFormula( + version string, + architectures []string, + operatingSystems []string, + releaseURL string, + templateFile string, + outputDir string, + writer io.Writer, +) error { + values := map[string]string{ + "ReleaseURL": releaseURL, + "Version": version, + } + + for _, targetOs := range operatingSystems { + for _, arch := range architectures { + digest, err := FetchDigestFromGithubRelease(releaseURL, version, targetOs, arch) + if err != nil { + return fmt.Errorf("failed to fetch digest for %s/%s: %w", targetOs, arch, err) + } + values[fmt.Sprintf("%s_%s_sha256", targetOs, arch)] = digest + } + } + + if err := GenerateFormula(templateFile, outputDir, version, values, writer); err != nil { + return fmt.Errorf("failed to generate formula: %w", err) + } + + return nil +} + +// FetchDigestFromGithubRelease retrieves the SHA256 digest for a specific version, operating system, and architecture +// from the given release URL. +func FetchDigestFromGithubRelease(releaseURL, version, targetOs, arch string) (_ string, err error) { + url := fmt.Sprintf("%s/v%s/ocm-%s-%s-%s.tar.gz.sha256", releaseURL, version, version, targetOs, arch) + resp, err := http.Get(url) + if err != nil { + return "", fmt.Errorf("failed to get digest: %w", err) + } + defer func() { + err = errors.Join(err, resp.Body.Close()) + }() + + digestBytes, err := io.ReadAll(resp.Body) + if err != nil { + return "", fmt.Errorf("failed to read digest: %w", err) + } + + return strings.TrimSpace(string(digestBytes)), nil +} + +// GenerateFormula generates the Homebrew formula file using the provided template and values. +func GenerateFormula(templateFile, outputDir, version string, values map[string]string, writer io.Writer) error { + tmpl, err := template.New(filepath.Base(templateFile)).Funcs(template.FuncMap{ + "classname": func() string { + return fmt.Sprintf("%sAT%s", ClassName, strings.ReplaceAll(version, ".", "")) + }, + }).ParseFiles(templateFile) + if err != nil { + return fmt.Errorf("failed to parse template: %w", err) + } + + outputFile := fmt.Sprintf("ocm@%s.rb", version) + if err := ensureDirectory(outputDir); err != nil { + return err + } + + versionedFormula, err := os.Create(filepath.Join(outputDir, outputFile)) + if err != nil { + return fmt.Errorf("failed to create output file: %w", err) + } + defer versionedFormula.Close() + + if err := tmpl.Execute(versionedFormula, values); err != nil { + return fmt.Errorf("failed to execute template: %w", err) + } + + if _, err := io.WriteString(writer, versionedFormula.Name()); err != nil { + return fmt.Errorf("failed to write output file path: %w", err) + } + + return nil +} + +// ensureDirectory checks if a directory exists and creates it if it does not. +func ensureDirectory(dir string) error { + fi, err := os.Stat(dir) + if os.IsNotExist(err) { + if err := os.MkdirAll(dir, 0755); err != nil { + return fmt.Errorf("failed to create directory: %w", err) + } + } else if err != nil { + return fmt.Errorf("failed to stat directory: %w", err) + } else if !fi.IsDir() { + return fmt.Errorf("path is not a directory") + } + return nil +} diff --git a/hack/brew/internal/generate_test.go b/hack/brew/internal/generate_test.go new file mode 100644 index 0000000000..02fc0620e7 --- /dev/null +++ b/hack/brew/internal/generate_test.go @@ -0,0 +1,145 @@ +package internal + +import ( + "bytes" + _ "embed" + "fmt" + "net/http" + "net/http/httptest" + "os" + "path/filepath" + "strings" + "testing" +) + +//go:embed ocm_formula_template.rb.tpl +var tplFile []byte + +//go:embed testdata/expected_formula.rb +var expectedResolved []byte + +func TestGenerateVersionedHomebrewFormula(t *testing.T) { + version := "1.0.0" + architectures := []string{"amd64", "arm64"} + operatingSystems := []string{"darwin", "linux"} + outputDir := t.TempDir() + + templateFile := filepath.Join(outputDir, "ocm_formula_template.rb.tpl") + if err := os.WriteFile(templateFile, tplFile, os.ModePerm); err != nil { + t.Fatalf("failed to write template file: %v", err) + } + + dummyDigest := "dummy-digest" + // Mock server to simulate fetching digests + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(dummyDigest)) + })) + defer server.Close() + expectedResolved = bytes.ReplaceAll(expectedResolved, []byte("$$TEST_SERVER$$"), []byte(server.URL)) + + var buf bytes.Buffer + + err := GenerateVersionedHomebrewFormula( + version, + architectures, + operatingSystems, + server.URL, + templateFile, + outputDir, + &buf, + ) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + + file := buf.String() + + fi, err := os.Stat(file) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + if fi.Size() == 0 { + t.Fatalf("expected file to be non-empty") + } + if filepath.Ext(file) != ".rb" { + t.Fatalf("expected file to have .rb extension") + } + if !strings.Contains(file, version) { + t.Fatalf("expected file to contain version") + } + + data, err := os.ReadFile(file) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + + if string(data) != string(expectedResolved) { + t.Fatalf("expected %s, got %s", string(expectedResolved), string(data)) + } +} + +func TestFetchDigest(t *testing.T) { + expectedDigest := "dummy-digest" + version := "1.0.0" + targetOS, arch := "linux", "amd64" + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.URL.Path != "/v1.0.0/ocm-1.0.0-linux-amd64.tar.gz.sha256" { + t.Fatalf("expected path %s, got %s", fmt.Sprintf("/v%[1]s/ocm-%[1]s-%s-%s.tar.gz.sha256", version, targetOS, arch), r.URL.Path) + } + w.Write([]byte(expectedDigest)) + })) + defer server.Close() + + digest, err := FetchDigestFromGithubRelease(server.URL, version, targetOS, arch) + if err != nil { + t.Fatalf("expected no error, got %v", err) + } + if digest != expectedDigest { + t.Fatalf("expected %s, got %s", expectedDigest, digest) + } +} + +func TestGenerateFormula(t *testing.T) { + templateContent := `class {{ classname }} < Formula +version "{{ .Version }}" +end` + templateFile := "test_template.rb.tpl" + if err := os.WriteFile(templateFile, []byte(templateContent), 0644); err != nil { + t.Fatalf("failed to write template file: %v", err) + } + defer os.Remove(templateFile) + + outputDir := t.TempDir() + values := map[string]string{"Version": "1.0.0"} + + var buf bytes.Buffer + + if err := GenerateFormula(templateFile, outputDir, "1.0.0", values, &buf); err != nil { + t.Fatalf("expected no error, got %v", err) + } + + if buf.String() == "" { + t.Fatalf("expected non-empty output") + } + + outputFile := filepath.Join(outputDir, "ocm@1.0.0.rb") + if _, err := os.Stat(outputFile); os.IsNotExist(err) { + t.Fatalf("expected output file to exist") + } +} + +func TestEnsureDirectory(t *testing.T) { + dir := t.TempDir() + if err := ensureDirectory(dir); err != nil { + t.Fatalf("expected no error, got %v", err) + } + + nonDirFile := filepath.Join(dir, "file") + if err := os.WriteFile(nonDirFile, []byte("content"), 0644); err != nil { + t.Fatalf("failed to write file: %v", err) + } + + if err := ensureDirectory(nonDirFile); err == nil { + t.Fatalf("expected error, got nil") + } +} diff --git a/hack/brew/internal/ocm_formula_template.rb.tpl b/hack/brew/internal/ocm_formula_template.rb.tpl new file mode 100644 index 0000000000..60a7f9013c --- /dev/null +++ b/hack/brew/internal/ocm_formula_template.rb.tpl @@ -0,0 +1,55 @@ +{{- /* Go template for Homebrew Formula */ -}} +# typed: false +# frozen_string_literal: true + +class {{ classname }} < Formula + desc "The OCM CLI makes it easy to create component versions and embed them in build processes." + homepage "https://ocm.software/" + version "{{ .Version }}" + + on_macos do + on_intel do + url "{{ .ReleaseURL }}/v{{ .Version }}/ocm-{{ .Version }}-darwin-amd64.tar.gz" + sha256 "{{ .darwin_amd64_sha256 }}" + + def install + bin.install "ocm" + end + end + on_arm do + url "{{ .ReleaseURL }}/v{{ .Version }}/ocm-{{ .Version }}-darwin-arm64.tar.gz" + sha256 "{{ .darwin_arm64_sha256 }}" + + def install + bin.install "ocm" + end + end + end + + on_linux do + on_intel do + if Hardware::CPU.is_64_bit? + url "{{ .ReleaseURL }}/v{{ .Version }}/ocm-{{ .Version }}-linux-amd64.tar.gz" + sha256 "{{ .linux_amd64_sha256 }}" + + def install + bin.install "ocm" + end + end + end + on_arm do + if Hardware::CPU.is_64_bit? + url "{{ .ReleaseURL }}/v{{ .Version }}/ocm-{{ .Version }}-linux-arm64.tar.gz" + sha256 "{{ .linux_arm64_sha256 }}" + + def install + bin.install "ocm" + end + end + end + end + + test do + system "#{bin}/ocm --version" + end +end diff --git a/hack/brew/internal/testdata/expected_formula.rb b/hack/brew/internal/testdata/expected_formula.rb new file mode 100644 index 0000000000..4adf158cb6 --- /dev/null +++ b/hack/brew/internal/testdata/expected_formula.rb @@ -0,0 +1,54 @@ +# typed: false +# frozen_string_literal: true + +class OcmAT100 < Formula + desc "The OCM CLI makes it easy to create component versions and embed them in build processes." + homepage "https://ocm.software/" + version "1.0.0" + + on_macos do + on_intel do + url "$$TEST_SERVER$$/v1.0.0/ocm-1.0.0-darwin-amd64.tar.gz" + sha256 "dummy-digest" + + def install + bin.install "ocm" + end + end + on_arm do + url "$$TEST_SERVER$$/v1.0.0/ocm-1.0.0-darwin-arm64.tar.gz" + sha256 "dummy-digest" + + def install + bin.install "ocm" + end + end + end + + on_linux do + on_intel do + if Hardware::CPU.is_64_bit? + url "$$TEST_SERVER$$/v1.0.0/ocm-1.0.0-linux-amd64.tar.gz" + sha256 "dummy-digest" + + def install + bin.install "ocm" + end + end + end + on_arm do + if Hardware::CPU.is_64_bit? + url "$$TEST_SERVER$$/v1.0.0/ocm-1.0.0-linux-arm64.tar.gz" + sha256 "dummy-digest" + + def install + bin.install "ocm" + end + end + end + end + + test do + system "#{bin}/ocm --version" + end +end diff --git a/hack/brew/main.go b/hack/brew/main.go new file mode 100644 index 0000000000..825cb925bc --- /dev/null +++ b/hack/brew/main.go @@ -0,0 +1,41 @@ +package main + +import ( + "flag" + "log" + "os" + "strings" + + "ocm.software/ocm/hack/brew/internal" +) + +const DefaultReleaseURL = "https://github.com/open-component-model/ocm/releases/download" +const DefaultFormulaTemplate = "hack/brew/internal/ocm_formula_template.rb.tpl" +const DefaultArchitectures = "amd64,arm64" +const DefaultOperatingSystems = "darwin,linux" + +func main() { + version := flag.String("version", "", "version of the OCM formula") + outputDir := flag.String("outputDirectory", ".", "path to the output directory") + templateFile := flag.String("template", DefaultFormulaTemplate, "path to the template file") + architecturesRaw := flag.String("arch", DefaultArchitectures, "comma-separated list of architectures") + operatingSystemsRaw := flag.String("os", DefaultOperatingSystems, "comma-separated list of operating systems") + releaseURL := flag.String("releaseURL", DefaultReleaseURL, "URL to fetch the release from") + + flag.Parse() + + if *version == "" { + log.Fatalf("version is required") + } + + if err := internal.GenerateVersionedHomebrewFormula(*version, + strings.Split(*architecturesRaw, ","), + strings.Split(*operatingSystemsRaw, ","), + *releaseURL, + *templateFile, + *outputDir, + os.Stdout, + ); err != nil { + log.Fatalf("failed to generate formula: %v", err) + } +} From 1cfc3c4b1fad352a67db297a6a427577041c1ca5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakob=20M=C3=B6ller?= Date: Mon, 11 Nov 2024 10:47:20 +0100 Subject: [PATCH 40/58] chore: remove ocm inception during build CTF aggregation (#1065) While building the components we face several layers of what I would call "OCM Inception". This is the problem that while building and packaging OCM, we need OCM. To solve this chicken and egg problem, a small intermediary script is now introduced that reuses the OCM from the built CTF. #### What this PR does / why we need it #### Which issue(s) this PR fixes --- .github/workflows/components.yaml | 59 ++++++++++++++---------------- hack/get_bare_resource_from_ctf.sh | 59 ++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+), 31 deletions(-) create mode 100644 hack/get_bare_resource_from_ctf.sh diff --git a/.github/workflows/components.yaml b/.github/workflows/components.yaml index ca944d5cfe..ff7f6b9af4 100644 --- a/.github/workflows/components.yaml +++ b/.github/workflows/components.yaml @@ -89,31 +89,6 @@ jobs: uses: TooMuch4U/actions-clean@v2.2 - name: Checkout uses: actions/checkout@v4 - - name: Setup Go - uses: actions/setup-go@v5 - with: - go-version-file: '${{ github.workspace }}/go.mod' - cache: false - - name: Get go environment for use with cache - run: | - echo "go_cache=$(go env GOCACHE)" >> $GITHUB_ENV - echo "go_modcache=$(go env GOMODCACHE)" >> $GITHUB_ENV - # This step will only reuse the go mod and build cache from main made during the Build, - # see push_ocm.yaml => "ocm-cli-latest" Job - # This means it never caches by itself and PRs cannot cause cache pollution / thrashing - # This is because we have huge storage requirements for our cache because of the mass of dependencies - - name: Restore / Reuse Cache from central build - id: cache-golang-restore - uses: actions/cache/restore@v4 # Only Restore, not build another cache (too big) - with: - path: | - ${{ env.go_cache }} - ${{ env.go_modcache }} - key: ${{ env.cache_name }}-${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}-${{ hashFiles('**/go.mod') }} - restore-keys: | - ${{ env.cache_name }}-${{ runner.os }}-go- - env: - cache_name: ocm-cli-latest-go-cache # needs to be the same key in the end as in the build step - name: Download CTFs uses: actions/download-artifact@v4 with: @@ -127,15 +102,37 @@ jobs: mv ${{ github.workspace }}/gen/downloaded-ctfs/ctf-component-${i} ${{ github.workspace }}/gen/${i}/ctf ls -R ${{ github.workspace }}/gen/${i} done + - name: Extract OCM Binary from CTF to avoid OCM Inception + id: extract-ocm + run: | + ocm_binary=$(bash ./hack/get_bare_resource_from_ctf.sh \ + "ocm.software/ocmcli" \ + "" \ + "ocmcli" \ + $(go env GOARCH) \ + $(go env GOOS) \ + "application/octet-stream" \ + ${{ github.workspace }}/gen/ocmcli/ctf) + + new_loc=${{ github.workspace }}/bin/ocm + mkdir -p $(dirname $new_loc) + ln -s $ocm_binary $new_loc + chmod +x $new_loc + echo "OCM binary linked to $new_loc" + echo "binary=$new_loc" >> $GITHUB_OUTPUT - name: Create aggregated CTF run: | - PATH=$PATH:$(go env GOPATH)/bin \ - CTF_TYPE=${{ env.CTF_TYPE }} \ - COMPONENTS="${{ env.components }}" \ - make plain-ctf + for i in ${{ env.components }}; do + echo "transfering component $i..." + ${{ steps.extract-ocm.outputs.binary }} transfer cv \ + --type ${{ env.CTF_TYPE }} -V \ + ${{ github.workspace }}/gen/$i/ctf \ + ${{ github.workspace }}/gen/ctf + done - name: Upload aggregated CTF - # only upload the artifact if we are not on a PR - if: needs.pr-check.outputs.number != 'null' + # TODO This is currently permanently disabled, + # until we integrate it with the release build, in which it would be reused + if: false uses: actions/upload-artifact@v4 with: if-no-files-found: error diff --git a/hack/get_bare_resource_from_ctf.sh b/hack/get_bare_resource_from_ctf.sh new file mode 100644 index 0000000000..242c85da98 --- /dev/null +++ b/hack/get_bare_resource_from_ctf.sh @@ -0,0 +1,59 @@ +#!/bin/bash + +set -e + +# This script is used to get a bare resource from a CTF file. +# It can be used in case the OCM CLI is not available to extract the resource from a CTF. +# A typical use case for this is the "OCM Inception" in which a CTF containing the CLI needs to be extracted +# to run the CLI to extract the resource. +# +# In this case one can use this script to extract the correct OCM CLI without having to rely on the CLI being +# already available. +# +# By default the script will look for the OCM CLI component with any version (the first encountered will be used) +# and will extract the resource "ocmcli" for amd64/linux as a filepath. This path can then be used to run the CLI, +# but only after allowing to execute it, e.g with `chmod +x `. + +COMPONENT=${1:-"ocm.software/ocmcli"} +COMPONENT_VERSION=${2:-""} +RESOURCE=${3:-"ocmcli"} +ARCHITECTURE=${4:-"amd64"} +OS=${5:-"linux"} +MEDIA_TYPE=${6:-"application/octet-stream"} +PATH_TO_CTF=${7:-"./gen/ctf"} + +INDEX=$( \ +yq -r ".artifacts | filter(.repository == \"component-descriptors/${COMPONENT}\" and (.tag | contains(\"${COMPONENT_VERSION}\")))[0].digest" \ + "${PATH_TO_CTF}"/artifact-index.json | \ + sed 's/:/./g' \ +) + +if [ -z "${INDEX}" ]; then + echo "No index found for ${COMPONENT}" + exit 1 +fi + +RESOURCE=$( \ +yq ".layers | filter( + ( + .annotations.\"software.ocm.artifact\" | + from_json | + .[0] + ) as \$artifact | + ( + \$artifact.identity.name == \"$RESOURCE\" and + \$artifact.identity.architecture == \"$ARCHITECTURE\" and + \$artifact.identity.os == \"$OS\" and + .mediaType == \"$MEDIA_TYPE\" + ) + )[0].digest" "${PATH_TO_CTF}"/blobs/"${INDEX}" | sed 's/:/./g' \ +) + +if [ -z "${RESOURCE}" ]; then + echo "No resource found for ${COMPONENT}" + exit 1 +fi + +RESOURCE=$PATH_TO_CTF/blobs/$RESOURCE + +echo "$RESOURCE" From 49c047f6cd4c089d9fad718cab5728ab9073c2b0 Mon Sep 17 00:00:00 2001 From: Uwe Krueger Date: Mon, 11 Nov 2024 12:32:40 +0100 Subject: [PATCH 41/58] doc resource management (#1035) #### What this PR does / why we need it Extend the tour documentation to illustrate the rules for complying to the resource management used by this library. #### Which issue(s) this PR fixes --- .github/config/wordlist.txt | 1 + api/ocm/internal/accesstypes.go | 2 +- .../lib/tour/07-resource-management/README.md | 297 ++++++++++++++++++ .../tour/07-resource-management/example.go | 259 +++++++++++++++ .../lib/tour/07-resource-management/main.go | 14 + examples/lib/tour/README.md | 1 + .../docsrc/07-resource-management/README.md | 158 ++++++++++ examples/lib/tour/docsrc/README.md | 1 + 8 files changed, 732 insertions(+), 1 deletion(-) create mode 100644 examples/lib/tour/07-resource-management/README.md create mode 100644 examples/lib/tour/07-resource-management/example.go create mode 100644 examples/lib/tour/07-resource-management/main.go create mode 100644 examples/lib/tour/docsrc/07-resource-management/README.md diff --git a/.github/config/wordlist.txt b/.github/config/wordlist.txt index 7a2e1647a7..81e7bd3d34 100644 --- a/.github/config/wordlist.txt +++ b/.github/config/wordlist.txt @@ -236,6 +236,7 @@ repocpi repositoryimpl repositoryspec resendbuffer +resmgmt resolvers resourcereference routings diff --git a/api/ocm/internal/accesstypes.go b/api/ocm/internal/accesstypes.go index 707c223e64..42f87e6891 100644 --- a/api/ocm/internal/accesstypes.go +++ b/api/ocm/internal/accesstypes.go @@ -97,7 +97,7 @@ type AccessMethod interface { // AsBlobAccess maps a method object into a // basic blob access interface. // It does not provide a separate reference, - // closing the blob access with close the + // closing the blob access will close the // access method. AsBlobAccess() BlobAccess } diff --git a/examples/lib/tour/07-resource-management/README.md b/examples/lib/tour/07-resource-management/README.md new file mode 100644 index 0000000000..a72611efc7 --- /dev/null +++ b/examples/lib/tour/07-resource-management/README.md @@ -0,0 +1,297 @@ + + + +# Resource Management + + + +This tour illustrates the basic contract to +correctly work with closeable object references used +in the library. + +Many objects provided by the library offer some kind of resource management. In the [first example](../01-getting-started/README.md#getting-started), this is an +OCM repository, the OCM component, component version and the access method. +Another important kind of objects are the `BlobAccess` implementations. + +Those objects may use external resources, like temporary file system content or caches. To get rid of those resources again, they offer a `Close` method. + +To achieve the possibility to pass those objects around in non-functional call contexts they feature some kind of resource management. It allows to handle +the life cycle of the resource in a completely local manner. To do so, a second method `Dup` is offered, which provides an independent reference to the original resources, which can be closed separately. +The possible externally held resource are released with the close of the last reference. + +This offers a simple contract to handle resources in functions or object methods: + +1. a function creating such an object is responsible for the life cycle of its reference + + - if the object is returned, this responsibility is passed to its caller + + ```go + func f() (Object, error) { + o, err:= Create() + if err != nil { + return nil, err + } + o.DoSomeThing() + DoSomeThingOther(o) + return o, nil + } + ``` + + - otherwise, it must be closed at the end of the function (or if it is not used anymore) + + ```go + func f() error { + o, err:= Create() + if err != nil { + return err + } + defer o.Close() + o.DoSomeThing() + DoSomeThingOther(o) + } + ``` + + The object may be passed to any called function without bothering what this function does with this reference. + +2. a function receiving such an object from a function as result it inherits the responsibility to close it again (see case 1) + +3. a function receiving such an object as an argument can freely use it and a pass it around. + + ```go + func f(o Object) { + o.DoSomeThing() + DoSomeThingOther(o) + } + ``` + + If it decides to store the reference in some state, it must use an own reference for this, obtained by a call to `Dup`. After obtaining an own reference the used storage context is responsible to close it again. It should never close the obtained reference, because the caller is responsible for this. + + ```go + func (r *State) f(o Object) (err error) { + r.obj, err = o.Dup() + return err + } + + func (r *State) Close() error { + if r.obj == nil { + return nil + } + return r.obj.Close() + } + ``` + +## Running the example + +You can call the main program without any argument. + +## Walkthrough + +The example is based on the initial [getting started scenario](../01-getting-started/README.md#getting-started). +It separates the resource gathering from the handling of the found resources. + +```go + // gathering resources, this is completely hidden + // behind an implementation. + resources, err := GatherResources(ctx, CachingFactory{}) + if err != nil { + return err + } + + var list errors.ErrorList + + list.Add(HandleResources(resources)) + + // we are done, so close the resources, again. + for i, r := range resources { + list.Addf(nil, r.Close(), "closing resource %d", i) + } + return list.Result() +``` + +The resources are provided by an array of the interface `Resource`: + +```go +type Resource interface { + GetIdentity() metav1.Identity + GetType() string + GetAccess() string + GetData() ([]byte, error) + + SetError(s string) + AddDataFromMethod(ctx ocm.ContextProvider, m ocm.AccessMethod) error + + Close() error +} + +``` + +It encapsulates the technical resource handling +and offers a `Close` method, also, to release potential local resources. + +The example provides one implementation, using the original access method +to cache the data to avoid additional copies. + +```go +// resource is a Resource implementation using +// the original access method to cache the content. +type resource struct { + Identity metav1.Identity + ArtifactType string + Access string + Data blobaccess.BlobAccess +} + +var _ Resource = (*resource)(nil) + +func (r *resource) AddDataFromMethod(ctx ocm.ContextProvider, m ocm.AccessMethod) error { + // provide an own reference to the method + // to store this in the provided resource object. + priv, err := m.Dup() + if err != nil { + return err + } + + // release a possible former cache entry + if r.Data != nil { + r.Data.Close() + } + r.Data = priv.AsBlobAccess() + // release obsolete blob access + r.Access = m.AccessSpec().Describe(ctx.OCMContext()) + return nil +} + +// Close releases the cached access. +func (r *resource) Close() error { + c := r.Data + if c == nil { + return nil + } + r.Data = nil + return c.Close() +} + +``` + +The `AddDataFromMethod` uses `Dup` to provide an own reference to the +access method, which is stored in the provided resource object. +It implements the `Close` method to release this cached content, again. +The responsibility for this reference is taken by the `resource`object. + +In the `GatherResources` function, a repository access is created. +It is not forwarded, and therefore closed, again, in this function. + +```go + repo, err := ctx.RepositoryForSpec(spec) + if err != nil { + return nil, errors.Wrapf(err, "cannot setup repository") + } + + // to release potentially allocated temporary resources, + // many objects must be closed, if they should not be used + // anymore. + // This is typically done by a `defer` statement placed after a + // successful object retrieval. + defer repo.Close() +``` + +The same is done for the component version lookup. + +```go + c, err := repo.LookupComponent("ocm.software/ocmcli") + if err != nil { + return nil, errors.Wrapf(err, "cannot lookup component") + } + defer c.Close() +``` + +Then the resource `factory` is used to create the `Resource` objects for +the resources found in the component version. + +```go + for _, r := range cv.GetResources() { + res := factory.Create( + r.Meta().GetIdentity(cv.GetDescriptor().Resources), + r.Meta().GetType(), + ) + acc, err := r.Access() + if err != nil { + res.SetError(err.Error()) + } else { + m, err := acc.AccessMethod(cv) + if err == nil { + // delegate data handling to target + // we don't know, how this is implemented. + err = res.AddDataFromMethod(ctx, m) + if err != nil { + res.SetError(err.Error()) + } + // release local usage of the access method object + m.Close() + } else { + res.SetError(err.Error()) + } + } + resources = append(resources, res) + } +``` + +Because the function cannot know what happens behind the call to +`AddDataFromMethod`, it just closes everything what is created +in the function, this also includes the access method (`m`). + +Finally, it returns the resource array after all locally created +references are correctly closed. +The provided `Resource` objects have taken the responsibility for +keeping their own references. + +The resource handling function just uses the resources. + +```go +func HandleResources(resources []Resource) error { + var list errors.ErrorList + fmt.Printf("*** resources:\n") + for i, r := range resources { + fmt.Printf(" %2d: extra identity: %s\n", i+1, r.GetIdentity()) + fmt.Printf(" resource type: %s\n", r.GetType()) + fmt.Printf(" access: %s\n", r.GetAccess()) + } + + return list.Result() +} + +``` + +The responsibility for closing the resources has been passed to +the `ResourceManagement` functions, which calls the gather and +the handling function. Therefore, it calls the `Resource.Close` +function before finishing. + +The final output of this example looks like: + +```yaml +versions for component ocm.software/ocmcli: 0.1.0-alpha.2, 0.1.0-dev, 0.3.0-dev, 0.3.0-rc.2, 0.3.0-rc.3, 0.3.0, 0.4.0-dev, 0.4.0, 0.4.1, 0.4.2, 0.4.3, 0.5.0, 0.6.0, 0.7.0, 0.8.0, 0.9.0, 0.10.0, 0.11.0, 0.12.0, 0.12.1, 0.13.0, 0.14.0, 0.15.0, 0.16.0, 0.16.1, 0.16.2, 0.17.0-rc.1, 0.17.0, 0.18.0-rc.1 +looking up resources of the latest version: + version: 0.18.0-rc.1 + provider: ocm.software +*** resources: + 1: extra identity: "architecture"="amd64","name"="ocmcli","os"="linux" + resource type: executable + access: Local blob sha256:74fdf71c5467cacd1cb09d15d6ad4944d60cc8efa1d704a91c337e54dcd03fbc[] + 2: extra identity: "architecture"="arm64","name"="ocmcli","os"="linux" + resource type: executable + access: Local blob sha256:d0022850cce685d48ca589b3b59913ecbc3572f7f5082bca5c086a4bf2b47c5a[] + 3: extra identity: "architecture"="arm64","name"="ocmcli","os"="darwin" + resource type: executable + access: Local blob sha256:1161fc38d0fe78ba3be97783f8676a46afa2baf57c199f937798f791cc4961d3[] + 4: extra identity: "architecture"="amd64","name"="ocmcli","os"="darwin" + resource type: executable + access: Local blob sha256:33074ce5cc079ea4fc1dbcc7bd54c27cc93f0e188d9ad8c56ba642c4ba6744af[] + 5: extra identity: "architecture"="amd64","name"="ocmcli","os"="windows" + resource type: executable + access: Local blob sha256:2fbac39d7772ae1cf209aca5bb5efdbb6b91e83aede9464c52304c3ccebb4f67[] + 6: extra identity: "name"="ocmcli-image" + resource type: ociImage + access: OCI artifact ghcr.io/open-component-model/ocm/ocm.software/ocmcli/ocmcli-image:0.18.0-rc.1@sha256:3ba3e8c075f7f91e851ec3ce53da2347fe464b3ac33c6d65cf89a459193bb5cb + +``` diff --git a/examples/lib/tour/07-resource-management/example.go b/examples/lib/tour/07-resource-management/example.go new file mode 100644 index 0000000000..c5c0f73809 --- /dev/null +++ b/examples/lib/tour/07-resource-management/example.go @@ -0,0 +1,259 @@ +package main + +import ( + "fmt" + "strings" + + "github.com/mandelsoft/goutils/errors" + "ocm.software/ocm/api/utils/blobaccess/blobaccess" + + "ocm.software/ocm/api/ocm" + metav1 "ocm.software/ocm/api/ocm/compdesc/meta/v1" + "ocm.software/ocm/api/ocm/extensions/repositories/ocireg" + "ocm.software/ocm/api/utils/semverutils" +) + +// --- begin resource interface --- +type Resource interface { + GetIdentity() metav1.Identity + GetType() string + GetAccess() string + GetData() ([]byte, error) + + SetError(s string) + AddDataFromMethod(ctx ocm.ContextProvider, m ocm.AccessMethod) error + + Close() error +} + +// --- end resource interface --- + +// --- begin resource factory --- +// ResourceFactory is used to create a particular resource object. +type ResourceFactory interface { + Create(id metav1.Identity, typ string) Resource +} + +// --- end resource factory --- + +// --- begin resource implementation --- +// resource is a Resource implementation using +// the original access method to cache the content. +type resource struct { + Identity metav1.Identity + ArtifactType string + Access string + Data blobaccess.BlobAccess +} + +var _ Resource = (*resource)(nil) + +func (r *resource) AddDataFromMethod(ctx ocm.ContextProvider, m ocm.AccessMethod) error { + // provide an own reference to the method + // to store this in the provided resource object. + priv, err := m.Dup() + if err != nil { + return err + } + + // release a possible former cache entry + if r.Data != nil { + r.Data.Close() + } + r.Data = priv.AsBlobAccess() + // release obsolete blob access + r.Access = m.AccessSpec().Describe(ctx.OCMContext()) + return nil +} + +// Close releases the cached access. +func (r *resource) Close() error { + c := r.Data + if c == nil { + return nil + } + r.Data = nil + return c.Close() +} + +// --- end resource implementation --- + +// --- begin caching factory --- +// CachingFactory provides resource inmplementations +// using the original access as cache. +type CachingFactory struct { +} + +func (c CachingFactory) Create(id metav1.Identity, typ string) Resource { + return &resource{ + Identity: id, + ArtifactType: typ, + } +} + +// --- end caching factory --- + +func (r *resource) GetIdentity() metav1.Identity { + return r.Identity +} +func (r *resource) GetType() string { + return r.ArtifactType +} + +func (r *resource) GetAccess() string { + return r.Access +} + +func (r *resource) SetError(s string) { + r.Access = "error: " + s +} + +func (r *resource) GetData() ([]byte, error) { + if r.Data == nil { + return nil, fmt.Errorf("no data set") + } + return r.Data.Get() +} + +func ResourceManagement() error { + // get the default context providing + // all OCM entry point registrations, like + // access method, repository types, etc. + // The context bundles all registrations and + // configuration settings, like credentials, + // which should be used when working with the OCM + // ecosystem. + ctx := ocm.DefaultContext() + + // --- begin decouple --- + // gathering resources, this is completely hidden + // behind an implementation. + resources, err := GatherResources(ctx, CachingFactory{}) + if err != nil { + return err + } + + var list errors.ErrorList + + list.Add(HandleResources(resources)) + + // we are done, so close the resources, again. + for i, r := range resources { + list.Addf(nil, r.Close(), "closing resource %d", i) + } + return list.Result() + // --- end decouple --- +} + +// --- begin handle --- +func HandleResources(resources []Resource) error { + var list errors.ErrorList + fmt.Printf("*** resources:\n") + for i, r := range resources { + fmt.Printf(" %2d: extra identity: %s\n", i+1, r.GetIdentity()) + fmt.Printf(" resource type: %s\n", r.GetType()) + fmt.Printf(" access: %s\n", r.GetAccess()) + } + + return list.Result() +} + +// --- end handle --- + +func GatherResources(ctx ocm.Context, factory ResourceFactory) ([]Resource, error) { + var resources []Resource + + spec := ocireg.NewRepositorySpec("ghcr.io/open-component-model/ocm") + + // And the context can now be used to map the descriptor + // into a repository object, which then provides access + // to the OCM elements stored in this repository. + // --- begin repository --- + repo, err := ctx.RepositoryForSpec(spec) + if err != nil { + return nil, errors.Wrapf(err, "cannot setup repository") + } + + // to release potentially allocated temporary resources, + // many objects must be closed, if they should not be used + // anymore. + // This is typically done by a `defer` statement placed after a + // successful object retrieval. + defer repo.Close() + // --- end repository --- + + // Now, we look up the OCM CLI component. + // All kinds of repositories, regardless of their type + // feature the same interface to work with OCM content. + // --- begin lookup component --- + c, err := repo.LookupComponent("ocm.software/ocmcli") + if err != nil { + return nil, errors.Wrapf(err, "cannot lookup component") + } + defer c.Close() + // --- end lookup component --- + + // Now we look for the versions of the component + // available in this repository. + versions, err := c.ListVersions() + if err != nil { + return nil, errors.Wrapf(err, "cannot query version names") + } + + // OCM version names must follow the SemVer rules. + // Therefore, we can simply order the versions and print them. + err = semverutils.SortVersions(versions) + if err != nil { + return nil, errors.Wrapf(err, "cannot sort versions") + } + fmt.Printf("versions for component ocm.software/ocmcli: %s\n", strings.Join(versions, ", ")) + + // Now, we have a look at the latest version. it is + // the last one in the list. + // --- begin lookup version --- + cv, err := c.LookupVersion(versions[len(versions)-1]) + if err != nil { + return nil, errors.Wrapf(err, "cannot get latest version") + } + defer cv.Close() + // --- end lookup version --- + + cd := cv.GetDescriptor() + fmt.Printf("looking up resources of the latest version:\n") + fmt.Printf(" version: %s\n", cv.GetVersion()) + fmt.Printf(" provider: %s\n", cd.Provider.Name) + + // and list all the included resources. + // Resources have some metadata, like the resource identity and a resource type. + // And they describe how the content of the resource (as blob) can be accessed. + // This is done by an *access specification*, again a serializable descriptor, + // like the repository specification. + // --- begin resources --- + for _, r := range cv.GetResources() { + res := factory.Create( + r.Meta().GetIdentity(cv.GetDescriptor().Resources), + r.Meta().GetType(), + ) + acc, err := r.Access() + if err != nil { + res.SetError(err.Error()) + } else { + m, err := acc.AccessMethod(cv) + if err == nil { + // delegate data handling to target + // we don't know, how this is implemented. + err = res.AddDataFromMethod(ctx, m) + if err != nil { + res.SetError(err.Error()) + } + // release local usage of the access method object + m.Close() + } else { + res.SetError(err.Error()) + } + } + resources = append(resources, res) + } + // --- end resources --- + return resources, nil +} diff --git a/examples/lib/tour/07-resource-management/main.go b/examples/lib/tour/07-resource-management/main.go new file mode 100644 index 0000000000..75a437c009 --- /dev/null +++ b/examples/lib/tour/07-resource-management/main.go @@ -0,0 +1,14 @@ +package main + +import ( + "fmt" + "os" +) + +func main() { + err := ResourceManagement() + if err != nil { + fmt.Fprintf(os.Stderr, "Error: %s\n", err) + os.Exit(1) + } +} diff --git a/examples/lib/tour/README.md b/examples/lib/tour/README.md index 6931b81dd0..9ea044220c 100644 --- a/examples/lib/tour/README.md +++ b/examples/lib/tour/README.md @@ -16,3 +16,4 @@ of extension points of the library. - [Working with Configuration](04-working-with-config/README.md#config) - [Transporting Component Versions](05-transporting-component-versions/README.md#transport) - [Signing Component Versions](06-signing-component-versions/README.md#signing) +- [Resource Management](07-resource-management/README.md#resmgmt) diff --git a/examples/lib/tour/docsrc/07-resource-management/README.md b/examples/lib/tour/docsrc/07-resource-management/README.md new file mode 100644 index 0000000000..5e964d5118 --- /dev/null +++ b/examples/lib/tour/docsrc/07-resource-management/README.md @@ -0,0 +1,158 @@ +# Resource Management + +{{resmgmt}} + +This tour illustrates the basic contract to +correctly work with closeable object references used +in the library. + +Many objects provided by the library offer some kind of resource management. In the [first example]({{getting-started}}), this is an +OCM repository, the OCM component, component version and the access method. +Another important kind of objects are the `BlobAccess` implementations. + +Those objects may use external resources, like temporary file system content or caches. To get rid of those resources again, they offer a `Close` method. + +To achieve the possibility to pass those objects around in non-functional call contexts they feature some kind of resource management. It allows to handle +the life cycle of the resource in a completely local manner. To do so, a second method `Dup` is offered, which provides an independent reference to the original resources, which can be closed separately. +The possible externally held resource are released with the close of the last reference. + +This offers a simple contract to handle resources in functions or object methods: + +1. a function creating such an object is responsible for the life cycle of its reference + + - if the object is returned, this responsibility is passed to its caller + + ```go + func f() (Object, error) { + o, err:= Create() + if err != nil { + return nil, err + } + o.DoSomeThing() + DoSomeThingOther(o) + return o, nil + } + ``` + + - otherwise, it must be closed at the end of the function (or if it is not used anymore) + + ```go + func f() error { + o, err:= Create() + if err != nil { + return err + } + defer o.Close() + o.DoSomeThing() + DoSomeThingOther(o) + } + ``` + + The object may be passed to any called function without bothering what this function does with this reference. + +2. a function receiving such an object from a function as result it inherits the responsibility to close it again (see case 1) + +3. a function receiving such an object as an argument can freely use it and a pass it around. + + ```go + func f(o Object) { + o.DoSomeThing() + DoSomeThingOther(o) + } + ``` + + If it decides to store the reference in some state, it must use an own reference for this, obtained by a call to `Dup`. After obtaining an own reference the used storage context is responsible to close it again. It should never close the obtained reference, because the caller is responsible for this. + + ```go + func (r *State) f(o Object) (err error) { + r.obj, err = o.Dup() + return err + } + + func (r *State) Close() error { + if r.obj == nil { + return nil + } + return r.obj.Close() + } + ``` + +## Running the example + +You can call the main program without any argument. + +## Walkthrough + +The example is based on the initial [getting started scenario]({{getting-started}}). +It separates the resource gathering from the handling of the found resources. + +```go +{{include}{../../07-resource-management/example.go}{decouple}} +``` + +The resources are provided by an array of the interface `Resource`: + +```go +{{include}{../../07-resource-management/example.go}{resource interface}} +``` + +It encapsulates the technical resource handling +and offers a `Close` method, also, to release potential local resources. + +The example provides one implementation, using the original access method +to cache the data to avoid additional copies. + +```go +{{include}{../../07-resource-management/example.go}{resource implementation}} +``` + +The `AddDataFromMethod` uses `Dup` to provide an own reference to the +access method, which is stored in the provided resource object. +It implements the `Close` method to release this cached content, again. +The responsibility for this reference is taken by the `resource`object. + +In the `GatherResources` function, a repository access is created. +It is not forwarded, and therefore closed, again, in this function. + +```go +{{include}{../../07-resource-management/example.go}{repository}} +``` + +The same is done for the component version lookup. + +```go +{{include}{../../07-resource-management/example.go}{lookup component}} +``` + +Then the resource `factory` is used to create the `Resource` objects for +the resources found in the component version. + +```go +{{include}{../../07-resource-management/example.go}{resources}} +``` + +Because the function cannot know what happens behind the call to +`AddDataFromMethod`, it just closes everything what is created +in the function, this also includes the access method (`m`). + +Finally, it returns the resource array after all locally created +references are correctly closed. +The provided `Resource` objects have taken the responsibility for +keeping their own references. + +The resource handling function just uses the resources. + +```go +{{include}{../../07-resource-management/example.go}{handle}} +``` + +The responsibility for closing the resources has been passed to +the `ResourceManagement` functions, which calls the gather and +the handling function. Therefore, it calls the `Resource.Close` +function before finishing. + +The final output of this example looks like: + +```yaml +{{execute}{go}{run}{../../07-resource-management}} +``` diff --git a/examples/lib/tour/docsrc/README.md b/examples/lib/tour/docsrc/README.md index 52ad1a7a7e..91de1b496c 100644 --- a/examples/lib/tour/docsrc/README.md +++ b/examples/lib/tour/docsrc/README.md @@ -13,3 +13,4 @@ of extension points of the library. - [Working with Configuration]({{config}}) - [Transporting Component Versions]({{transport}}) - [Signing Component Versions]({{signing}}) +- [Resource Management]({{resmgmt}}) From a509b0f210bebc7144b075b2f39fcc70f1acf47a Mon Sep 17 00:00:00 2001 From: Uwe Krueger Date: Mon, 11 Nov 2024 13:44:20 +0100 Subject: [PATCH 42/58] skip digest for component constructors (#1070) #### What this PR does / why we need it This PR adds the option `--skip-digest-generation` to the `ocm add components` command. It generally disables the digest generation for all added resources. Additionally, the resource description may set `skipDigestGeneration` to `true` to disable the digest generation for this particular resource. #### Which issue(s) this PR fixes Fixes https://github.com/open-component-model/ocm-project/issues/322 --- .../ocmcmds/common/addhdlrs/comp/elements.go | 11 +++--- .../ocmcmds/common/addhdlrs/options.go | 3 +- .../ocmcmds/common/addhdlrs/rscs/elements.go | 8 +++++ .../commands/ocmcmds/components/add/cmd.go | 16 +++------ .../ocmcmds/components/add/cmd_test.go | 30 +++++++++++++++- .../testdata/component-constructor-skip.yaml | 35 +++++++++++++++++++ docs/reference/ocm_add_componentversions.md | 9 +---- 7 files changed, 85 insertions(+), 27 deletions(-) create mode 100644 cmds/ocm/commands/ocmcmds/components/add/testdata/component-constructor-skip.yaml diff --git a/cmds/ocm/commands/ocmcmds/common/addhdlrs/comp/elements.go b/cmds/ocm/commands/ocmcmds/common/addhdlrs/comp/elements.go index c0634d8630..43ba0711c7 100644 --- a/cmds/ocm/commands/ocmcmds/common/addhdlrs/comp/elements.go +++ b/cmds/ocm/commands/ocmcmds/common/addhdlrs/comp/elements.go @@ -21,6 +21,7 @@ import ( "ocm.software/ocm/cmds/ocm/commands/ocmcmds/common/addhdlrs/rscs" "ocm.software/ocm/cmds/ocm/commands/ocmcmds/common/addhdlrs/srcs" "ocm.software/ocm/cmds/ocm/commands/ocmcmds/common/inputs" + "ocm.software/ocm/cmds/ocm/commands/ocmcmds/common/options/schemaoption" "ocm.software/ocm/cmds/ocm/common/options" "ocm.software/ocm/cmds/ocm/common/utils" ) @@ -34,7 +35,7 @@ type ResourceSpecHandler struct { srchandler *srcs.ResourceSpecHandler refhandler *refs.ResourceSpecHandler version string - schema string + schema *schemaoption.Option } var ( @@ -42,13 +43,12 @@ var ( _ options.Options = (*ResourceSpecHandler)(nil) ) -func New(v string, schema string, opts ...ocm.ModificationOption) *ResourceSpecHandler { +func New(opts ...ocm.ModificationOption) *ResourceSpecHandler { return &ResourceSpecHandler{ rschandler: rscs.New(opts...), srchandler: srcs.New(), refhandler: refs.New(), - version: v, - schema: schema, + schema: schemaoption.New(compdesc.DefaultSchemeVersion), } } @@ -56,6 +56,7 @@ func (h *ResourceSpecHandler) AddFlags(fs *pflag.FlagSet) { h.rschandler.AddFlags(fs) h.srchandler.AddFlags(fs) h.refhandler.AddFlags(fs) + fs.StringVarP(&h.version, "version", "v", "", "default version for components") } func (h *ResourceSpecHandler) WithCLIOptions(opts ...options.Options) *ResourceSpecHandler { @@ -118,7 +119,7 @@ func (h *ResourceSpecHandler) Add(ctx clictx.Context, ictx inputs.Context, elem cd.References = nil } - schema := h.schema + schema := h.schema.Schema if r.Meta.ConfiguredVersion != "" { schema = r.Meta.ConfiguredVersion } diff --git a/cmds/ocm/commands/ocmcmds/common/addhdlrs/options.go b/cmds/ocm/commands/ocmcmds/common/addhdlrs/options.go index e9614db216..e4e305a268 100644 --- a/cmds/ocm/commands/ocmcmds/common/addhdlrs/options.go +++ b/cmds/ocm/commands/ocmcmds/common/addhdlrs/options.go @@ -1,7 +1,6 @@ package addhdlrs import ( - "github.com/mandelsoft/goutils/generics" "github.com/spf13/pflag" "ocm.software/ocm/api/ocm" @@ -16,7 +15,7 @@ var _ ocm.ModificationOption = (*Options)(nil) func (o *Options) AddFlags(fs *pflag.FlagSet) { f := fs.Lookup("replace") if f != nil { - if bp := generics.Cast[*bool](f.Value); bp != nil { + if f.Value.Type() == "bool" { return } } diff --git a/cmds/ocm/commands/ocmcmds/common/addhdlrs/rscs/elements.go b/cmds/ocm/commands/ocmcmds/common/addhdlrs/rscs/elements.go index 1cd98d2392..36a1e97858 100644 --- a/cmds/ocm/commands/ocmcmds/common/addhdlrs/rscs/elements.go +++ b/cmds/ocm/commands/ocmcmds/common/addhdlrs/rscs/elements.go @@ -102,6 +102,9 @@ func (h ResourceSpecHandler) Set(v ocm.ComponentVersionAccess, r addhdlrs.Elemen SourceRefs: compdescv2.ConvertSourcerefsTo(spec.SourceRefs), } opts := h.getModOpts() + if spec.SkipDigestGeneration { + opts = append(opts, ocm.SkipDigest()) //nolint:staticcheck // skip digest still used for tests) + } if ocm.IsIntermediate(v.Repository().GetSpecification()) { opts = append(opts, ocm.ModifyResource()) } @@ -126,6 +129,11 @@ type ResourceSpec struct { SourceRefs []compdescv2.SourceRef `json:"srcRefs"` addhdlrs.ResourceInput `json:",inline"` + + // additional process related options + + // SkipDigestGeneration omits the digest generation. + SkipDigestGeneration bool `json:"skipDigestGeneration,omitempty"` } var _ addhdlrs.ElementSpec = (*ResourceSpec)(nil) diff --git a/cmds/ocm/commands/ocmcmds/components/add/cmd.go b/cmds/ocm/commands/ocmcmds/components/add/cmd.go index cc2309a940..c52cc0130e 100644 --- a/cmds/ocm/commands/ocmcmds/components/add/cmd.go +++ b/cmds/ocm/commands/ocmcmds/components/add/cmd.go @@ -11,7 +11,6 @@ import ( clictx "ocm.software/ocm/api/cli" "ocm.software/ocm/api/ocm" - "ocm.software/ocm/api/ocm/compdesc" "ocm.software/ocm/api/ocm/extensions/repositories/ctf" "ocm.software/ocm/api/ocm/tools/transfer/transferhandler/standard" "ocm.software/ocm/api/utils/accessio" @@ -25,7 +24,6 @@ import ( "ocm.software/ocm/cmds/ocm/commands/ocmcmds/common/options/fileoption" "ocm.software/ocm/cmds/ocm/commands/ocmcmds/common/options/lookupoption" "ocm.software/ocm/cmds/ocm/commands/ocmcmds/common/options/rscbyvalueoption" - "ocm.software/ocm/cmds/ocm/commands/ocmcmds/common/options/schemaoption" "ocm.software/ocm/cmds/ocm/commands/ocmcmds/common/options/templateroption" "ocm.software/ocm/cmds/ocm/commands/ocmcmds/common/options/uploaderoption" "ocm.software/ocm/cmds/ocm/commands/ocmcmds/names" @@ -48,23 +46,21 @@ type Command struct { FormatHandler ctf.FormatHandler Format string - Version string + Handler *comp.ResourceSpecHandler Envs []string Archive string - Options addhdlrs.Options - Elements []addhdlrs.ElementSource } func NewCommand(ctx clictx.Context, names ...string) *cobra.Command { return utils.SetupCommand(&Command{ + Handler: comp.New().WithCLIOptions(&addhdlrs.Options{}), BaseCommand: utils.NewBaseCommand(ctx, formatoption.New(ctf.GetFormats()...), fileoption.New("transport-archive"), - schemaoption.New(compdesc.DefaultSchemeVersion), templateroption.New(""), dryrunoption.New("evaluate and print component specifications", true), lookupoption.New(), @@ -155,12 +151,11 @@ Various elements support to add arbitrary information by using labels func (o *Command) AddFlags(fs *pflag.FlagSet) { o.BaseCommand.AddFlags(fs) - o.Options.AddFlags(fs) + o.Handler.AddFlags(fs) fs.BoolVarP(&o.Force, "force", "f", false, "remove existing content") fs.BoolVarP(&o.Create, "create", "c", false, "(re)create archive") fs.BoolVarP(&o.Closure, "complete", "C", false, "include all referenced component version") fs.StringArrayVarP(&o.Envs, "settings", "s", nil, "settings file with variable settings (yaml)") - fs.StringVarP(&o.Version, "version", "v", "", "default version for components") } func (o *Command) Complete(args []string) error { @@ -209,8 +204,7 @@ func (o *Command) Run() error { printer := common2.NewPrinter(o.Context.StdOut()) fs := o.Context.FileSystem() - h := comp.New(o.Version, schemaoption.From(o).Schema).WithCLIOptions(&o.Options) - elems, ictx, err := addhdlrs.ProcessDescriptions(o.Context, printer, templateroption.From(o).Options, h, o.Elements) + elems, ictx, err := addhdlrs.ProcessDescriptions(o.Context, printer, templateroption.From(o).Options, o.Handler, o.Elements) if err != nil { return err } @@ -250,7 +244,7 @@ func (o *Command) Run() error { } if err == nil { - err = comp.ProcessComponents(o.Context, ictx, repo, general.Conditional(o.Closure, lookupoption.From(o).Resolver, nil), thdlr, h, elems) + err = comp.ProcessComponents(o.Context, ictx, repo, general.Conditional(o.Closure, lookupoption.From(o).Resolver, nil), thdlr, o.Handler, elems) cerr := repo.Close() if err == nil { err = cerr diff --git a/cmds/ocm/commands/ocmcmds/components/add/cmd_test.go b/cmds/ocm/commands/ocmcmds/components/add/cmd_test.go index a225d098ba..df8269cda5 100644 --- a/cmds/ocm/commands/ocmcmds/components/add/cmd_test.go +++ b/cmds/ocm/commands/ocmcmds/components/add/cmd_test.go @@ -1,6 +1,7 @@ package add_test import ( + "github.com/mandelsoft/goutils/general" . "github.com/mandelsoft/goutils/testutils" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" @@ -35,7 +36,7 @@ const ( OUT = "/tmp/res" ) -func CheckComponent(env *TestEnv, handler func(ocm.Repository)) { +func CheckComponent(env *TestEnv, handler func(ocm.Repository), tests ...func(cv ocm.ComponentVersionAccess)) { repo := Must(ctf.Open(env.OCMContext(), accessobj.ACC_READONLY, ARCH, 0, env)) defer Close(repo) cv := Must(repo.LookupComponentVersion("ocm.software/demo/test", "1.0.0")) @@ -73,6 +74,10 @@ func CheckComponent(env *TestEnv, handler func(ocm.Repository)) { if handler != nil { handler(repo) } + + for _, t := range tests { + t(cv) + } } var _ = Describe("Test Environment", func() { @@ -104,6 +109,17 @@ var _ = Describe("Test Environment", func() { CheckComponent(env, nil) }) + It("creates ctf and adds components without digests", func() { + Expect(env.Execute("add", "c", "--skip-digest-generation", "-fc", "--file", ARCH, "--version", "1.0.0", "testdata/component-constructor.yaml")).To(Succeed()) + Expect(env.DirExists(ARCH)).To(BeTrue()) + CheckComponent(env, nil, noDigest("data"), noDigest("text")) + }) + It("creates ctf and adds components without digest for one resource", func() { + Expect(env.Execute("add", "c", "-fc", "--file", ARCH, "--version", "1.0.0", "testdata/component-constructor-skip.yaml")).To(Succeed()) + Expect(env.DirExists(ARCH)).To(BeTrue()) + CheckComponent(env, nil, noDigest("data", false), noDigest("text")) + }) + Context("failures", func() { It("rejects adding duplicate components", func() { ExpectError(env.Execute("add", "c", "-fc", "--file", ARCH, "--version", "1.0.0", "testdata/components-dup.yaml")).To( @@ -176,3 +192,15 @@ var _ = Describe("Test Environment", func() { }) }) }) + +func noDigest(name string, skips ...bool) func(cv ocm.ComponentVersionAccess) { + skip := general.OptionalDefaultedBool(true, skips...) + return func(cv ocm.ComponentVersionAccess) { + r := MustWithOffset(1, Calling(cv.GetResource(metav1.Identity{"name": name}))) + if skip { + ExpectWithOffset(1, r.Meta().Digest).To(BeNil()) + } else { + ExpectWithOffset(1, r.Meta().Digest).NotTo(BeNil()) + } + } +} diff --git a/cmds/ocm/commands/ocmcmds/components/add/testdata/component-constructor-skip.yaml b/cmds/ocm/commands/ocmcmds/components/add/testdata/component-constructor-skip.yaml new file mode 100644 index 0000000000..bd8c88c4dd --- /dev/null +++ b/cmds/ocm/commands/ocmcmds/components/add/testdata/component-constructor-skip.yaml @@ -0,0 +1,35 @@ +name: ocm.software/demo/test +version: 1.0.0 +provider: + name: ocm.software + labels: + - name: city + value: Karlsruhe +labels: + - name: purpose + value: test + +resources: + - name: text + type: PlainText + skipDigestGeneration: true + labels: + - name: city + value: Karlsruhe + merge: + algorithm: default + config: + overwrite: inbound + input: + type: file + path: testdata + - name: data + type: PlainText + input: + type: binary + data: IXN0cmluZ2RhdGE= + +references: + - name: ref + version: v1 + componentName: github.com/mandelsoft/test2 diff --git a/docs/reference/ocm_add_componentversions.md b/docs/reference/ocm_add_componentversions.md index b95988d4ac..89cd2cda77 100644 --- a/docs/reference/ocm_add_componentversions.md +++ b/docs/reference/ocm_add_componentversions.md @@ -27,8 +27,8 @@ componentversions, componentversion, cv, components, component, comps, comp, c --lookup stringArray repository name or spec for closure lookup fallback -O, --output string output file for dry-run -R, --replace replace existing elements - -S, --scheme string schema version (default "v2") -s, --settings stringArray settings file with variable settings (yaml) + --skip-digest-generation skip digest creation --templater string templater to use (go, none, spiff, subst) (default "subst") -t, --type string archive format (directory, tar, tgz) (default "directory") --uploader = repository uploader ([:[:[:]]]=) (default []) @@ -85,13 +85,6 @@ archive does not exist yet. The following formats are supported: The default format is directory. -If the option --scheme is given, the specified component descriptor format is used/generated. - -The following schema versions are supported for explicit conversions: - - ocm.software/v3alpha1 - - v2 (default) - - All yaml/json defined resources can be templated. Variables are specified as regular arguments following the syntax <name>=<value>. Additionally settings can be specified by a yaml file using the --settings From a0ace6810008338fc33a0e22b9dfd888ea51b72b Mon Sep 17 00:00:00 2001 From: Uwe Krueger Date: Mon, 11 Nov 2024 14:55:22 +0100 Subject: [PATCH 43/58] fix: add back scheme option after it was accidentally removed (#1073) #### What this PR does / why we need it complete #1070 Move handler-local options correctly to the comp handler and adapt the using code to reflect this change. #### Which issue(s) this PR fixes --- cmds/ocm/commands/ocmcmds/common/addhdlrs/base.go | 7 +++++-- cmds/ocm/commands/ocmcmds/common/addhdlrs/comp/elements.go | 7 ++++++- cmds/ocm/commands/ocmcmds/common/addhdlrs/rscs/elements.go | 4 ++-- cmds/ocm/commands/ocmcmds/components/add/cmd.go | 5 +++-- docs/reference/ocm_add_componentversions.md | 1 + 5 files changed, 17 insertions(+), 7 deletions(-) diff --git a/cmds/ocm/commands/ocmcmds/common/addhdlrs/base.go b/cmds/ocm/commands/ocmcmds/common/addhdlrs/base.go index f772472acc..41512f23c9 100644 --- a/cmds/ocm/commands/ocmcmds/common/addhdlrs/base.go +++ b/cmds/ocm/commands/ocmcmds/common/addhdlrs/base.go @@ -11,7 +11,10 @@ type ResourceSpecHandlerBase struct { options options.OptionSet } -var _ options.Options = (*ResourceSpecHandlerBase)(nil) +var ( + _ options.Options = (*ResourceSpecHandlerBase)(nil) + _ options.OptionSetProvider = (*ResourceSpecHandlerBase)(nil) +) func NewBase(opts ...options.Options) ResourceSpecHandlerBase { return ResourceSpecHandlerBase{options: opts} @@ -26,7 +29,7 @@ func (h *ResourceSpecHandlerBase) WithCLIOptions(opts ...options.Options) Resour return *h } -func (h *ResourceSpecHandlerBase) GetOptions() options.OptionSet { +func (h *ResourceSpecHandlerBase) AsOptionSet() options.OptionSet { return h.options } diff --git a/cmds/ocm/commands/ocmcmds/common/addhdlrs/comp/elements.go b/cmds/ocm/commands/ocmcmds/common/addhdlrs/comp/elements.go index 43ba0711c7..c5fdf9a3b3 100644 --- a/cmds/ocm/commands/ocmcmds/common/addhdlrs/comp/elements.go +++ b/cmds/ocm/commands/ocmcmds/common/addhdlrs/comp/elements.go @@ -52,11 +52,16 @@ func New(opts ...ocm.ModificationOption) *ResourceSpecHandler { } } +func (h *ResourceSpecHandler) AsOptionSet() options.OptionSet { + return options.OptionSet{h.rschandler.AsOptionSet(), h.srchandler.AsOptionSet(), h.refhandler.AsOptionSet(), h.schema} +} + func (h *ResourceSpecHandler) AddFlags(fs *pflag.FlagSet) { h.rschandler.AddFlags(fs) h.srchandler.AddFlags(fs) h.refhandler.AddFlags(fs) fs.StringVarP(&h.version, "version", "v", "", "default version for components") + h.schema.AddFlags(fs) } func (h *ResourceSpecHandler) WithCLIOptions(opts ...options.Options) *ResourceSpecHandler { @@ -112,7 +117,7 @@ func (h *ResourceSpecHandler) Add(ctx clictx.Context, ictx inputs.Context, elem cd := cv.GetDescriptor() - opts := h.srchandler.GetOptions()[0].(*addhdlrs.Options) + opts := h.srchandler.AsOptionSet()[0].(*addhdlrs.Options) if !opts.Replace { cd.Resources = nil cd.Sources = nil diff --git a/cmds/ocm/commands/ocmcmds/common/addhdlrs/rscs/elements.go b/cmds/ocm/commands/ocmcmds/common/addhdlrs/rscs/elements.go index 36a1e97858..ef57f97e49 100644 --- a/cmds/ocm/commands/ocmcmds/common/addhdlrs/rscs/elements.go +++ b/cmds/ocm/commands/ocmcmds/common/addhdlrs/rscs/elements.go @@ -48,7 +48,7 @@ func (h *ResourceSpecHandler) WithCLIOptions(opts ...options.Options) *ResourceS } func (h *ResourceSpecHandler) getModOpts() []ocm.ModificationOption { - opts := options.FindOptions[ocm.ModificationOption](h.GetOptions()) + opts := options.FindOptions[ocm.ModificationOption](h.AsOptionSet()) if h.opts != nil { opts = append(opts, h.opts) } @@ -103,7 +103,7 @@ func (h ResourceSpecHandler) Set(v ocm.ComponentVersionAccess, r addhdlrs.Elemen } opts := h.getModOpts() if spec.SkipDigestGeneration { - opts = append(opts, ocm.SkipDigest()) //nolint:staticcheck // skip digest still used for tests) + opts = append(opts, ocm.SkipDigest()) //nolint:staticcheck // skip digest still used for tests } if ocm.IsIntermediate(v.Repository().GetSpecification()) { opts = append(opts, ocm.ModifyResource()) diff --git a/cmds/ocm/commands/ocmcmds/components/add/cmd.go b/cmds/ocm/commands/ocmcmds/components/add/cmd.go index c52cc0130e..5032ea8cec 100644 --- a/cmds/ocm/commands/ocmcmds/components/add/cmd.go +++ b/cmds/ocm/commands/ocmcmds/components/add/cmd.go @@ -56,9 +56,11 @@ type Command struct { } func NewCommand(ctx clictx.Context, names ...string) *cobra.Command { + hdlr := comp.New().WithCLIOptions(&addhdlrs.Options{}) return utils.SetupCommand(&Command{ - Handler: comp.New().WithCLIOptions(&addhdlrs.Options{}), + Handler: hdlr, BaseCommand: utils.NewBaseCommand(ctx, + hdlr, formatoption.New(ctf.GetFormats()...), fileoption.New("transport-archive"), templateroption.New(""), @@ -151,7 +153,6 @@ Various elements support to add arbitrary information by using labels func (o *Command) AddFlags(fs *pflag.FlagSet) { o.BaseCommand.AddFlags(fs) - o.Handler.AddFlags(fs) fs.BoolVarP(&o.Force, "force", "f", false, "remove existing content") fs.BoolVarP(&o.Create, "create", "c", false, "(re)create archive") fs.BoolVarP(&o.Closure, "complete", "C", false, "include all referenced component version") diff --git a/docs/reference/ocm_add_componentversions.md b/docs/reference/ocm_add_componentversions.md index 89cd2cda77..73b8857604 100644 --- a/docs/reference/ocm_add_componentversions.md +++ b/docs/reference/ocm_add_componentversions.md @@ -27,6 +27,7 @@ componentversions, componentversion, cv, components, component, comps, comp, c --lookup stringArray repository name or spec for closure lookup fallback -O, --output string output file for dry-run -R, --replace replace existing elements + -S, --scheme string schema version (default "v2") -s, --settings stringArray settings file with variable settings (yaml) --skip-digest-generation skip digest creation --templater string templater to use (go, none, spiff, subst) (default "subst") From 378bcc0743e9a188f3a66917dd05f0f9ad53eb4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakob=20M=C3=B6ller?= Date: Mon, 11 Nov 2024 15:17:07 +0100 Subject: [PATCH 44/58] chore: release branches as `releases/vX.Y` instead of `releases/vX.Y.Z` (#1071) #### What this PR does / why we need it This reworks the release branch action to correctly branch off in patterns that do not include Z / Patch versions: ``` releases/v0.17.0 # before releases/v0.17 # after ``` To achieve this it allows to print only the major/minor combination for the release_generate.go generator. Additionally, it adds an automatic bump to main after the Branch Cutoff was completed into main. #### Which issue(s) this PR fixes Currently our release branches include the 0 Z / Patch version as part of their name, but this is misleading because we also use these branches for patches onto the Y / Minor version. This fixes up the release branch creation to 1. Create the Branch according to this pattern 2. Fixup the Main Branch with a Version Bump PR after the bump so that the next minor development can start. part of https://github.com/open-component-model/ocm/issues/995 to ensure proper candidate creation --- .github/workflows/release-branch.yaml | 185 +++++++++++++++-------- api/version/generate/release_generate.go | 2 + 2 files changed, 125 insertions(+), 62 deletions(-) diff --git a/.github/workflows/release-branch.yaml b/.github/workflows/release-branch.yaml index 42a666e321..e19a45abe3 100644 --- a/.github/workflows/release-branch.yaml +++ b/.github/workflows/release-branch.yaml @@ -1,75 +1,136 @@ - -name: Release Branch Creation +# This creates a new release branch from the main branch. +# It serves as the cutoff point for the next minor release. +# From this point onward only bug fixes and critical changes will be accepted onto the release +# branch as backports from main. At the same time, the main branch will be open for new features +# and changes for the next minor release. +name: Release Branch Cutoff on: workflow_dispatch: - inputs: - tag: - type: string - description: "Tag name (if other than execution base)" - required: false - default: "" + +permissions: + # Necessary to write the branch + contents: write jobs: - check-and-create: + cutoff-preconditions: + runs-on: ubuntu-latest + permissions: + contents: read + id-token: write + repository-projects: read + outputs: + minor: ${{ steps.get-minor.outputs.minor }} + branch: ${{ steps.verify-branch.outputs.branch }} + steps: + - name: Generate token + id: generate_token + uses: tibdex/github-app-token@v2 + with: + app_id: ${{ secrets.OCMBOT_APP_ID }} + private_key: ${{ secrets.OCMBOT_PRIV_KEY }} + - name: Checkout + uses: actions/checkout@v4 + with: + ref: main + fetch-depth: 0 + token: ${{ steps.generate_token.outputs.token }} + - name: Setup Go + uses: actions/setup-go@v5 + with: + go-version-file: '${{ github.workspace }}/go.mod' + cache: false + - name: Get Minor + id: get-minor + run: | + set -e + minor="$(go run ./api/version/generate print-major-minor)" + echo "minor=$minor" >> $GITHUB_OUTPUT + echo "Current Major-Minor Version: $minor" + - name: Verify Branch does not exist + id: verify-branch + run: | + set -e + minor="v${{ steps.get-minor.outputs.minor }}" + branch="releases/$minor" + if git ls-remote --exit-code origin refs/heads/$branch ; then + >&2 echo "branch $branch already exists, aborting" + exit 1 + fi + echo "branch $branch does not exist" + echo "branch=$branch" >> $GITHUB_OUTPUT + + create-branch: runs-on: ubuntu-latest + needs: cutoff-preconditions permissions: contents: write id-token: write repository-projects: read steps: - - name: Generate token - id: generate_token - uses: tibdex/github-app-token@v2 - with: - app_id: ${{ secrets.OCMBOT_APP_ID }} - private_key: ${{ secrets.OCMBOT_PRIV_KEY }} - - name: Checkout - uses: actions/checkout@v4 - with: - fetch-depth: 0 - token: ${{ steps.generate_token.outputs.token }} + - name: Generate token + id: generate_token + uses: tibdex/github-app-token@v2 + with: + app_id: ${{ secrets.OCMBOT_APP_ID }} + private_key: ${{ secrets.OCMBOT_PRIV_KEY }} + - name: Checkout + uses: actions/checkout@v4 + with: + ref: main + fetch-depth: 0 + token: ${{ steps.generate_token.outputs.token }} - - name: Create Release Branch - run: | - set -e - git config --global user.name github-actions - git config --global user.email '${GITHUB_ACTOR}@users.noreply.github.com' + - name: Create Release Branch + run: | + set -e + branch=${{ needs.cutoff-preconditions.outputs.branch }} + git checkout -b "$branch" + git push origin $branch - tag="${{github.event.inputs.tag}}" - if [ -n "$tag" ]; then - if ! git ls-remote --tags --exit-code origin "$tag" >/dev/null; then - >&2 echo "tag $tag not found" - exit 1 - fi - git fetch origin "$tag" - git checkout "$tag" - else - if [ "${{ github.ref_type }}" != "tag" ]; then - >&2 echo "please run workflow on desired tag to create a release branch for or specify a tag as input" - exit 1 - fi - - tag="${{ github.ref_name }}" - fi - - if ! [[ "$tag" =~ ^v?[0-9]+\.[0-9]+\.[0-9]+$ ]]; then - >&2 echo "no valid non-pre-release tag $tag" - exit 1 - fi - if [ "$tag" == "${tag%.0}" ]; then - >&2 echo "please use a non-patch tag" - exit 1 - fi - if git ls-remote --exit-code origin refs/heads/releases/$tag ; then - >&2 echo "branch releases/$tag already exists" - exit 1 - fi - echo "creating release branch for $tag" - n="releases/$tag" - git checkout -b "$n" - v="$(go run ./api/version/generate bump-patch)" - echo "$v" > VERSION - git add VERSION - git commit -m "Prepare Development of v$v" - git push origin "$n" + bump-main-pr: + runs-on: ubuntu-latest + needs: [create-branch, cutoff-preconditions] # wait for the release branch to be created, then create a version bump + steps: + - name: Generate token + id: generate_token + uses: tibdex/github-app-token@v2 + with: + app_id: ${{ secrets.OCMBOT_APP_ID }} + private_key: ${{ secrets.OCMBOT_PRIV_KEY }} + - name: Checkout + uses: actions/checkout@v4 + with: + ref: main + token: ${{ steps.generate_token.outputs.token }} + - name: Version Bump + id: version-bump + run: | + set -e + + echo "determining next version" + version=$(go run ./api/version/generate bump-version) + + echo "bumping main branch to $version" + echo $version > VERSION + + echo "version=$version" >> $GITHUB_OUTPUT + echo "version after bump: $version" + + - name: Create Pull Request + uses: peter-evans/create-pull-request@v7 + with: + token: ${{ steps.generate_token.outputs.token }} + title: "chore: bump VERSION to ${{ steps.version-bump.outputs.version }}" + commit-message: "[github-actions] Bump to ${{ steps.version-bump.outputs.version }} after branch cutoff" + branch: "chore/bump-main/v${{ steps.version-bump.outputs.version }}" + delete-branch: true + sign-commits: true + add-paths: | + VERSION + body: | + Update OCM Version to ${{ steps.version-bump.outputs.version }} + + After the release branch cutoff into ${{ needs.cutoff-preconditions.outputs.branch }}, + this bumps the OCM version so that future development continues on the next minor release. + diff --git a/api/version/generate/release_generate.go b/api/version/generate/release_generate.go index d93f2c6a6c..d28b4e2122 100644 --- a/api/version/generate/release_generate.go +++ b/api/version/generate/release_generate.go @@ -84,6 +84,8 @@ func main() { switch cmd { case "print-semver": fmt.Print(nonpre) + case "print-major-minor": + fmt.Printf("%d.%d", nonpre.Major(), nonpre.Minor()) case "print-version": fmt.Print(v) case "print-rc-version": From ef17caf31be954488ea7f32610b10267218db620 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakob=20M=C3=B6ller?= Date: Mon, 11 Nov 2024 18:52:36 +0100 Subject: [PATCH 45/58] fix: fixup blackduck scan job (#1075) #### What this PR does / why we need it Accidentally the go env didnt get set for blackduck which caused the cron job to fail before. This now sets it correctly #### Which issue(s) this PR fixes fix #1074 --- .github/workflows/blackduck_scan_scheduled.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/blackduck_scan_scheduled.yaml b/.github/workflows/blackduck_scan_scheduled.yaml index 4b2146e628..9491840c0d 100644 --- a/.github/workflows/blackduck_scan_scheduled.yaml +++ b/.github/workflows/blackduck_scan_scheduled.yaml @@ -25,6 +25,10 @@ jobs: go-version-file: '${{ github.workspace }}/go.mod' cache: false + - name: Get go environment for use with cache + run: | + echo "go_cache=$(go env GOCACHE)" >> $GITHUB_ENV + echo "go_modcache=$(go env GOMODCACHE)" >> $GITHUB_ENV # This step will only reuse the go mod and build cache from main made during the Build, # see push_ocm.yaml => "ocm-cli-latest" Job # This means it never caches by itself and PRs cannot cause cache pollution / thrashing From 1b607462f2b11ba6f1e554e1a688d5379752dbf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakob=20M=C3=B6ller?= Date: Tue, 12 Nov 2024 10:57:00 +0100 Subject: [PATCH 46/58] chore: cleanup release action (#1076) #### What this PR does / why we need it This fixes several inconsistencies with the release action and cleans it up before we are migrating some of the more substantial work within it: 1. main no longer gets release notes (as only release branches need to hold release notes) 2. The release version fetching and resolution is separated into a job just for this purpose, and can be reused across steps that need access to it 3. The draft release notes are now fetched via `gh` instead of the old `cardinalby/git-get-release-action@v1` because it is much faster and transparent what happens and the action wasn't maintained properly. 4. The `prerelease` flag was renamed to `release_candidate_name` to make it more clear for what it is actually used in the code. The existing docs on the action one can see when triggering them are unchanged 5. The `create_branch` option is killed because we dont expect the release to trigger the release branch creation, we expect that to come before. A separate PR can trigger the first release candidate creation from the Branch cutoff however (this will come separately) #### Which issue(s) this PR fixes Part of the release process and transparency rework in https://github.com/open-component-model/ocm/issues/995 --- .github/workflows/release-drafter.yaml | 27 ++--- .github/workflows/release-version.yaml | 71 +++++++++++ .github/workflows/release.yaml | 157 ++++++++----------------- 3 files changed, 132 insertions(+), 123 deletions(-) create mode 100644 .github/workflows/release-version.yaml diff --git a/.github/workflows/release-drafter.yaml b/.github/workflows/release-drafter.yaml index 0b531836e7..1901afcea0 100644 --- a/.github/workflows/release-drafter.yaml +++ b/.github/workflows/release-drafter.yaml @@ -3,7 +3,6 @@ name: Release Drafter on: push: branches: - - main - releases/* permissions: @@ -11,26 +10,26 @@ permissions: # The release-drafter action adds PR titles to the release notes once these are merged to main. # A draft release is kept up-to-date listing the changes for the next minor release version. jobs: + release-version: + name: Release Version + uses: ./.github/workflows/release-version.yaml + with: + # the draft release notes do not need to be done by release candidate + # instead we can continously maintain them throughout the candidates + release_candidate: false + permissions: + contents: read + repository-projects: read update_release_draft: + needs: release-version permissions: contents: write runs-on: ubuntu-latest + env: + RELEASE_VERSION: ${{ needs.release-version.outputs.version }} steps: - name: Checkout uses: actions/checkout@v4 - - - name: Setup Go - uses: actions/setup-go@v5 - with: - go-version-file: '${{ github.workspace }}/go.mod' - cache: false - - - name: Set Version - run: | - RELEASE_VERSION=v$(go run $GITHUB_WORKSPACE/api/version/generate print-version) - echo "release version is $RELEASE_VERSION" - echo "RELEASE_VERSION=$RELEASE_VERSION" >> $GITHUB_ENV - - name: Drafter uses: release-drafter/release-drafter@v6 env: diff --git a/.github/workflows/release-version.yaml b/.github/workflows/release-version.yaml new file mode 100644 index 0000000000..4bf084bece --- /dev/null +++ b/.github/workflows/release-version.yaml @@ -0,0 +1,71 @@ +# This workflow can be used to resolve the combination of the inputs candidate and candidate name +# to a release version. The release version is then used in the subsequent steps of the release workflow. +# The release version base is fetched from the VERSION file in the repository root. +name: Derive Release Version from VERSION file + +on: + workflow_call: + inputs: + release_candidate: + type: boolean + description: "Release Candidate" + required: false + default: true + release_candidate_name: + type: string + description: "Release Candidate Name, adjust after every succinct release candidate (e.g. to rc.2, rc.3...)" + required: false + default: "rc.1" + outputs: + version: + description: "The release version to use, e.g. v0.18.0" + value: ${{ jobs.get-release-version.outputs.release-version }} + version_no_prefix: + description: "The release version to use without the 'v' prefix, e.g. v0.18.0 => 0.18.0" + value: ${{ jobs.get-release-version.outputs.release-version-no-prefix }} + version_no_suffix: + description: "The base version to use, without any suffix, e.g. v0.18.0-rc.1 => v0.18.0" + value: ${{ jobs.get-release-version.outputs.base-version }} + +jobs: + get-release-version: + name: Get Release Version + runs-on: ubuntu-latest + permissions: + contents: read + outputs: + base-version: ${{ steps.set-base-version.outputs.BASE_VERSION }} + release-version: ${{ steps.export-version.outputs.RELEASE_VERSION }} + release-version-no-prefix: ${{ steps.export-version.outputs.RELEASE_VERSION_NO_PREFIX }} + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Setup Go + uses: actions/setup-go@v5 + with: + go-version-file: '${{ github.workspace }}/go.mod' + cache: false + + - name: Generate Base Version + id: set-base-version + run: | + BASE_VERSION=v$(go run $GITHUB_WORKSPACE/api/version/generate print-version) + echo "BASE_VERSION=$BASE_VERSION" >> $GITHUB_ENV + echo "BASE_VERSION=$BASE_VERSION" >> $GITHUB_OUTPUT + + - name: Set Version for Release Candidate + if: inputs.release_candidate == true + run: | + RELEASE_VERSION=v$(go run $GITHUB_WORKSPACE/api/version/generate --no-dev print-rc-version ${{ inputs.release_candidate_name }}) + echo "RELEASE_VERSION=$RELEASE_VERSION" >> $GITHUB_ENV + - name: Set Version + if: inputs.release_candidate == false + run: | + RELEASE_VERSION=${{env.BASE_VERSION}} + echo "RELEASE_VERSION=$RELEASE_VERSION" >> $GITHUB_ENV + + - name: Export Version + id: export-version + run: | + echo "RELEASE_VERSION=$RELEASE_VERSION" >> $GITHUB_OUTPUT + echo "RELEASE_VERSION_NO_PREFIX=${RELEASE_VERSION#v}" >> $GITHUB_OUTPUT \ No newline at end of file diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 95e0971a07..06d7ec63fd 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -8,47 +8,40 @@ on: description: "Release Candidate" required: true default: true - create_branch: - type: boolean - description: "Create Release Branch (on failure or if already existing, set to false to ensure a successful run)" - required: true - default: false - prerelease: + release_candidate_name: type: string description: "Release Candidate Name, adjust after every succinct release candidate (e.g. to rc.2, rc.3...)" required: true default: "rc.1" jobs: + release-version: + name: Release Version + uses: ./.github/workflows/release-version.yaml + with: + release_candidate: ${{ inputs.release_candidate }} + release_candidate_name: ${{ inputs.release_candidate_name }} + permissions: + contents: read + repository-projects: read check: name: Check Release Preconditions - runs-on: large_runner + runs-on: ubuntu-latest permissions: - contents: write - id-token: write + contents: read repository-projects: read + needs: release-version + env: + RELEASE_VERSION: ${{ needs.release-version.outputs.version }} + RELEASE_VERSION_NO_SUFFIX: ${{ needs.release-version.outputs.version_no_suffix }} + REF: ${{ github.ref }} + outputs: + draft-release-notes: ${{ steps.release-notes.outputs.json }} steps: - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 0 - - - name: Generate Base Version - run: | - BASE_VERSION=v$(go run $GITHUB_WORKSPACE/api/version/generate print-version) - echo "BASE_VERSION=$BASE_VERSION" >> $GITHUB_ENV - - - name: Generate Pre-Release Version - if: inputs.release_candidate == true - run: | - RELEASE_VERSION=v$(go run $GITHUB_WORKSPACE/api/version/generate --no-dev print-rc-version ${{ github.event.inputs.prerelease }}) - echo "RELEASE_VERSION=$RELEASE_VERSION" >> $GITHUB_ENV - - name: Generate Release Version - if: inputs.release_candidate == false - run: | - RELEASE_VERSION=${{env.BASE_VERSION}} - echo "RELEASE_VERSION=$RELEASE_VERSION" >> $GITHUB_ENV - - name: Check Tag run: | set -e @@ -56,25 +49,35 @@ jobs: >&2 echo "tag ${{ env.RELEASE_VERSION }} already exists" exit 1 fi - - - name: Check Branch - if: inputs.release_candidate == false && inputs.create_branch && github.ref == 'refs/heads/main' + - name: Check if release is running on release branch run: | - set -e - if git ls-remote --exit-code origin refs/heads/releases/${{ env.RELEASE_VERSION }} ; then - >&2 echo "branch releases/${{ env.RELEASE_VERSION }} already exists" - exit 1 + if [[ ${{ env.REF }} != *"releases/"* ]]; then + echo "The branch ${{ env.REF }} is not a valid release branch and cannot be used for a release" + exit 1 fi - - - name: Get Draft Release Notes + echo "Branch ${{ env.REF }} is a valid release branch" + - name: Generate token + id: generate_token + uses: tibdex/github-app-token@v2 + with: + app_id: ${{ secrets.OCMBOT_APP_ID }} + private_key: ${{ secrets.OCMBOT_PRIV_KEY }} + - name: Ensure existing Draft Release Notes exist id: release-notes - uses: cardinalby/git-get-release-action@v1 + shell: bash env: - GITHUB_TOKEN: ${{ github.token }} - with: - draft: true - releaseName: ${{ env.BASE_VERSION }} - + GH_TOKEN: ${{ steps.generate_token.outputs.token }} + run: | + RELEASE_JSON=$( \ + gh api /repos/${{ github.repository }}/releases \ + -q '.[] | select(.name == "${{ env.RELEASE_VERSION_NO_SUFFIX }}" and .draft == true)' \ + ) + echo "json=${RELEASE_JSON}" >> $GITHUB_OUTPUT + # if no draft release notes are found, we cannot continue + if [ -z "${RELEASE_JSON}" ]; then + echo "No draft release notes found for ${{ env.RELEASE_VERSION_NO_SUFFIX }}" + exit 1 + fi components: name: Component CTF Builds uses: ./.github/workflows/components.yaml @@ -89,12 +92,16 @@ jobs: # run check before actual release to make sure we succeed # they will be skipped from the needs check - check + - release-version name: Release Build runs-on: large_runner permissions: contents: write id-token: write packages: write + env: + RELEASE_VERSION: ${{ needs.release-version.outputs.version }} + RELEASE_NOTES: ${{ fromJSON(needs.check.outputs.draft-release-notes).body }} steps: - name: Self Hosted Runner Post Job Cleanup Action uses: TooMuch4U/actions-clean@v2.2 @@ -111,35 +118,6 @@ jobs: fetch-depth: 0 token: ${{ steps.generate_token.outputs.token }} - - name: Setup Go - uses: actions/setup-go@v5 - with: - go-version-file: '${{ github.workspace }}/go.mod' - check-latest: false - cache: false - - - name: Get go environment for use with cache - run: | - echo "go_cache=$(go env GOCACHE)" >> $GITHUB_ENV - echo "go_modcache=$(go env GOMODCACHE)" >> $GITHUB_ENV - - # This step will only reuse the go mod and build cache from main made during the Build, - # see push_ocm.yaml => "ocm-cli-latest" Job - # This means it never caches by itself and PRs cannot cause cache pollution / thrashing - # This is because we have huge storage requirements for our cache because of the mass of dependencies - - name: Restore / Reuse Cache from central build - id: cache-golang-restore - uses: actions/cache/restore@v4 # Only Restore, not build another cache (too big) - with: - path: | - ${{ env.go_cache }} - ${{ env.go_modcache }} - key: ${{ env.cache_name }}-${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}-${{ hashFiles('**/go.mod') }} - restore-keys: | - ${{ env.cache_name }}-${{ runner.os }}-go- - env: - cache_name: ocm-cli-latest-go-cache # needs to be the same key in the end as in the build step - - name: Setup Syft uses: anchore/sbom-action/download-syft@fc46e51fd3cb168ffb36c6d1915723c47db58abb # v0.17.7 @@ -151,35 +129,8 @@ jobs: git config user.name "GitHub Actions Bot" git config user.email "<41898282+github-actions[bot]@users.noreply.github.com>" - - name: Set Base Version - run: | - BASE_VERSION=v$(go run $GITHUB_WORKSPACE/api/version/generate print-version) - echo "BASE_VERSION=$BASE_VERSION" >> $GITHUB_ENV - - name: Set Pre-Release Version - if: inputs.release_candidate == true - run: | - RELEASE_VERSION=v$(go run $GITHUB_WORKSPACE/api/version/generate --no-dev print-rc-version ${{ github.event.inputs.prerelease }}) - echo "RELEASE_VERSION=$RELEASE_VERSION" >> $GITHUB_ENV - echo "release name is $RELEASE_VERSION" - - name: Set Version - if: inputs.release_candidate == false - run: | - RELEASE_VERSION=${{env.BASE_VERSION}} - echo "RELEASE_VERSION=$RELEASE_VERSION" >> $GITHUB_ENV - echo "release name is $RELEASE_VERSION" - - - name: Get Draft Release Notes - id: release-notes - uses: cardinalby/git-get-release-action@v1 - env: - GITHUB_TOKEN: ${{ github.token }} - with: - draft: true - releaseName: ${{ env.BASE_VERSION }} - - name: Update Release Notes File env: - RELEASE_NOTES: ${{ steps.release-notes.outputs.body }} GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }} run: | if git ls-remote --exit-code origin refs/tags/${{ env.RELEASE_VERSION }}; then @@ -225,7 +176,6 @@ jobs: env: GITHUBORG: ${{ github.repository_owner }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - HOMEBREW_TAP_GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }} GORELEASER_CURRENT_TAG: ${{ env.RELEASE_VERSION }} NFPM_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} @@ -239,17 +189,6 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: make plain-push - - name: Create Release Branch - if: inputs.release_candidate == false && inputs.create_branch && github.ref == 'refs/heads/main' - run: | - n="releases/${{env.RELEASE_VERSION}}" - git checkout -b "$n" - v="$(go run ./api/version/generate bump-patch)" - echo "$v" > VERSION - git add VERSION - git commit -m "Prepare Development of v$v" - git push origin "$n" - - name: Bump Version File if: inputs.release_candidate == false run: | From 782970c77f9da3ab8d73eb7904a50d0b1a9d1aba Mon Sep 17 00:00:00 2001 From: Uwe Krueger Date: Tue, 12 Nov 2024 15:05:46 +0100 Subject: [PATCH 47/58] fix implicit version handling of an artifact identity (#1026) #### What this PR does / why we need it The defaulting of the extraIdentity did only work, if there was an identity map already set. So far the version was implicutly added to the extraIdentity of a CV if the rest is not unique. In the future the extraIdentity should be explicitly set to be unique. Therefore, the version was now implicitly added to the extraIdentity. This has two problems: - it was only done, if there was already an identity map set, - it was always done, when serializing a CD To be comparable with older signed component versions, such defaulting may only be done if the content of a component version is changed, otherwise the signature would be brocken. #### Which issue(s) this PR fixes --- api/helper/builder/ocm_identity.go | 16 ++ api/helper/builder/ocm_reference.go | 3 +- api/helper/builder/ocm_resource.go | 4 +- api/oci/ociutils/ref.go | 3 +- api/ocm/add_test.go | 14 +- api/ocm/compdesc/componentdescriptor.go | 17 +- api/ocm/compdesc/default.go | 47 +++++- .../versions/ocm.software/v3alpha1/default.go | 26 --- api/ocm/compdesc/versions/v2/default.go | 26 --- api/ocm/cpi/dummy.go | 8 +- api/ocm/cpi/modopts.go | 22 ++- api/ocm/cpi/repocpi/view_cv.go | 46 ++++-- api/ocm/internal/modopts.go | 145 ++++++++++++----- api/ocm/internal/repository.go | 11 +- api/ocm/modopts.go | 16 +- api/ocm/tools/signing/handler_test.go | 14 +- api/ocm/tools/signing/signing_test.go | 153 ++++++++++++++++++ api/ocm/tools/transfer/transfer.go | 2 +- .../commands/ocmcmds/common/addhdlrs/base.go | 8 +- .../ocmcmds/common/addhdlrs/options.go | 51 ++++-- .../ocmcmds/common/addhdlrs/refs/elements.go | 3 +- .../ocmcmds/common/addhdlrs/rscs/elements.go | 12 +- .../ocmcmds/common/addhdlrs/srcs/elements.go | 4 +- .../commands/ocmcmds/components/hash/cmd.go | 45 ++++-- .../ocmcmds/components/hash/cmd_test.go | 44 +++++ .../ocmcmds/components/hash/options.go | 2 +- docs/reference/ocm_add_componentversions.md | 6 +- docs/reference/ocm_add_references.md | 6 +- docs/reference/ocm_add_resources.md | 6 +- docs/reference/ocm_add_sources.md | 6 +- docs/reference/ocm_hash_componentversions.md | 2 +- 31 files changed, 588 insertions(+), 180 deletions(-) diff --git a/api/helper/builder/ocm_identity.go b/api/helper/builder/ocm_identity.go index f77719a7e3..ec302ee622 100644 --- a/api/helper/builder/ocm_identity.go +++ b/api/helper/builder/ocm_identity.go @@ -1,5 +1,9 @@ package builder +import ( + metav1 "ocm.software/ocm/api/ocm/compdesc/meta/v1" +) + const T_OCMMETA = "element with metadata" //////////////////////////////////////////////////////////////////////////////// @@ -10,6 +14,18 @@ func (b *Builder) ExtraIdentity(name string, value string) { b.ocm_meta.ExtraIdentity.Set(name, value) } +func (b *Builder) ExtraIdentities(extras ...string) { + b.expect(b.ocm_meta, T_OCMMETA) + + id := metav1.NewExtraIdentity(extras...) + if b.ocm_meta.ExtraIdentity == nil { + b.ocm_meta.ExtraIdentity = metav1.Identity{} + } + for k, v := range id { + b.ocm_meta.ExtraIdentity.Set(k, v) + } +} + //////////////////////////////////////////////////////////////////////////////// func (b *Builder) RemoveExtraIdentity(name string) { diff --git a/api/helper/builder/ocm_reference.go b/api/helper/builder/ocm_reference.go index 93fc02f932..8f3d2b92f7 100644 --- a/api/helper/builder/ocm_reference.go +++ b/api/helper/builder/ocm_reference.go @@ -1,6 +1,7 @@ package builder import ( + "ocm.software/ocm/api/ocm" "ocm.software/ocm/api/ocm/compdesc" ) @@ -22,7 +23,7 @@ func (r *ocmReference) Set() { } func (r *ocmReference) Close() error { - return r.ocm_vers.SetReference(&r.meta) + return r.ocm_vers.SetReference(&r.meta, ocm.ModifyElement()) } //////////////////////////////////////////////////////////////////////////////// diff --git a/api/helper/builder/ocm_resource.go b/api/helper/builder/ocm_resource.go index 9b3ffe30dc..fb29c85b65 100644 --- a/api/helper/builder/ocm_resource.go +++ b/api/helper/builder/ocm_resource.go @@ -42,9 +42,9 @@ func (r *ocmResource) Close() error { } switch { case r.access != nil: - return r.Builder.ocm_vers.SetResource(&r.meta, r.access, r.opts.ApplyModificationOptions((ocm.ModifyResource()))) + return r.Builder.ocm_vers.SetResource(&r.meta, r.access, r.opts.ApplyModificationOptions((ocm.ModifyElement()))) case r.blob != nil: - return r.Builder.ocm_vers.SetResourceBlob(&r.meta, r.blob, r.hint, nil, r.opts.ApplyModificationOptions((ocm.ModifyResource()))) + return r.Builder.ocm_vers.SetResourceBlob(&r.meta, r.blob, r.hint, nil, r.opts.ApplyModificationOptions((ocm.ModifyElement()))) } return errors.New("access or blob required") } diff --git a/api/oci/ociutils/ref.go b/api/oci/ociutils/ref.go index 50f7675264..5d05921777 100644 --- a/api/oci/ociutils/ref.go +++ b/api/oci/ociutils/ref.go @@ -89,8 +89,7 @@ func (v *ArtVersion) IsDigested() bool { } func (v *ArtVersion) GetTag() string { - if v != nil && - v.Tag != nil { + if v != nil && v.Tag != nil { return *v.Tag } return "" diff --git a/api/ocm/add_test.go b/api/ocm/add_test.go index 9d27a6c0de..1c33309f7d 100644 --- a/api/ocm/add_test.go +++ b/api/ocm/add_test.go @@ -179,13 +179,13 @@ var _ = Describe("add resources", func() { Context("references", func() { It("adds reference", func() { ref := ocm.NewComponentReference("test", COMPONENT+"/sub", "v1") - MustBeSuccessful(cv.SetReference(ref)) + MustBeSuccessful(cv.SetReference(ref, ocm.ModifyElement())) Expect(len(cv.GetDescriptor().References)).To(Equal(1)) }) It("replaces reference", func() { ref := ocm.NewComponentReference("test", COMPONENT+"/sub", "v1") - MustBeSuccessful(cv.SetReference(ref)) + MustBeSuccessful(cv.SetReference(ref, ocm.ModifyElement())) MustBeSuccessful(cv.SetReference(ref.WithVersion("v1"))) Expect(len(Must(cv.SelectReferences(selectors.Name("test"))))).To(Equal(1)) @@ -193,7 +193,7 @@ var _ = Describe("add resources", func() { It("replaces source (enforced)", func() { ref := ocm.NewComponentReference("test", COMPONENT+"/sub", "v1") - MustBeSuccessful(cv.SetReference(ref)) + MustBeSuccessful(cv.SetReference(ref, ocm.ModifyElement())) MustBeSuccessful(cv.SetReference(ref.WithVersion("v2"))) Expect(len(Must(cv.SelectReferences(selectors.Name("test"))))).To(Equal(1)) @@ -201,7 +201,7 @@ var _ = Describe("add resources", func() { It("fails replace non-existent source)", func() { ref := ocm.NewComponentReference("test", COMPONENT+"/sub", "v1") - MustBeSuccessful(cv.SetReference(ref)) + MustBeSuccessful(cv.SetReference(ref, ocm.ModifyElement())) Expect(cv.SetReference(ref.WithExtraIdentity("attr", "value"), ocm.UpdateElement)).To( MatchError("element \"attr\"=\"value\",\"name\"=\"test\" not found")) @@ -209,21 +209,21 @@ var _ = Describe("add resources", func() { It("adds duplicate reference with different version", func() { ref := ocm.NewComponentReference("test", COMPONENT+"/sub", "v1") - MustBeSuccessful(cv.SetReference(ref)) + MustBeSuccessful(cv.SetReference(ref, ocm.ModifyElement())) MustBeSuccessful(cv.SetReference(ref.WithVersion("v2"), ocm.AppendElement)) Expect(len(Must(cv.SelectReferences(selectors.Name("test"))))).To(Equal(2)) }) It("rejects duplicate reference with same version", func() { ref := ocm.NewComponentReference("test", COMPONENT+"/sub", "v1") - MustBeSuccessful(cv.SetReference(ref)) + MustBeSuccessful(cv.SetReference(ref, ocm.ModifyElement())) Expect(cv.SetReference(ref.WithVersion("v1"), ocm.AppendElement)). To(MatchError("adding a new reference with same base identity requires different version")) }) It("rejects duplicate reference with extra identity", func() { ref := ocm.NewComponentReference("test", COMPONENT+"/sub", "v1").WithExtraIdentity("attr", "value") - MustBeSuccessful(cv.SetReference(ref)) + MustBeSuccessful(cv.SetReference(ref, ocm.ModifyElement())) Expect(cv.SetReference(ref, ocm.AppendElement)). To(MatchError("adding a new reference with same base identity requires different version")) }) diff --git a/api/ocm/compdesc/componentdescriptor.go b/api/ocm/compdesc/componentdescriptor.go index 02feb8d26c..8638dfdb7c 100644 --- a/api/ocm/compdesc/componentdescriptor.go +++ b/api/ocm/compdesc/componentdescriptor.go @@ -238,18 +238,21 @@ func (o *ElementMeta) GetIdentity(accessor ElementListAccessor) metav1.Identity identity = metav1.Identity{} } identity[SystemIdentityName] = o.Name - if accessor != nil { + if identity.Get(SystemIdentityVersion) == "" && accessor != nil { found := false l := accessor.Len() for i := 0; i < l; i++ { m := accessor.Get(i).GetMeta() - if m.GetName() == o.Name && m.GetExtraIdentity().Equals(o.ExtraIdentity) { - if found { - identity[SystemIdentityVersion] = o.Version - - break + if m.GetName() == o.Name { + mid := m.GetExtraIdentity() + mid.Remove(SystemIdentityVersion) + if mid.Equals(o.ExtraIdentity) { + if found { + identity[SystemIdentityVersion] = o.Version + break + } + found = true } - found = true } } } diff --git a/api/ocm/compdesc/default.go b/api/ocm/compdesc/default.go index af504034f2..22c3359152 100644 --- a/api/ocm/compdesc/default.go +++ b/api/ocm/compdesc/default.go @@ -27,9 +27,16 @@ func DefaultComponent(component *ComponentDescriptor) *ComponentDescriptor { return component } +func DefaultElements(component *ComponentDescriptor) { + DefaultResources(component) + DefaultSources(component) + DefaultReferences(component) +} + // DefaultResources defaults a list of resources. // The version of the component is defaulted for local resources that do not contain a version. // adds the version as identity if the resource identity would clash otherwise. +// The version is added to an extraIdentity, if it is not unique without it. func DefaultResources(component *ComponentDescriptor) { for i, res := range component.Resources { if res.Relation == v1.LocalRelation && len(res.Version) == 0 { @@ -39,7 +46,45 @@ func DefaultResources(component *ComponentDescriptor) { id := res.GetIdentity(component.Resources) if v, ok := id[SystemIdentityVersion]; ok { if res.ExtraIdentity == nil { - res.ExtraIdentity = v1.Identity{ + component.Resources[i].ExtraIdentity = v1.Identity{ + SystemIdentityVersion: v, + } + } else { + if _, ok := res.ExtraIdentity[SystemIdentityVersion]; !ok { + res.ExtraIdentity[SystemIdentityVersion] = v + } + } + } + } +} + +// DefaultSources defaults a list of sources. +// The version is added to an extraIdentity, if it is not unique without it. +func DefaultSources(component *ComponentDescriptor) { + for i, res := range component.Sources { + id := res.GetIdentity(component.Resources) + if v, ok := id[SystemIdentityVersion]; ok { + if res.ExtraIdentity == nil { + component.Sources[i].ExtraIdentity = v1.Identity{ + SystemIdentityVersion: v, + } + } else { + if _, ok := res.ExtraIdentity[SystemIdentityVersion]; !ok { + res.ExtraIdentity[SystemIdentityVersion] = v + } + } + } + } +} + +// DefaultReferences defaults a list of references. +// The version is added to an extraIdentity, if it is not unique without it. +func DefaultReferences(component *ComponentDescriptor) { + for i, res := range component.References { + id := res.GetIdentity(component.Resources) + if v, ok := id[SystemIdentityVersion]; ok { + if res.ExtraIdentity == nil { + component.References[i].ExtraIdentity = v1.Identity{ SystemIdentityVersion: v, } } else { diff --git a/api/ocm/compdesc/versions/ocm.software/v3alpha1/default.go b/api/ocm/compdesc/versions/ocm.software/v3alpha1/default.go index 0a03ce49ab..979c2b09ea 100644 --- a/api/ocm/compdesc/versions/ocm.software/v3alpha1/default.go +++ b/api/ocm/compdesc/versions/ocm.software/v3alpha1/default.go @@ -1,7 +1,6 @@ package v3alpha1 import ( - v1 "ocm.software/ocm/api/ocm/compdesc/meta/v1" "ocm.software/ocm/api/utils/runtime" ) @@ -20,30 +19,5 @@ func (cd *ComponentDescriptor) Default() error { cd.Spec.Resources = make([]Resource, 0) } - DefaultResources(cd) return nil } - -// DefaultResources defaults a list of resources. -// The version of the component is defaulted for local resources that do not contain a version. -// adds the version as identity if the resource identity would clash otherwise. -func DefaultResources(component *ComponentDescriptor) { - for i, res := range component.Spec.Resources { - if res.Relation == v1.LocalRelation && len(res.Version) == 0 { - component.Spec.Resources[i].Version = component.GetVersion() - } - - id := res.GetIdentity(component.Spec.Resources) - if v, ok := id[SystemIdentityVersion]; ok { - if res.ExtraIdentity == nil { - res.ExtraIdentity = v1.Identity{ - SystemIdentityVersion: v, - } - } else { - if _, ok := res.ExtraIdentity[SystemIdentityVersion]; !ok { - res.ExtraIdentity[SystemIdentityVersion] = v - } - } - } - } -} diff --git a/api/ocm/compdesc/versions/v2/default.go b/api/ocm/compdesc/versions/v2/default.go index ce4aec2201..08ea24a1a3 100644 --- a/api/ocm/compdesc/versions/v2/default.go +++ b/api/ocm/compdesc/versions/v2/default.go @@ -1,7 +1,6 @@ package v2 import ( - v1 "ocm.software/ocm/api/ocm/compdesc/meta/v1" "ocm.software/ocm/api/utils/runtime" ) @@ -20,30 +19,5 @@ func (cd *ComponentDescriptor) Default() error { cd.Resources = make([]Resource, 0) } - DefaultResources(cd) return nil } - -// DefaultResources defaults a list of resources. -// The version of the component is defaulted for local resources that do not contain a version. -// adds the version as identity if the resource identity would clash otherwise. -func DefaultResources(component *ComponentDescriptor) { - for i, res := range component.Resources { - if res.Relation == v1.LocalRelation && len(res.Version) == 0 { - component.Resources[i].Version = component.GetVersion() - } - - id := res.GetIdentity(component.Resources) - if v, ok := id[SystemIdentityVersion]; ok { - if res.ExtraIdentity == nil { - res.ExtraIdentity = v1.Identity{ - SystemIdentityVersion: v, - } - } else { - if _, ok := res.ExtraIdentity[SystemIdentityVersion]; !ok { - res.ExtraIdentity[SystemIdentityVersion] = v - } - } - } - } -} diff --git a/api/ocm/cpi/dummy.go b/api/ocm/cpi/dummy.go index 7181a35c05..fa45b54aa4 100644 --- a/api/ocm/cpi/dummy.go +++ b/api/ocm/cpi/dummy.go @@ -164,19 +164,19 @@ func (d *DummyComponentVersionAccess) SetResourceByAccess(art ResourceAccess, mo return errors.ErrNotSupported("resource modification") } -func (d *DummyComponentVersionAccess) SetSourceBlob(meta *SourceMeta, blob BlobAccess, refname string, global AccessSpec, opts ...TargetOption) error { +func (d *DummyComponentVersionAccess) SetSourceBlob(meta *SourceMeta, blob BlobAccess, refname string, global AccessSpec, opts ...TargetElementOption) error { return errors.ErrNotSupported("source modification") } -func (d *DummyComponentVersionAccess) SetSource(meta *SourceMeta, spec compdesc.AccessSpec, opts ...TargetOption) error { +func (d *DummyComponentVersionAccess) SetSource(meta *SourceMeta, spec compdesc.AccessSpec, opts ...TargetElementOption) error { return errors.ErrNotSupported("source modification") } -func (d *DummyComponentVersionAccess) SetSourceByAccess(art SourceAccess, opts ...TargetOption) error { +func (d *DummyComponentVersionAccess) SetSourceByAccess(art SourceAccess, opts ...TargetElementOption) error { return errors.ErrNotSupported() } -func (d *DummyComponentVersionAccess) SetReference(ref *ComponentReference, opts ...TargetOption) error { +func (d *DummyComponentVersionAccess) SetReference(ref *ComponentReference, opts ...ElementModificationOption) error { return errors.ErrNotSupported() } diff --git a/api/ocm/cpi/modopts.go b/api/ocm/cpi/modopts.go index 1666c0355b..ebdfeab00d 100644 --- a/api/ocm/cpi/modopts.go +++ b/api/ocm/cpi/modopts.go @@ -9,9 +9,12 @@ import ( ) type ( - TargetElement = internal.TargetElement - TargetOption = internal.TargetOption - TargetOptions = internal.TargetOptions + TargetElement = internal.TargetElement + TargetElementOption = internal.TargetElementOption + TargetElementOptions = internal.TargetElementOptions + + ElementModificationOption = internal.ElementModificationOption + ElementModificationOptions = internal.ElementModificationOptions ModificationOption = internal.ModificationOption ModificationOptions = internal.ModificationOptions @@ -26,8 +29,8 @@ type ( AddVersionOptions = internal.AddVersionOptions ) -func NewTargetOptions(list ...TargetOption) *TargetOptions { - var m TargetOptions +func NewTargetElementOptions(list ...TargetElementOption) *TargetElementOptions { + var m TargetElementOptions m.ApplyTargetOptions(list...) return &m } @@ -65,6 +68,10 @@ func NewModificationOptions(list ...ModificationOption) *ModificationOptions { return internal.NewModificationOptions(list...) } +func NewElementModificationOptions(list ...ElementModificationOption) *ElementModificationOptions { + return internal.NewElementModificationOptions(list...) +} + func TargetIndex(idx int) internal.TargetIndex { return internal.TargetIndex(-1) } @@ -77,10 +84,15 @@ func TargetIdentity(id v1.Identity) internal.TargetIdentity { return internal.TargetIdentity(id) } +// Deprecated: use ModifyElement. func ModifyResource(flag ...bool) internal.ModOptionImpl { return internal.ModifyResource(flag...) } +func ModifyElement(flag ...bool) internal.ElemModOptionImpl { + return internal.ModifyElement(flag...) +} + func AcceptExistentDigests(flag ...bool) internal.ModOptionImpl { return internal.AcceptExistentDigests(flag...) } diff --git a/api/ocm/cpi/repocpi/view_cv.go b/api/ocm/cpi/repocpi/view_cv.go index 98e43e2aa6..2c36d65db8 100644 --- a/api/ocm/cpi/repocpi/view_cv.go +++ b/api/ocm/cpi/repocpi/view_cv.go @@ -249,7 +249,7 @@ func (c *componentVersionAccessView) SetResourceBlob(meta *cpi.ResourceMeta, blo return fmt.Errorf("unable to add blob (component %s:%s resource %s): %w", c.GetName(), c.GetVersion(), meta.GetName(), err) } - if err := c.SetResource(meta, acc, eff, cpi.ModifyResource()); err != nil { + if err := c.SetResource(meta, acc, eff, cpi.ModifyElement()); err != nil { return fmt.Errorf("unable to set resource: %w", err) } @@ -264,7 +264,7 @@ func (c *componentVersionAccessView) AdjustSourceAccess(meta *cpi.SourceMeta, ac return errors.ErrUnknown(cpi.KIND_RESOURCE, meta.GetIdentity(cd.Resources).String()) } -func (c *componentVersionAccessView) SetSourceBlob(meta *cpi.SourceMeta, blob cpi.BlobAccess, refName string, global cpi.AccessSpec, modopts ...cpi.TargetOption) error { +func (c *componentVersionAccessView) SetSourceBlob(meta *cpi.SourceMeta, blob cpi.BlobAccess, refName string, global cpi.AccessSpec, modopts ...cpi.TargetElementOption) error { cpi.Logger(c).Debug("adding source blob", "source", meta.Name) if err := utils.ValidateObject(blob); err != nil { return err @@ -384,7 +384,7 @@ func (c *componentVersionAccessView) SetResource(meta *cpi.ResourceMeta, acc com cd := c.bridge.GetDescriptor() - idx, err := c.getElementIndex("resource", cd.Resources, res, &opts.TargetOptions) + idx, err := c.getElementIndex("resource", cd.Resources, res, &opts.TargetElementOptions) if err != nil { return err } @@ -393,7 +393,7 @@ func (c *componentVersionAccessView) SetResource(meta *cpi.ResourceMeta, acc com } if old == nil { - if !opts.IsModifyResource() && c.bridge.IsPersistent() { + if !opts.IsModifyElement() && c.bridge.IsPersistent() { return fmt.Errorf("new resource would invalidate signature") } } @@ -456,7 +456,7 @@ func (c *componentVersionAccessView) SetResource(meta *cpi.ResourceMeta, acc com if old != nil { eq := res.Equivalent(old) if !eq.IsLocalHashEqual() && c.bridge.IsPersistent() { - if !opts.IsModifyResource() { + if !opts.IsModifyElement() { return fmt.Errorf("resource would invalidate signature") } cd.Signatures = nil @@ -468,6 +468,10 @@ func (c *componentVersionAccessView) SetResource(meta *cpi.ResourceMeta, acc com } else { cd.Resources[idx] = *res } + if opts.IsModifyElement() { + // default handling for completing an extra identity for modifications, only. + compdesc.DefaultResources(cd) + } return c.bridge.Update(false) }) } @@ -499,7 +503,7 @@ func (c *componentVersionAccessView) evaluateResourceDigest(res, old *compdesc.R if !old.Digest.IsNone() { digester.HashAlgorithm = old.Digest.HashAlgorithm digester.NormalizationAlgorithm = old.Digest.NormalisationAlgorithm - if opts.IsAcceptExistentDigests() && !opts.IsModifyResource() && c.bridge.IsPersistent() { + if opts.IsAcceptExistentDigests() && !opts.IsModifyElement() && c.bridge.IsPersistent() { res.Digest = old.Digest value = old.Digest.Value } @@ -508,7 +512,7 @@ func (c *componentVersionAccessView) evaluateResourceDigest(res, old *compdesc.R return hashAlgo, digester, value } -func (c *componentVersionAccessView) SetSourceByAccess(art cpi.SourceAccess, optslist ...cpi.TargetOption) error { +func (c *componentVersionAccessView) SetSourceByAccess(art cpi.SourceAccess, optslist ...cpi.TargetElementOption) error { return setAccess(c, "source", art, func(meta *cpi.SourceMeta, acc compdesc.AccessSpec) error { return c.SetSource(meta, acc, optslist...) @@ -518,7 +522,7 @@ func (c *componentVersionAccessView) SetSourceByAccess(art cpi.SourceAccess, opt }) } -func (c *componentVersionAccessView) SetSource(meta *cpi.SourceMeta, acc compdesc.AccessSpec, optlist ...cpi.TargetOption) error { +func (c *componentVersionAccessView) SetSource(meta *cpi.SourceMeta, acc compdesc.AccessSpec, optlist ...cpi.TargetElementOption) error { if c.bridge.IsReadOnly() { return accessio.ErrReadOnly } @@ -544,33 +548,51 @@ func (c *componentVersionAccessView) SetSource(meta *cpi.SourceMeta, acc compdes } else { cd.Sources[idx] = *res } + compdesc.DefaultSources(cd) return c.bridge.Update(false) }) } -func (c *componentVersionAccessView) SetReference(ref *cpi.ComponentReference, optlist ...cpi.TargetOption) error { +func (c *componentVersionAccessView) SetReference(ref *cpi.ComponentReference, optlist ...cpi.ElementModificationOption) error { + opts := cpi.NewElementModificationOptions(optlist...) + moddef := false + return c.Execute(func() error { cd := c.bridge.GetDescriptor() if ref.Version == "" { return fmt.Errorf("version required for component version reference") } - idx, err := c.getElementIndex("reference", cd.References, ref, optlist...) + idx, err := c.getElementIndex("reference", cd.References, ref, &opts.TargetElementOptions) if err != nil { return err } if idx < 0 { + if !opts.IsModifyElement(moddef) { + return fmt.Errorf("adding reference would invalidate signature") + } cd.References = append(cd.References, *ref) } else { + eq := ref.Equivalent(&cd.References[idx]) + if !eq.IsEquivalent() && c.bridge.IsPersistent() { + if !opts.IsModifyElement(moddef) { + return fmt.Errorf("reference would invalidate signature") + } + cd.Signatures = nil + } + cd.References[idx].Equivalent(ref) cd.References[idx] = *ref } + if opts.IsModifyElement(moddef) { + compdesc.DefaultReferences(cd) + } return c.bridge.Update(false) }) } -func (c *componentVersionAccessView) getElementIndex(kind string, acc compdesc.ElementListAccessor, prov compdesc.ElementMetaProvider, optlist ...cpi.TargetOption) (int, error) { - opts := internal.NewTargetOptions(optlist...) +func (c *componentVersionAccessView) getElementIndex(kind string, acc compdesc.ElementListAccessor, prov compdesc.ElementMetaProvider, optlist ...cpi.TargetElementOption) (int, error) { + opts := internal.NewTargetElementOptions(optlist...) curidx := compdesc.ElementIndex(acc, prov) meta := prov.GetMeta() var idx int diff --git a/api/ocm/internal/modopts.go b/api/ocm/internal/modopts.go index 41826374bc..3732c59434 100644 --- a/api/ocm/internal/modopts.go +++ b/api/ocm/internal/modopts.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/mandelsoft/goutils/general" + "github.com/mandelsoft/goutils/generics" "github.com/mandelsoft/goutils/optionutils" "ocm.software/ocm/api/ocm/compdesc" @@ -100,32 +101,36 @@ type TargetElement interface { } type TargetOptionImpl interface { - TargetOption + TargetElementOption ModificationOption BlobModificationOption } -type TargetOptions struct { +type TargetElementOptions struct { TargetElement TargetElement } -type TargetOption interface { - ApplyTargetOption(options *TargetOptions) +type TargetElementOption interface { + ApplyTargetOption(options *TargetElementOptions) } -func (m *TargetOptions) ApplyBlobModificationOption(opts *BlobModificationOptions) { - m.ApplyTargetOption(&opts.TargetOptions) +func (m *TargetElementOptions) ApplyBlobModificationOption(opts *BlobModificationOptions) { + m.ApplyTargetOption(&opts.TargetElementOptions) } -func (m *TargetOptions) ApplyModificationOption(opts *ModificationOptions) { - m.ApplyTargetOption(&opts.TargetOptions) +func (m *TargetElementOptions) ApplyModificationOption(opts *ModificationOptions) { + m.ApplyTargetOption(&opts.TargetElementOptions) } -func (m *TargetOptions) ApplyTargetOption(opts *TargetOptions) { +func (m *TargetElementOptions) ApplyElementModificationOption(opts *ElementModificationOptions) { + m.ApplyTargetOption(&opts.TargetElementOptions) +} + +func (m *TargetElementOptions) ApplyTargetOption(opts *TargetElementOptions) { optionutils.Transfer(&opts.TargetElement, m.TargetElement) } -func (m *TargetOptions) ApplyTargetOptions(list ...TargetOption) *TargetOptions { +func (m *TargetElementOptions) ApplyTargetOptions(list ...TargetElementOption) *TargetElementOptions { for _, o := range list { if o != nil { o.ApplyTargetOption(m) @@ -134,12 +139,55 @@ func (m *TargetOptions) ApplyTargetOptions(list ...TargetOption) *TargetOptions return m } -func NewTargetOptions(list ...TargetOption) *TargetOptions { - var m TargetOptions +func NewTargetElementOptions(list ...TargetElementOption) *TargetElementOptions { + var m TargetElementOptions m.ApplyTargetOptions(list...) return &m } +type ElementModificationOption interface { + ApplyElementModificationOption(opts *ElementModificationOptions) +} + +type ElementModificationOptions struct { + TargetElementOptions + + // ModifyElement disables the modification of signature relevant + // resource parts. + ModifyElement *bool +} + +func (m *ElementModificationOptions) ApplyBlobModificationOption(opts *BlobModificationOptions) { + m.ApplyElementModificationOption(&opts.ElementModificationOptions) +} + +func (m *ElementModificationOptions) ApplyModificationOption(opts *ModificationOptions) { + m.ApplyElementModificationOption(&opts.ElementModificationOptions) +} + +func (m *ElementModificationOptions) ApplyElementModificationOption(opts *ElementModificationOptions) { + optionutils.Transfer(&opts.ModifyElement, m.ModifyElement) +} + +func (m *ElementModificationOptions) ApplyElementModificationOptions(list ...ElementModificationOption) *ElementModificationOptions { + for _, o := range list { + if o != nil { + o.ApplyElementModificationOption(m) + } + } + return m +} + +func (m *ElementModificationOptions) IsModifyElement(def ...bool) bool { + return utils.AsBool(m.ModifyElement, def...) +} + +func NewElementModificationOptions(list ...ElementModificationOption) *ElementModificationOptions { + var m ElementModificationOptions + m.ApplyElementModificationOptions(list...) + return &m +} + type ModificationOption interface { ApplyModificationOption(opts *ModificationOptions) } @@ -149,12 +197,14 @@ type ModOptionImpl interface { BlobModificationOption } -type ModificationOptions struct { - TargetOptions +type ElemModOptionImpl interface { + ElementModificationOption + ModificationOption + BlobModificationOption +} - // ModifyResource disables the modification of signature releveant - // resource parts. - ModifyResource *bool +type ModificationOptions struct { + ElementModificationOptions // AcceptExistentDigests don't validate/recalculate the content digest // of resources. @@ -173,10 +223,6 @@ type ModificationOptions struct { SkipDigest *bool } -func (m *ModificationOptions) IsModifyResource() bool { - return utils.AsBool(m.ModifyResource) -} - func (m *ModificationOptions) IsAcceptExistentDigests() bool { return utils.AsBool(m.AcceptExistentDigests) } @@ -203,8 +249,8 @@ func (m *ModificationOptions) ApplyBlobModificationOption(opts *BlobModification } func (m *ModificationOptions) ApplyModificationOption(opts *ModificationOptions) { - m.TargetOptions.ApplyTargetOption(&opts.TargetOptions) - optionutils.Transfer(&opts.ModifyResource, m.ModifyResource) + m.TargetElementOptions.ApplyTargetOption(&opts.TargetElementOptions) + optionutils.Transfer(&opts.ModifyElement, m.ModifyElement) optionutils.Transfer(&opts.AcceptExistentDigests, m.AcceptExistentDigests) optionutils.Transfer(&opts.SkipDigest, m.SkipDigest) optionutils.Transfer(&opts.SkipVerify, m.SkipVerify) @@ -238,10 +284,17 @@ func (m TargetIndex) ApplyBlobModificationOption(opts *BlobModificationOptions) } func (m TargetIndex) ApplyModificationOption(opts *ModificationOptions) { - m.ApplyTargetOption(&opts.TargetOptions) + m.ApplyTargetOption(&opts.TargetElementOptions) } -func (m TargetIndex) ApplyTargetOption(opts *TargetOptions) { +func (m TargetIndex) ApplyElementModificationOption(opts *ElementModificationOptions) { + if m < 0 { + opts.ModifyElement = generics.Pointer(true) + } + m.ApplyTargetOption(&opts.TargetElementOptions) +} + +func (m TargetIndex) ApplyTargetOption(opts *TargetElementOptions) { opts.TargetElement = m } @@ -259,10 +312,14 @@ func (m TargetIdentityOrAppend) ApplyBlobModificationOption(opts *BlobModificati } func (m TargetIdentityOrAppend) ApplyModificationOption(opts *ModificationOptions) { - m.ApplyTargetOption(&opts.TargetOptions) + m.ApplyTargetOption(&opts.TargetElementOptions) +} + +func (m TargetIdentityOrAppend) ApplyElementModificationOption(opts *ElementModificationOptions) { + m.ApplyTargetOption(&opts.TargetElementOptions) } -func (m TargetIdentityOrAppend) ApplyTargetOption(opts *TargetOptions) { +func (m TargetIdentityOrAppend) ApplyTargetOption(opts *TargetElementOptions) { opts.TargetElement = m } @@ -285,10 +342,14 @@ func (m TargetIdentity) ApplyBlobModificationOption(opts *BlobModificationOption } func (m TargetIdentity) ApplyModificationOption(opts *ModificationOptions) { - m.ApplyTargetOption(&opts.TargetOptions) + m.ApplyTargetOption(&opts.TargetElementOptions) } -func (m TargetIdentity) ApplyTargetOption(opts *TargetOptions) { +func (m TargetIdentity) ApplyElementModificationOption(opts *ElementModificationOptions) { + m.ApplyTargetOption(&opts.TargetElementOptions) +} + +func (m TargetIdentity) ApplyTargetOption(opts *TargetElementOptions) { opts.TargetElement = m } @@ -313,27 +374,39 @@ func (m replaceElement) ApplyBlobModificationOption(opts *BlobModificationOption } func (m replaceElement) ApplyModificationOption(opts *ModificationOptions) { - m.ApplyTargetOption(&opts.TargetOptions) + m.ApplyTargetOption(&opts.TargetElementOptions) } -func (m replaceElement) ApplyTargetOption(opts *TargetOptions) { +func (m replaceElement) ApplyElementModificationOption(opts *ElementModificationOptions) { + m.ApplyTargetOption(&opts.TargetElementOptions) +} + +func (m replaceElement) ApplyTargetOption(opts *TargetElementOptions) { opts.TargetElement = m } //////////////////////////////////////////////////////////////////////////////// -type modifyresource bool +type modifyelement bool -func (m modifyresource) ApplyBlobModificationOption(opts *BlobModificationOptions) { +func (m modifyelement) ApplyBlobModificationOption(opts *BlobModificationOptions) { m.ApplyModificationOption(&opts.ModificationOptions) } -func (m modifyresource) ApplyModificationOption(opts *ModificationOptions) { - opts.ModifyResource = utils.BoolP(m) +func (m modifyelement) ApplyModificationOption(opts *ModificationOptions) { + opts.ModifyElement = utils.BoolP(m) +} + +func (m modifyelement) ApplyElementModificationOption(opts *ElementModificationOptions) { + opts.ModifyElement = utils.BoolP(m) } func ModifyResource(flag ...bool) ModOptionImpl { - return modifyresource(utils.OptionalDefaultedBool(true, flag...)) + return modifyelement(utils.OptionalDefaultedBool(true, flag...)) +} + +func ModifyElement(flag ...bool) ElemModOptionImpl { + return modifyelement(utils.OptionalDefaultedBool(true, flag...)) } //////////////////////////////////////////////////////////////////////////////// diff --git a/api/ocm/internal/repository.go b/api/ocm/internal/repository.go index 4aa4008afc..7ed53168f7 100644 --- a/api/ocm/internal/repository.go +++ b/api/ocm/internal/repository.go @@ -144,10 +144,10 @@ type ComponentVersionAccess interface { // SetSource updates or sets anew source. The options only use the // target options. All other options are ignored. - SetSource(*SourceMeta, compdesc.AccessSpec, ...TargetOption) error + SetSource(*SourceMeta, compdesc.AccessSpec, ...TargetElementOption) error // SetSourceByAccess updates or sets anew source. The options only use the // target options. All other options are ignored. - SetSourceByAccess(art SourceAccess, opts ...TargetOption) error + SetSourceByAccess(art SourceAccess, opts ...TargetElementOption) error GetReference(meta metav1.Identity) (ComponentReference, error) GetReferenceIndex(meta metav1.Identity) int @@ -155,7 +155,10 @@ type ComponentVersionAccess interface { GetReferences() []ComponentReference SelectReferences(sel ...refsel.Selector) ([]ComponentReference, error) - SetReference(ref *ComponentReference, opts ...TargetOption) error + // SetReference adds or updates a reference. By default, it does not allow for + // signature relevant changes. If such operations should be possible + // the option ModifyElement() has to be passed as option. + SetReference(ref *ComponentReference, opts ...ElementModificationOption) error // AddBlob adds a local blob and returns an appropriate local access spec. AddBlob(blob BlobAccess, artType, refName string, global AccessSpec, opts ...BlobUploadOption) (AccessSpec, error) @@ -166,7 +169,7 @@ type ComponentVersionAccess interface { AdjustSourceAccess(meta *SourceMeta, acc compdesc.AccessSpec) error // SetSourceBlob updates or sets anew source. The options only use the // target options. All other options are ignored. - SetSourceBlob(meta *SourceMeta, blob BlobAccess, refname string, global AccessSpec, opts ...TargetOption) error + SetSourceBlob(meta *SourceMeta, blob BlobAccess, refname string, global AccessSpec, opts ...TargetElementOption) error // AccessMethod provides an access method implementation for // an access spec. This might be a repository local implementation diff --git a/api/ocm/modopts.go b/api/ocm/modopts.go index 5c271f0e6b..a980ae0485 100644 --- a/api/ocm/modopts.go +++ b/api/ocm/modopts.go @@ -9,9 +9,12 @@ import ( ) type ( - TargetElement = internal.TargetElement - TargetOption = internal.TargetOption - TargetOptions = internal.TargetOptions + TargetElement = internal.TargetElement + TargetElementOption = internal.TargetElementOption + TargetElementOptions = internal.TargetElementOptions + + ElementModificationOption = internal.ElementModificationOption + ElementModificationOptions = internal.ElementModificationOptions ModificationOption = internal.ModificationOption ModificationOptions = internal.ModificationOptions @@ -60,7 +63,7 @@ func NewModificationOptions(list ...ModificationOption) *ModificationOptions { } func TargetIndex(idx int) internal.TargetOptionImpl { - return internal.TargetIndex(-1) + return internal.TargetIndex(idx) } const AppendElement = internal.TargetIndex(-1) @@ -75,10 +78,15 @@ func TargetIdentityOrCreate(id v1.Identity) internal.TargetOptionImpl { return internal.TargetIdentityOrAppend(id) } +// Deprecated: use ModifyElement. func ModifyResource(flag ...bool) internal.ModOptionImpl { return internal.ModifyResource(flag...) } +func ModifyElement(flag ...bool) internal.ElemModOptionImpl { + return internal.ModifyElement(flag...) +} + func AcceptExistentDigests(flag ...bool) internal.ModOptionImpl { return internal.AcceptExistentDigests(flag...) } diff --git a/api/ocm/tools/signing/handler_test.go b/api/ocm/tools/signing/handler_test.go index 6707f84a8f..4b7984543c 100644 --- a/api/ocm/tools/signing/handler_test.go +++ b/api/ocm/tools/signing/handler_test.go @@ -58,18 +58,28 @@ var _ = Describe("Simple signing handlers", func() { meta := ocm.NewResourceMeta("blob", resourcetypes.PLAIN_TEXT, v1.LocalRelation) meta.Version = "v1" - meta.ExtraIdentity = map[string]string{} MustBeSuccessful(cv.SetResourceBlob(meta, blobaccess.ForString(mime.MIME_TEXT, "test data"), "", nil)) + meta.ExtraIdentity = map[string]string{} meta.Version = "v2" MustBeSuccessful(cv.SetResourceBlob(meta, blobaccess.ForString(mime.MIME_TEXT, "other test data"), "", nil, ocm.TargetIndex(-1))) }) - It("signs without modification", func() { + It("signs without modification (compatibility)", func() { Must(signing.SignComponentVersion(cv, "signature", signing.PrivateKey("signature", priv))) cd := cv.GetDescriptor() + cd.Resources[0].ExtraIdentity = v1.Identity{} + cd.Resources[1].ExtraIdentity = v1.Identity{} Expect(len(cd.Resources)).To(Equal(2)) Expect(len(cd.Resources[0].ExtraIdentity)).To(Equal(0)) Expect(len(cd.Resources[1].ExtraIdentity)).To(Equal(0)) }) + + It("signs defaulted", func() { + Must(signing.SignComponentVersion(cv, "signature", signing.PrivateKey("signature", priv))) + cd := cv.GetDescriptor() + Expect(len(cd.Resources)).To(Equal(2)) + Expect(len(cd.Resources[0].ExtraIdentity)).To(Equal(1)) + Expect(len(cd.Resources[1].ExtraIdentity)).To(Equal(1)) + }) }) }) diff --git a/api/ocm/tools/signing/signing_test.go b/api/ocm/tools/signing/signing_test.go index f374ec0528..a54e91c9bb 100644 --- a/api/ocm/tools/signing/signing_test.go +++ b/api/ocm/tools/signing/signing_test.go @@ -1286,6 +1286,159 @@ applying to version "github.com/mandelsoft/ref2:v1"[github.com/mandelsoft/ref2:v CheckStore(store, common.NewNameVersion(COMPONENTA, VERSION)) }) }) + + Context("handle extra identity", func() { + BeforeEach(func() { + env.OCMCommonTransport(ARCH, accessio.FormatDirectory, func() { + env.ComponentVersion(COMPONENTA, VERSION, func() { + env.Provider(PROVIDER) + env.Resource("test", "v1", resourcetypes.PLAIN_TEXT, metav1.ExternalRelation, func() { + env.BlobStringData(mime.MIME_TEXT, "test data") + }) + env.Resource("test", "v2", resourcetypes.PLAIN_TEXT, metav1.ExternalRelation, func() { + env.BlobStringData(mime.MIME_TEXT, "extended test data") + env.ModificationOptions(ocm.AppendElement) + env.ExtraIdentities() + }) + }) + }) + }) + + It("signs version with non-unique resource names", func() { + session := datacontext.NewSession() + defer session.Close() + + src := Must(ctf.Open(env.OCMContext(), accessobj.ACC_WRITABLE, ARCH, 0, env)) + archcloser := session.AddCloser(src) + + cv := Must(src.LookupComponentVersion(COMPONENTA, VERSION)) + closer := session.AddCloser(cv) + + cd := cv.GetDescriptor() + + Expect(cd.Resources[0].GetIdentity(cv.GetDescriptor().Resources)).To(YAMLEqual(` +name: test +version: v1 +`)) + Expect(cd.Resources[0].ExtraIdentity).To(YAMLEqual(` +version: v1 +`)) + Expect(cd.Resources[1].GetIdentity(cv.GetDescriptor().Resources)).To(YAMLEqual(` +name: test +version: v2 +`)) + Expect(cd.Resources[1].ExtraIdentity).To(YAMLEqual(` +version: v2 +`)) + data := Must(compdesc.Encode(cd, compdesc.DefaultYAMLCodec)) + Expect(string(data)).To(YAMLEqual(` + component: + componentReferences: [] + name: github.com/mandelsoft/test + provider: mandelsoft + repositoryContexts: [] + resources: + - access: + localReference: sha256:916f0027a575074ce72a331777c3478d6513f786a591bd892da1a577bf2335f9 + mediaType: text/plain + type: localBlob + digest: + hashAlgorithm: SHA-256 + normalisationAlgorithm: genericBlobDigest/v1 + value: 916f0027a575074ce72a331777c3478d6513f786a591bd892da1a577bf2335f9 + name: test + relation: external + type: plainText + version: v1 + extraIdentity: + version: v1 + - access: + localReference: sha256:920ce99fb13b43ca0408caee6e61f6335ea5156d79aa98e733e1ed2393e0f649 + mediaType: text/plain + type: localBlob + digest: + hashAlgorithm: SHA-256 + normalisationAlgorithm: genericBlobDigest/v1 + value: 920ce99fb13b43ca0408caee6e61f6335ea5156d79aa98e733e1ed2393e0f649 + name: test + relation: external + type: plainText + version: v2 + extraIdentity: + version: v2 + sources: [] + version: v1 + meta: + schemaVersion: v2 +`)) + + digest := "70c1b7f5e2260a283e24788c81ea7f8f6e9a70a8544dbf62d6f3a27285f6b633" + + pr, buf := common.NewBufferedPrinter() + // key taken from signing attr + dig := Must(SignComponentVersion(cv, SIGNATURE, SignerByAlgo(SIGN_ALGO), Printer(pr))) + Expect(closer.Close()).To(Succeed()) + Expect(archcloser.Close()).To(Succeed()) + Expect(dig.Value).To(StringEqualWithContext(digest)) + + Expect(buf.String()).To(StringEqualTrimmedWithContext(` +applying to version "github.com/mandelsoft/test:v1"[github.com/mandelsoft/test:v1]... + resource 0: "name"="test","version"="v1": digest SHA-256:916f0027a575074ce72a331777c3478d6513f786a591bd892da1a577bf2335f9[genericBlobDigest/v1] + resource 1: "name"="test","version"="v2": digest SHA-256:920ce99fb13b43ca0408caee6e61f6335ea5156d79aa98e733e1ed2393e0f649[genericBlobDigest/v1] +`)) + + src = Must(ctf.Open(env.OCMContext(), accessobj.ACC_READONLY, ARCH, 0, env)) + session.AddCloser(src) + cv = Must(src.LookupComponentVersion(COMPONENTA, VERSION)) + session.AddCloser(cv) + + cd = cv.GetDescriptor().Copy() + Expect(len(cd.Signatures)).To(Equal(1)) + cd.Signatures = nil // for comparison + data = Must(compdesc.Encode(cd, compdesc.DefaultYAMLCodec)) + + Expect(string(data)).To(YAMLEqual(` + component: + componentReferences: [] + name: github.com/mandelsoft/test + provider: mandelsoft + repositoryContexts: [] + resources: + - access: + localReference: sha256:916f0027a575074ce72a331777c3478d6513f786a591bd892da1a577bf2335f9 + mediaType: text/plain + type: localBlob + digest: + hashAlgorithm: SHA-256 + normalisationAlgorithm: genericBlobDigest/v1 + value: 916f0027a575074ce72a331777c3478d6513f786a591bd892da1a577bf2335f9 + name: test + relation: external + type: plainText + version: v1 + extraIdentity: + version: v1 + - access: + localReference: sha256:920ce99fb13b43ca0408caee6e61f6335ea5156d79aa98e733e1ed2393e0f649 + mediaType: text/plain + type: localBlob + digest: + hashAlgorithm: SHA-256 + normalisationAlgorithm: genericBlobDigest/v1 + value: 920ce99fb13b43ca0408caee6e61f6335ea5156d79aa98e733e1ed2393e0f649 + name: test + relation: external + type: plainText + version: v2 + extraIdentity: + version: v2 + sources: [] + version: v1 + meta: + schemaVersion: v2 +`)) + }) + }) }) func CheckStore(store VerifiedStore, ve common.VersionedElement) { diff --git a/api/ocm/tools/transfer/transfer.go b/api/ocm/tools/transfer/transfer.go index 8490138868..ad6121728e 100644 --- a/api/ocm/tools/transfer/transfer.go +++ b/api/ocm/tools/transfer/transfer.go @@ -273,7 +273,7 @@ func copyVersion(printer common.Printer, log logging.Logger, hist common.History err = handler.HandleTransferResource(r, m, hint, t) } else { if err == nil { // old resource found -> keep current access method - t.SetResource(r.Meta(), old.Access, ocm.ModifyResource(), ocm.SkipVerify()) + t.SetResource(r.Meta(), old.Access, ocm.ModifyElement(), ocm.SkipVerify()) } notifyArtifactInfo(printer, log, "resource", i, r.Meta(), hint, "already present") } diff --git a/cmds/ocm/commands/ocmcmds/common/addhdlrs/base.go b/cmds/ocm/commands/ocmcmds/common/addhdlrs/base.go index 41512f23c9..3927286a42 100644 --- a/cmds/ocm/commands/ocmcmds/common/addhdlrs/base.go +++ b/cmds/ocm/commands/ocmcmds/common/addhdlrs/base.go @@ -37,6 +37,10 @@ func (h *ResourceSpecHandlerBase) AddFlags(opts *pflag.FlagSet) { h.options.AddFlags(opts) } -func (h *ResourceSpecHandlerBase) GetTargetOpts() []ocm.TargetOption { - return options.FindOptions[ocm.TargetOption](h.options) +func (h *ResourceSpecHandlerBase) GetTargetOpts() []ocm.TargetElementOption { + return options.FindOptions[ocm.TargetElementOption](h.options) +} + +func (h *ResourceSpecHandlerBase) GetElementModificationOpts() []ocm.ElementModificationOption { + return options.FindOptions[ocm.ElementModificationOption](h.options) } diff --git a/cmds/ocm/commands/ocmcmds/common/addhdlrs/options.go b/cmds/ocm/commands/ocmcmds/common/addhdlrs/options.go index e4e305a268..2297e16847 100644 --- a/cmds/ocm/commands/ocmcmds/common/addhdlrs/options.go +++ b/cmds/ocm/commands/ocmcmds/common/addhdlrs/options.go @@ -1,36 +1,66 @@ package addhdlrs import ( + "github.com/mandelsoft/goutils/generics" "github.com/spf13/pflag" "ocm.software/ocm/api/ocm" ) type Options struct { + // Replace enables to replace existing elements (same raw identity) with a different version instead + // of appending a new element. Replace bool + // PreserveSignature disables the modification of signature relevant information. + PreserveSignature bool } -var _ ocm.ModificationOption = (*Options)(nil) +var ( + _ ocm.ModificationOption = (*Options)(nil) + _ ocm.ElementModificationOption = (*Options)(nil) + _ ocm.BlobModificationOption = (*Options)(nil) + _ ocm.TargetElementOption = (*Options)(nil) +) func (o *Options) AddFlags(fs *pflag.FlagSet) { - f := fs.Lookup("replace") + o.addBoolFlag(fs, &o.Replace, "replace", "R", false, "replace existing elements") + o.addBoolFlag(fs, &o.PreserveSignature, "preserve-signature", "P", false, "preserve existing signatures") +} + +func (o *Options) addBoolFlag(fs *pflag.FlagSet, p *bool, long string, short string, def bool, usage string) { + f := fs.Lookup(long) if f != nil { - if f.Value.Type() == "bool" { - return + if f.Value.Type() != "bool" { + f = nil } } - fs.BoolVarP(&o.Replace, "replace", "R", false, "replace existing elements") + if f == nil { + fs.BoolVarP(p, long, short, def, usage) + } +} + +func (o *Options) applyPreserve(opts *ocm.ElementModificationOptions) { + if !o.PreserveSignature { + opts.ModifyElement = generics.Pointer(true) + } } func (o *Options) ApplyBlobModificationOption(opts *ocm.BlobModificationOptions) { - o.ApplyTargetOption(&opts.TargetOptions) + o.applyPreserve(&opts.ElementModificationOptions) + o.ApplyTargetOption(&opts.TargetElementOptions) } func (o *Options) ApplyModificationOption(opts *ocm.ModificationOptions) { - o.ApplyTargetOption(&opts.TargetOptions) + o.applyPreserve(&opts.ElementModificationOptions) + o.ApplyTargetOption(&opts.TargetElementOptions) } -func (o *Options) ApplyTargetOption(opts *ocm.TargetOptions) { +func (o *Options) ApplyElementModificationOption(opts *ocm.ElementModificationOptions) { + o.applyPreserve(opts) + o.ApplyTargetOption(&opts.TargetElementOptions) +} + +func (o *Options) ApplyTargetOption(opts *ocm.TargetElementOptions) { if !o.Replace { opts.TargetElement = ocm.AppendElement } @@ -40,6 +70,9 @@ func (o *Options) Description() string { return ` The --replace option allows users to specify whether adding an element with the same name and extra identity but different version as an -existing element append (false) or replace (true) the existing element. +existing element, append (false) or replace (true) the existing element. + +The --preserve-signature option prohibits changes of signature +relevant elements. ` } diff --git a/cmds/ocm/commands/ocmcmds/common/addhdlrs/refs/elements.go b/cmds/ocm/commands/ocmcmds/common/addhdlrs/refs/elements.go index 3c529accd7..ddab09974b 100644 --- a/cmds/ocm/commands/ocmcmds/common/addhdlrs/refs/elements.go +++ b/cmds/ocm/commands/ocmcmds/common/addhdlrs/refs/elements.go @@ -66,7 +66,8 @@ func (h *ResourceSpecHandler) Set(v ocm.ComponentVersionAccess, r addhdlrs.Eleme }, ComponentName: spec.ComponentName, } - return v.SetReference(meta, h.GetTargetOpts()...) + + return v.SetReference(meta, h.GetElementModificationOpts()...) } //////////////////////////////////////////////////////////////////////////////// diff --git a/cmds/ocm/commands/ocmcmds/common/addhdlrs/rscs/elements.go b/cmds/ocm/commands/ocmcmds/common/addhdlrs/rscs/elements.go index ef57f97e49..c51fa9d12e 100644 --- a/cmds/ocm/commands/ocmcmds/common/addhdlrs/rscs/elements.go +++ b/cmds/ocm/commands/ocmcmds/common/addhdlrs/rscs/elements.go @@ -63,7 +63,7 @@ func (*ResourceSpecHandler) RequireInputs() bool { return true } -func (ResourceSpecHandler) Decode(data []byte) (addhdlrs.ElementSpec, error) { +func (*ResourceSpecHandler) Decode(data []byte) (addhdlrs.ElementSpec, error) { var desc ResourceSpec err := runtime.DefaultYAMLEncoding.Unmarshal(data, &desc) if err != nil { @@ -72,7 +72,7 @@ func (ResourceSpecHandler) Decode(data []byte) (addhdlrs.ElementSpec, error) { return &desc, nil } -func (h ResourceSpecHandler) Set(v ocm.ComponentVersionAccess, r addhdlrs.Element, acc compdesc.AccessSpec) error { +func (h *ResourceSpecHandler) Set(v ocm.ComponentVersionAccess, r addhdlrs.Element, acc compdesc.AccessSpec) error { spec, ok := r.Spec().(*ResourceSpec) if !ok { return fmt.Errorf("element spec is not a valid resource spec, failed to assert type %T to ResourceSpec", r.Spec()) @@ -105,9 +105,11 @@ func (h ResourceSpecHandler) Set(v ocm.ComponentVersionAccess, r addhdlrs.Elemen if spec.SkipDigestGeneration { opts = append(opts, ocm.SkipDigest()) //nolint:staticcheck // skip digest still used for tests } - if ocm.IsIntermediate(v.Repository().GetSpecification()) { - opts = append(opts, ocm.ModifyResource()) - } + /* + if ocm.IsIntermediate(v.Repository().GetSpecification()) { + opts = append(opts, ocm.ModifyElement()) + } + */ return v.SetResource(meta, acc, opts...) } diff --git a/cmds/ocm/commands/ocmcmds/common/addhdlrs/srcs/elements.go b/cmds/ocm/commands/ocmcmds/common/addhdlrs/srcs/elements.go index 6ab83fca1d..9d8dced1dc 100644 --- a/cmds/ocm/commands/ocmcmds/common/addhdlrs/srcs/elements.go +++ b/cmds/ocm/commands/ocmcmds/common/addhdlrs/srcs/elements.go @@ -29,11 +29,11 @@ func New(opts ...options.Options) *ResourceSpecHandler { return &ResourceSpecHandler{addhdlrs.NewBase(opts...)} } -func (ResourceSpecHandler) Key() string { +func (*ResourceSpecHandler) Key() string { return "source" } -func (ResourceSpecHandler) RequireInputs() bool { +func (*ResourceSpecHandler) RequireInputs() bool { return true } diff --git a/cmds/ocm/commands/ocmcmds/components/hash/cmd.go b/cmds/ocm/commands/ocmcmds/components/hash/cmd.go index 43922b6ff0..b2ef1f9932 100644 --- a/cmds/ocm/commands/ocmcmds/components/hash/cmd.go +++ b/cmds/ocm/commands/ocmcmds/components/hash/cmd.go @@ -13,6 +13,7 @@ import ( "ocm.software/ocm/api/ocm" "ocm.software/ocm/api/ocm/compdesc" common "ocm.software/ocm/api/utils/misc" + "ocm.software/ocm/api/utils/out" "ocm.software/ocm/cmds/ocm/commands/common/options/closureoption" ocmcommon "ocm.software/ocm/cmds/ocm/commands/ocmcmds/common" "ocm.software/ocm/cmds/ocm/commands/ocmcmds/common/handlers/comphdlr" @@ -180,17 +181,26 @@ func (h *action) Close() error { func (h *action) Out() error { if len(h.norms) > 1 { - dir := h.mode.outfile - dir = strings.TrimSuffix(dir, ".ncd") - err := h.ctx.FileSystem().Mkdir(dir, 0o755) - if err != nil { - return fmt.Errorf("cannot create output dir %s", dir) - } - for k, n := range h.norms { - p := filepath.Join(dir, k.String()) - err := h.write(p+".ncd", n) + if h.mode.outfile == "" || h.mode.outfile == "-" { + for _, n := range h.norms { + err := h.write(h.mode.outfile, n) + if err != nil { + return err + } + } + } else { + dir := h.mode.outfile + dir = strings.TrimSuffix(dir, ".ncd") + err := h.ctx.FileSystem().Mkdir(dir, 0o755) if err != nil { - return err + return fmt.Errorf("cannot create output dir %s", dir) + } + for k, n := range h.norms { + p := filepath.Join(dir, k.String()) + err := h.write(p+".ncd", n) + if err != nil { + return err + } } } } else { @@ -202,12 +212,17 @@ func (h *action) Out() error { } func (h *action) write(p, n string) error { - dir := filepath.Dir(p) - err := h.ctx.FileSystem().MkdirAll(dir, 0o755) - if err != nil { - return fmt.Errorf("cannot create dir %s", dir) + if p == "" || p == "-" { + out.Outln(h.ctx, n) + return nil + } else { + dir := filepath.Dir(p) + err := h.ctx.FileSystem().MkdirAll(dir, 0o755) + if err != nil { + return fmt.Errorf("cannot create dir %s", dir) + } + return vfs.WriteFile(h.ctx.FileSystem(), p, []byte(n), 0o644) } - return vfs.WriteFile(h.ctx.FileSystem(), p, []byte(n), 0o644) } ///////// diff --git a/cmds/ocm/commands/ocmcmds/components/hash/cmd_test.go b/cmds/ocm/commands/ocmcmds/components/hash/cmd_test.go index 7783820f74..f79e2c1c05 100644 --- a/cmds/ocm/commands/ocmcmds/components/hash/cmd_test.go +++ b/cmds/ocm/commands/ocmcmds/components/hash/cmd_test.go @@ -2,6 +2,8 @@ package hash_test import ( "bytes" + "crypto/sha256" + "encoding/hex" "fmt" . "github.com/mandelsoft/goutils/testutils" @@ -50,6 +52,48 @@ test.de/x v1 37f7f500d87f4b0a8765649f7c047db382e272b73e042805131df57279991b `)) }) + It("normalize component archive v1", func() { + env.ComponentArchive(ARCH, accessio.FormatDirectory, COMP, VERSION, func() { + env.Provider(PROVIDER) + }) + + buf := bytes.NewBuffer(nil) + Expect(env.CatchOutput(buf).Execute("hash", "components", ARCH, "-O", "-", "-o", "norm")).To(Succeed()) + Expect(buf.String()).To(Equal(`[{"component":[{"componentReferences":[]},{"name":"test.de/x"},{"provider":"mandelsoft"},{"resources":[]},{"version":"v1"}]},{"meta":[{"schemaVersion":"v2"}]}] +`)) + }) + + It("normalize component archive v2", func() { + env.ComponentArchive(ARCH, accessio.FormatDirectory, COMP, VERSION, func() { + env.Provider(PROVIDER) + }) + + buf := bytes.NewBuffer(nil) + Expect(env.CatchOutput(buf).Execute("hash", "components", ARCH, "-N", "jsonNormalisation/v2", "-o", "norm")).To(Succeed()) + Expect(buf.String()).To(StringEqualTrimmedWithContext(`{"component":{"componentReferences":[],"name":"test.de/x","provider":{"name":"mandelsoft"},"resources":[],"sources":[],"version":"v1"}} +`)) + }) + + It("check hash", func() { + env.ComponentArchive(ARCH, accessio.FormatDirectory, COMP, VERSION, func() { + env.Provider(PROVIDER) + }) + + buf := bytes.NewBuffer(nil) + Expect(env.CatchOutput(buf).Execute("hash", "components", ARCH, "-o", "yaml")).To(Succeed()) + Expect(buf.String()).To(StringEqualTrimmedWithContext(` +--- +component: test.de/x +context: [] +hash: 37f7f500d87f4b0a8765649f7c047db382e272b73e042805131df57279991b2b +normalized: '[{"component":[{"componentReferences":[]},{"name":"test.de/x"},{"provider":"mandelsoft"},{"resources":[]},{"version":"v1"}]},{"meta":[{"schemaVersion":"v2"}]}]' +version: v1 +`)) + + h := sha256.Sum256([]byte(`[{"component":[{"componentReferences":[]},{"name":"test.de/x"},{"provider":"mandelsoft"},{"resources":[]},{"version":"v1"}]},{"meta":[{"schemaVersion":"v2"}]}]`)) + Expect(hex.EncodeToString(h[:])).To(Equal("37f7f500d87f4b0a8765649f7c047db382e272b73e042805131df57279991b2b")) + }) + It("hash component archive with resources", func() { env.ComponentArchive(ARCH, accessio.FormatDirectory, COMP, VERSION, func() { env.Provider(PROVIDER) diff --git a/cmds/ocm/commands/ocmcmds/components/hash/options.go b/cmds/ocm/commands/ocmcmds/components/hash/options.go index d3165c732b..99346e88a2 100644 --- a/cmds/ocm/commands/ocmcmds/components/hash/options.go +++ b/cmds/ocm/commands/ocmcmds/components/hash/options.go @@ -33,7 +33,7 @@ func (o *Option) AddFlags(fs *pflag.FlagSet) { fs.BoolVarP(&o.Actual, "actual", "", false, "use actual component descriptor") fs.BoolVarP(&o.Update, "update", "U", false, "update digests in component version") fs.BoolVarP(&o.Verify, "verify", "V", false, "verify digests found in component version") - fs.StringVarP(&o.outfile, "outfile", "O", "norm.ncd", "Output file for normalized component descriptor") + fs.StringVarP(&o.outfile, "outfile", "O", "-", "Output file for normalized component descriptor") } func (o *Option) Complete(cmd *Command) error { diff --git a/docs/reference/ocm_add_componentversions.md b/docs/reference/ocm_add_componentversions.md index 73b8857604..b400223c54 100644 --- a/docs/reference/ocm_add_componentversions.md +++ b/docs/reference/ocm_add_componentversions.md @@ -26,6 +26,7 @@ componentversions, componentversion, cv, components, component, comps, comp, c -h, --help help for componentversions --lookup stringArray repository name or spec for closure lookup fallback -O, --output string output file for dry-run + -P, --preserve-signature preserve existing signatures -R, --replace replace existing elements -S, --scheme string schema version (default "v2") -s, --settings stringArray settings file with variable settings (yaml) @@ -55,7 +56,10 @@ components will be added by value. The --replace option allows users to specify whether adding an element with the same name and extra identity but different version as an -existing element append (false) or replace (true) the existing element. +existing element, append (false) or replace (true) the existing element. + +The --preserve-signature option prohibits changes of signature +relevant elements. The source, resource and reference list can be composed according to the commands diff --git a/docs/reference/ocm_add_references.md b/docs/reference/ocm_add_references.md index 6af5dfca9c..dfc6834cb1 100644 --- a/docs/reference/ocm_add_references.md +++ b/docs/reference/ocm_add_references.md @@ -20,6 +20,7 @@ references, reference, refs -F, --file string target file/directory (default "component-archive") -h, --help help for references -O, --output string output file for dry-run + -P, --preserve-signature preserve existing signatures -R, --replace replace existing elements -s, --settings stringArray settings file with variable settings (yaml) --templater string templater to use (go, none, spiff, subst) (default "subst") @@ -112,7 +113,10 @@ There are several templaters that can be selected by the --templater--replace option allows users to specify whether adding an element with the same name and extra identity but different version as an -existing element append (false) or replace (true) the existing element. +existing element, append (false) or replace (true) the existing element. + +The --preserve-signature option prohibits changes of signature +relevant elements. All yaml/json defined resources can be templated. diff --git a/docs/reference/ocm_add_resources.md b/docs/reference/ocm_add_resources.md index 88985eff7b..99d746c1ad 100644 --- a/docs/reference/ocm_add_resources.md +++ b/docs/reference/ocm_add_resources.md @@ -20,6 +20,7 @@ resources, resource, res, r -F, --file string target file/directory (default "component-archive") -h, --help help for resources -O, --output string output file for dry-run + -P, --preserve-signature preserve existing signatures -R, --replace replace existing elements -s, --settings stringArray settings file with variable settings (yaml) --skip-digest-generation skip digest creation @@ -976,7 +977,10 @@ shown below. The --replace option allows users to specify whether adding an element with the same name and extra identity but different version as an -existing element append (false) or replace (true) the existing element. +existing element, append (false) or replace (true) the existing element. + +The --preserve-signature option prohibits changes of signature +relevant elements. All yaml/json defined resources can be templated. diff --git a/docs/reference/ocm_add_sources.md b/docs/reference/ocm_add_sources.md index 8426c5e600..54f7d17b70 100644 --- a/docs/reference/ocm_add_sources.md +++ b/docs/reference/ocm_add_sources.md @@ -20,6 +20,7 @@ sources, source, src, s -F, --file string target file/directory (default "component-archive") -h, --help help for sources -O, --output string output file for dry-run + -P, --preserve-signature preserve existing signatures -R, --replace replace existing elements -s, --settings stringArray settings file with variable settings (yaml) --templater string templater to use (go, none, spiff, subst) (default "subst") @@ -974,7 +975,10 @@ shown below. The --replace option allows users to specify whether adding an element with the same name and extra identity but different version as an -existing element append (false) or replace (true) the existing element. +existing element, append (false) or replace (true) the existing element. + +The --preserve-signature option prohibits changes of signature +relevant elements. All yaml/json defined resources can be templated. diff --git a/docs/reference/ocm_hash_componentversions.md b/docs/reference/ocm_hash_componentversions.md index a00153f15a..561a9c16c9 100644 --- a/docs/reference/ocm_hash_componentversions.md +++ b/docs/reference/ocm_hash_componentversions.md @@ -22,7 +22,7 @@ componentversions, componentversion, cv, components, component, comps, comp, c --latest restrict component versions to latest --lookup stringArray repository name or spec for closure lookup fallback -N, --normalization string normalization algorithm (default "jsonNormalisation/v1") - -O, --outfile string Output file for normalized component descriptor (default "norm.ncd") + -O, --outfile string Output file for normalized component descriptor (default "-") -o, --output string output mode (JSON, json, norm, wide, yaml) -r, --recursive follow component reference nesting --repo string repository name or spec From a1890c261fc2a5ffb58ee1590662b04a752fa9a0 Mon Sep 17 00:00:00 2001 From: Uwe Krueger Date: Tue, 12 Nov 2024 17:02:10 +0100 Subject: [PATCH 48/58] fix version info for OCI refs (#1078) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #### What this PR does / why we need it PR #1033 introduced a split of the OCI version info from the repository part. The method `Version` checks the inverted condition for an existing version inf. #### Which issue(s) this PR fixes --------- Co-authored-by: Jakob Möller --- api/oci/ociutils/ref.go | 22 +++++- api/oci/ociutils/ref_test.go | 70 +++++++++++++++++++ api/oci/ociutils/suite_test.go | 13 ++++ api/oci/ref.go | 10 --- api/oci/testhelper/manifests.go | 8 +-- .../relativeociref/method_test.go | 2 +- 6 files changed, 109 insertions(+), 16 deletions(-) create mode 100644 api/oci/ociutils/ref_test.go create mode 100644 api/oci/ociutils/suite_test.go diff --git a/api/oci/ociutils/ref.go b/api/oci/ociutils/ref.go index 5d05921777..b419e30a3d 100644 --- a/api/oci/ociutils/ref.go +++ b/api/oci/ociutils/ref.go @@ -31,6 +31,9 @@ func ParseVersion(vers string) (*ArtVersion, error) { Digest: &dig, }, nil } + if vers == "" { + return &ArtVersion{}, nil + } return &ArtVersion{ Tag: &vers, }, nil @@ -50,7 +53,7 @@ type ArtVersion struct { } func (v *ArtVersion) VersionSpec() string { - if v != nil { + if v == nil { return "" } @@ -94,3 +97,20 @@ func (v *ArtVersion) GetTag() string { } return "" } + +func (v *ArtVersion) GetDigest() digest.Digest { + if v != nil && v.Digest != nil { + return *v.Digest + } + return "" +} + +func (r *ArtVersion) Version() string { + if r.Digest != nil { + return "@" + string(*r.Digest) + } + if r.Tag != nil { + return *r.Tag + } + return "latest" +} diff --git a/api/oci/ociutils/ref_test.go b/api/oci/ociutils/ref_test.go new file mode 100644 index 0000000000..1e5075447a --- /dev/null +++ b/api/oci/ociutils/ref_test.go @@ -0,0 +1,70 @@ +package ociutils_test + +import ( + . "github.com/mandelsoft/goutils/testutils" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/opencontainers/go-digest" + "ocm.software/ocm/api/oci/ociutils" + "ocm.software/ocm/api/oci/testhelper" +) + +var _ = Describe("Ref Test Environment", func() { + dig := "sha256:" + testhelper.H_OCIARCHMANIFEST1 + + type expect struct { + yaml string + versionSpec string + isVersion bool + version string + isTag bool + tag string + isDigested bool + digest string + } + + DescribeTable("parsing", func(src string, e expect) { + v := Must(ociutils.ParseVersion(src)) + Expect(v).NotTo(BeNil()) + Expect(v).To(YAMLEqual(e.yaml)) + Expect(v.VersionSpec()).To(Equal(e.versionSpec)) + Expect(v.IsVersion()).To(Equal(e.isVersion)) + Expect(v.Version()).To(Equal(e.version)) + Expect(v.IsTagged()).To(Equal(e.isTag)) + Expect(v.GetTag()).To(Equal(e.tag)) + Expect(v.IsDigested()).To(Equal(e.isDigested)) + Expect(v.GetDigest()).To(Equal(digest.Digest(e.digest))) + }, + Entry("empty", "", expect{ + yaml: "{}", + versionSpec: "latest", + version: "latest", + }), + Entry("tag", "tag", expect{ + yaml: "{\"tag\":\"tag\"}", + versionSpec: "tag", + isVersion: true, + version: "tag", + isTag: true, + tag: "tag", + }), + Entry("digest", "@"+dig, expect{ + yaml: "{\"digest\":\"" + dig + "\"}", + versionSpec: "@" + dig, + isVersion: true, + version: "@" + dig, + isDigested: true, + digest: dig, + }), + Entry("tag@digest", "tag@"+dig, expect{ + yaml: "{\"tag\":\"tag\",\"digest\":\"" + dig + "\"}", + versionSpec: "tag@" + dig, + isVersion: true, + version: "@" + dig, + isTag: true, + tag: "tag", + isDigested: true, + digest: dig, + }), + ) +}) diff --git a/api/oci/ociutils/suite_test.go b/api/oci/ociutils/suite_test.go new file mode 100644 index 0000000000..bf4c1257f7 --- /dev/null +++ b/api/oci/ociutils/suite_test.go @@ -0,0 +1,13 @@ +package ociutils_test + +import ( + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +func TestConfig(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "OCI Utils Test Suite") +} diff --git a/api/oci/ref.go b/api/oci/ref.go index 20186d78c9..0d64f407b0 100644 --- a/api/oci/ref.go +++ b/api/oci/ref.go @@ -272,16 +272,6 @@ type ArtSpec struct { ArtVersion `json:",inline"` } -func (r *ArtSpec) Version() string { - if r.Digest != nil { - return "@" + string(*r.Digest) - } - if r.Tag != nil { - return *r.Tag - } - return "latest" -} - func (r *ArtSpec) IsRegistry() bool { return r.Repository == "" } diff --git a/api/oci/testhelper/manifests.go b/api/oci/testhelper/manifests.go index 44b92c12cd..a6506db65a 100644 --- a/api/oci/testhelper/manifests.go +++ b/api/oci/testhelper/manifests.go @@ -64,8 +64,8 @@ func OCIArtifactResource1(env *builder.Builder, name string, host string, funcs const ( D_OCIMANIFEST1 = "0c4abdb72cf59cb4b77f4aacb4775f9f546ebc3face189b2224a966c8826ca9f" - H_OCIARCHMANIFEST1 = "818fb6a69a5f55e8b3dbc921a61fdd000b9445a745b587ba753a811b02426326" - // H_OCIARCHMANIFEST1 = "b0692bcec00e0a875b6b280f3209d6776f3eca128adcb7e81e82fd32127c0c62". + H_OCIARCHMANIFEST1 = "b0692bcec00e0a875b6b280f3209d6776f3eca128adcb7e81e82fd32127c0c62" + // H_OCIARCHMANIFEST1 = "818fb6a69a5f55e8b3dbc921a61fdd000b9445a745b587ba753a811b02426326". ) var DS_OCIMANIFEST1 = &metav1.DigestSpec{ @@ -124,8 +124,8 @@ func OCIManifest2For(env *builder.Builder, ns, tag string, nested ...func()) (*a const ( D_OCIMANIFEST2 = "c2d2dca275c33c1270dea6168a002d67c0e98780d7a54960758139ae19984bd7" - H_OCIARCHMANIFEST2 = "2aaf6f8857dcbfa04a72fb98dd53f649b46e5d81aa4fb17330df74b0ffc30839" - // H_OCIARCHMANIFEST2 = "cb85cd58b10e36343971691abbfe40200cb645c6e95f0bdabd111a30cf794708". + H_OCIARCHMANIFEST2 = "cb85cd58b10e36343971691abbfe40200cb645c6e95f0bdabd111a30cf794708" + // H_OCIARCHMANIFEST2 = "2aaf6f8857dcbfa04a72fb98dd53f649b46e5d81aa4fb17330df74b0ffc30839". ) func HashManifest2(fmt string) string { diff --git a/api/ocm/extensions/accessmethods/relativeociref/method_test.go b/api/ocm/extensions/accessmethods/relativeociref/method_test.go index 2e589770c0..4634480fc9 100644 --- a/api/ocm/extensions/accessmethods/relativeociref/method_test.go +++ b/api/ocm/extensions/accessmethods/relativeociref/method_test.go @@ -68,7 +68,7 @@ var _ = Describe("Method", func() { return m.Close() }) data := Must(m.Get()) - Expect(len(data)).To(Equal(630)) + Expect(len(data)).To(Equal(628)) Expect(accspeccpi.GetAccessMethodImplementation(m).(blobaccess.DigestSource).Digest().String()).To(Equal("sha256:0c4abdb72cf59cb4b77f4aacb4775f9f546ebc3face189b2224a966c8826ca9f")) Expect(utils.GetOCIArtifactRef(env, res)).To(Equal("ocm/value:v2.0")) }) From 2b02f108ab443a5c42afd672b018f1c1c50941de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakob=20M=C3=B6ller?= Date: Wed, 13 Nov 2024 08:50:54 +0100 Subject: [PATCH 49/58] chore: pin version in tour guide to avoid regeneration (#1083) #### What this PR does / why we need it Pins the tour versions for the guide so that we dont have to regenerate them on every successful release... #### Which issue(s) this PR fixes --- examples/lib/tour/01-getting-started/README.md | 18 ++++++++++-------- .../lib/tour/01-getting-started/example.go | 4 +++- .../lib/tour/07-resource-management/README.md | 16 ++++++++-------- .../lib/tour/07-resource-management/example.go | 5 ++++- 4 files changed, 25 insertions(+), 18 deletions(-) diff --git a/examples/lib/tour/01-getting-started/README.md b/examples/lib/tour/01-getting-started/README.md index 5ec9f956ad..fd23f76256 100644 --- a/examples/lib/tour/01-getting-started/README.md +++ b/examples/lib/tour/01-getting-started/README.md @@ -128,7 +128,9 @@ Now, we have a look at the latest version. It is the last one in the list. ```go - cv, err := c.LookupVersion(versions[len(versions)-1]) + // to retrieve the latest version use + // cv, err := c.LookupVersion(versions[len(versions)-1]) + cv, err := c.LookupVersion("0.17.0") if err != nil { return errors.Wrapf(err, "cannot get latest version") } @@ -168,32 +170,32 @@ differ, because the code always describes the latest version): ```text resources of the latest version: - version: 0.18.0-rc.1 + version: 0.17.0 provider: ocm.software 1: name: ocmcli extra identity: "architecture"="amd64","os"="linux" resource type: executable - access: Local blob sha256:74fdf71c5467cacd1cb09d15d6ad4944d60cc8efa1d704a91c337e54dcd03fbc[] + access: Local blob sha256:03a45dcde67ba565fe806cb5db67da3387f772f7c50af711a0edd6f802570c04[] 2: name: ocmcli extra identity: "architecture"="arm64","os"="linux" resource type: executable - access: Local blob sha256:d0022850cce685d48ca589b3b59913ecbc3572f7f5082bca5c086a4bf2b47c5a[] + access: Local blob sha256:5a622634ae43cf03eac91079389d83266891d1f9b2d8a3884cef6fe639180324[] 3: name: ocmcli extra identity: "architecture"="arm64","os"="darwin" resource type: executable - access: Local blob sha256:1161fc38d0fe78ba3be97783f8676a46afa2baf57c199f937798f791cc4961d3[] + access: Local blob sha256:1482fe5b764e3a86cf96704d7a839ad7e53dcbfd4f5fce5405abffb1962153dd[] 4: name: ocmcli extra identity: "architecture"="amd64","os"="darwin" resource type: executable - access: Local blob sha256:33074ce5cc079ea4fc1dbcc7bd54c27cc93f0e188d9ad8c56ba642c4ba6744af[] + access: Local blob sha256:805f181aff48511eea12c699ed1bbcee8bdc4c5168924e81058aff8715946875[] 5: name: ocmcli extra identity: "architecture"="amd64","os"="windows" resource type: executable - access: Local blob sha256:2fbac39d7772ae1cf209aca5bb5efdbb6b91e83aede9464c52304c3ccebb4f67[] + access: Local blob sha256:20839c68bf0c4cf99444d78ebb93f53358fa9e95fe806f186220bd21d520efa7[] 6: name: ocmcli-image extra identity: resource type: ociImage - access: OCI artifact ghcr.io/open-component-model/ocm/ocm.software/ocmcli/ocmcli-image:0.18.0-rc.1@sha256:3ba3e8c075f7f91e851ec3ce53da2347fe464b3ac33c6d65cf89a459193bb5cb + access: OCI artifact ghcr.io/open-component-model/ocm/ocm.software/ocmcli/ocmcli-image:0.17.0@sha256:16fb52a1cb11c867bd058f4124dea53fbab94229842cc14b52653c2e80b1cede ``` Resources have some metadata, like their identity and a resource type. diff --git a/examples/lib/tour/01-getting-started/example.go b/examples/lib/tour/01-getting-started/example.go index 25b5b34236..c84fe58f06 100644 --- a/examples/lib/tour/01-getting-started/example.go +++ b/examples/lib/tour/01-getting-started/example.go @@ -103,7 +103,9 @@ func GettingStarted() error { // Now, we have a look at the latest version. it is // the last one in the list. // --- begin lookup version --- - cv, err := c.LookupVersion(versions[len(versions)-1]) + // to retrieve the latest version use + // cv, err := c.LookupVersion(versions[len(versions)-1]) + cv, err := c.LookupVersion("0.17.0") if err != nil { return errors.Wrapf(err, "cannot get latest version") } diff --git a/examples/lib/tour/07-resource-management/README.md b/examples/lib/tour/07-resource-management/README.md index a72611efc7..06cda25194 100644 --- a/examples/lib/tour/07-resource-management/README.md +++ b/examples/lib/tour/07-resource-management/README.md @@ -270,28 +270,28 @@ function before finishing. The final output of this example looks like: ```yaml -versions for component ocm.software/ocmcli: 0.1.0-alpha.2, 0.1.0-dev, 0.3.0-dev, 0.3.0-rc.2, 0.3.0-rc.3, 0.3.0, 0.4.0-dev, 0.4.0, 0.4.1, 0.4.2, 0.4.3, 0.5.0, 0.6.0, 0.7.0, 0.8.0, 0.9.0, 0.10.0, 0.11.0, 0.12.0, 0.12.1, 0.13.0, 0.14.0, 0.15.0, 0.16.0, 0.16.1, 0.16.2, 0.17.0-rc.1, 0.17.0, 0.18.0-rc.1 +versions for component ocm.software/ocmcli: 0.1.0-alpha.2, 0.1.0-dev, 0.3.0-dev, 0.3.0-rc.2, 0.3.0-rc.3, 0.3.0, 0.4.0-dev, 0.4.0, 0.4.1, 0.4.2, 0.4.3, 0.5.0, 0.6.0, 0.7.0, 0.8.0, 0.9.0, 0.10.0, 0.11.0, 0.12.0, 0.12.1, 0.13.0, 0.14.0, 0.15.0, 0.16.0, 0.16.1, 0.16.2, 0.17.0-rc.1, 0.17.0, 0.18.0-rc.1, 0.18.0-rc.2 looking up resources of the latest version: - version: 0.18.0-rc.1 + version: 0.17.0 provider: ocm.software *** resources: 1: extra identity: "architecture"="amd64","name"="ocmcli","os"="linux" resource type: executable - access: Local blob sha256:74fdf71c5467cacd1cb09d15d6ad4944d60cc8efa1d704a91c337e54dcd03fbc[] + access: Local blob sha256:03a45dcde67ba565fe806cb5db67da3387f772f7c50af711a0edd6f802570c04[] 2: extra identity: "architecture"="arm64","name"="ocmcli","os"="linux" resource type: executable - access: Local blob sha256:d0022850cce685d48ca589b3b59913ecbc3572f7f5082bca5c086a4bf2b47c5a[] + access: Local blob sha256:5a622634ae43cf03eac91079389d83266891d1f9b2d8a3884cef6fe639180324[] 3: extra identity: "architecture"="arm64","name"="ocmcli","os"="darwin" resource type: executable - access: Local blob sha256:1161fc38d0fe78ba3be97783f8676a46afa2baf57c199f937798f791cc4961d3[] + access: Local blob sha256:1482fe5b764e3a86cf96704d7a839ad7e53dcbfd4f5fce5405abffb1962153dd[] 4: extra identity: "architecture"="amd64","name"="ocmcli","os"="darwin" resource type: executable - access: Local blob sha256:33074ce5cc079ea4fc1dbcc7bd54c27cc93f0e188d9ad8c56ba642c4ba6744af[] + access: Local blob sha256:805f181aff48511eea12c699ed1bbcee8bdc4c5168924e81058aff8715946875[] 5: extra identity: "architecture"="amd64","name"="ocmcli","os"="windows" resource type: executable - access: Local blob sha256:2fbac39d7772ae1cf209aca5bb5efdbb6b91e83aede9464c52304c3ccebb4f67[] + access: Local blob sha256:20839c68bf0c4cf99444d78ebb93f53358fa9e95fe806f186220bd21d520efa7[] 6: extra identity: "name"="ocmcli-image" resource type: ociImage - access: OCI artifact ghcr.io/open-component-model/ocm/ocm.software/ocmcli/ocmcli-image:0.18.0-rc.1@sha256:3ba3e8c075f7f91e851ec3ce53da2347fe464b3ac33c6d65cf89a459193bb5cb + access: OCI artifact ghcr.io/open-component-model/ocm/ocm.software/ocmcli/ocmcli-image:0.17.0@sha256:16fb52a1cb11c867bd058f4124dea53fbab94229842cc14b52653c2e80b1cede ``` diff --git a/examples/lib/tour/07-resource-management/example.go b/examples/lib/tour/07-resource-management/example.go index c5c0f73809..d4b46e909d 100644 --- a/examples/lib/tour/07-resource-management/example.go +++ b/examples/lib/tour/07-resource-management/example.go @@ -5,6 +5,7 @@ import ( "strings" "github.com/mandelsoft/goutils/errors" + "ocm.software/ocm/api/utils/blobaccess/blobaccess" "ocm.software/ocm/api/ocm" @@ -211,7 +212,9 @@ func GatherResources(ctx ocm.Context, factory ResourceFactory) ([]Resource, erro // Now, we have a look at the latest version. it is // the last one in the list. // --- begin lookup version --- - cv, err := c.LookupVersion(versions[len(versions)-1]) + // to retrieve the latest version use + // cv, err := c.LookupVersion(versions[len(versions)-1]) + cv, err := c.LookupVersion("0.17.0") if err != nil { return nil, errors.Wrapf(err, "cannot get latest version") } From d7564d652daecaac9b55a4a8156d3fd93116100a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakob=20M=C3=B6ller?= Date: Wed, 13 Nov 2024 09:16:13 +0100 Subject: [PATCH 50/58] fix: also set release notes from file when file exists (#1081) #### What this PR does / why we need it If the release notes file exists the release notes aren't properly set into the environment which causes the release notes not to be applied to the release correctly #### Which issue(s) this PR fixes --- .github/workflows/release.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 06d7ec63fd..9c6fdb5d27 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -142,13 +142,13 @@ jobs: if [ ! -f "$f" ]; then echo "# Release ${{ env.RELEASE_VERSION }}" > "$f" echo "$RELEASE_NOTES" | tail -n +2 >> "$f" - echo "RELEASE_NOTES_FILE=$f" >> $GITHUB_ENV git add "$f" git commit -m "ReleaseNotes for $RELEASE_VERSION" git push origin ${GITHUB_REF#refs/heads/} else echo "Using release notes file $f from code base" fi + echo "RELEASE_NOTES_FILE=$f" >> $GITHUB_ENV - name: Create and Push Release env: From c55fe220d4791a56d78163ed0c48f7f1deac6748 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakob=20M=C3=B6ller?= Date: Wed, 13 Nov 2024 10:23:48 +0100 Subject: [PATCH 51/58] chore: bump version to 0.19.0-dev (#1084) #### What this PR does / why we need it This is the last manual bump on main since 378bcc0743e9a188f3a66917dd05f0f9ad53eb4d now allows us to automatically create a pull request with this bump #### Which issue(s) this PR fixes --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 498b6fb3d5..7120f981c5 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.18.0-dev +0.19.0-dev From b3873862269e3d19f3e2c8532bbb38ded6a162d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakob=20M=C3=B6ller?= Date: Wed, 13 Nov 2024 14:09:02 +0100 Subject: [PATCH 52/58] fix: correctly set prerelease flag (#1085) #### What this PR does / why we need it Currently all releases (even if candidates) were published as the latest release even though they should be marked as prereleases. This changes this by using the correct goreleaser indicator: ``` # If set to auto, will mark the release as not ready for production # in case there is an indicator for this in the tag e.g. v1.0.0-rc1 # If set to true, will mark the release as not ready for production. # Default: false. ``` #### Which issue(s) this PR fixes --- .github/config/goreleaser.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/config/goreleaser.yaml b/.github/config/goreleaser.yaml index 351813dd65..5f8e6ebec5 100644 --- a/.github/config/goreleaser.yaml +++ b/.github/config/goreleaser.yaml @@ -2,6 +2,9 @@ # However, latest builds (equivalent to nightlies based on the main branch), uses latest.yml version: 2 +release: + prerelease: auto + before: hooks: - go mod tidy From 5447b0c55c00cff22c832b9ada51bd3942d5f56a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakob=20M=C3=B6ller?= Date: Thu, 14 Nov 2024 13:42:43 +0100 Subject: [PATCH 53/58] chore: disable mandatory period comments (#1079) #### What this PR does / why we need it I doubt that we need mandatory dots on every single godoc comment. #### Which issue(s) this PR fixes --- .github/config/golangci.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/config/golangci.yaml b/.github/config/golangci.yaml index a2d6efa90f..8352fbc2a3 100644 --- a/.github/config/golangci.yaml +++ b/.github/config/golangci.yaml @@ -91,6 +91,9 @@ linters: # Disabled because of deprecation - execinquery + # Seriously, who wants every comment to end in a period??? + - godot + linters-settings: gci: sections: From bb7c5f7639d35c2ab3b718571f80445a9a7fc3ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakob=20M=C3=B6ller?= Date: Fri, 15 Nov 2024 21:57:07 +0100 Subject: [PATCH 54/58] chore: make sure that version bumping happens everytime (#1090) #### What this PR does / why we need it This makes sure that we dont only do a patch bump on main after a successful branch cut, but we also do a bump on the release branch (for the next z / patch version) after the minor has been released. Creates a shared workflow that can be called from other workflows. #### Which issue(s) this PR fixes Ensures more automated workflows after the rework from https://github.com/open-component-model/ocm/issues/995 Example run at https://github.com/open-component-model/ocm-cicd-playground/actions/runs/11838213132/job/32986884073 --- .github/workflows/release-branch.yaml | 56 +++----------- .github/workflows/release-bump-version.yaml | 85 +++++++++++++++++++++ .github/workflows/release.yaml | 28 +++---- api/version/generate/release_generate.go | 10 +-- 4 files changed, 112 insertions(+), 67 deletions(-) create mode 100644 .github/workflows/release-bump-version.yaml diff --git a/.github/workflows/release-branch.yaml b/.github/workflows/release-branch.yaml index e19a45abe3..f63d279c5f 100644 --- a/.github/workflows/release-branch.yaml +++ b/.github/workflows/release-branch.yaml @@ -88,49 +88,15 @@ jobs: git checkout -b "$branch" git push origin $branch + # Make sure main contains the next minor after cutoff bump-main-pr: - runs-on: ubuntu-latest - needs: [create-branch, cutoff-preconditions] # wait for the release branch to be created, then create a version bump - steps: - - name: Generate token - id: generate_token - uses: tibdex/github-app-token@v2 - with: - app_id: ${{ secrets.OCMBOT_APP_ID }} - private_key: ${{ secrets.OCMBOT_PRIV_KEY }} - - name: Checkout - uses: actions/checkout@v4 - with: - ref: main - token: ${{ steps.generate_token.outputs.token }} - - name: Version Bump - id: version-bump - run: | - set -e - - echo "determining next version" - version=$(go run ./api/version/generate bump-version) - - echo "bumping main branch to $version" - echo $version > VERSION - - echo "version=$version" >> $GITHUB_OUTPUT - echo "version after bump: $version" - - - name: Create Pull Request - uses: peter-evans/create-pull-request@v7 - with: - token: ${{ steps.generate_token.outputs.token }} - title: "chore: bump VERSION to ${{ steps.version-bump.outputs.version }}" - commit-message: "[github-actions] Bump to ${{ steps.version-bump.outputs.version }} after branch cutoff" - branch: "chore/bump-main/v${{ steps.version-bump.outputs.version }}" - delete-branch: true - sign-commits: true - add-paths: | - VERSION - body: | - Update OCM Version to ${{ steps.version-bump.outputs.version }} - - After the release branch cutoff into ${{ needs.cutoff-preconditions.outputs.branch }}, - this bumps the OCM version so that future development continues on the next minor release. - + uses: ./.github/workflows/release-bump-version.yaml + needs: create-branch + permissions: + contents: write + id-token: write + packages: write + secrets: inherit + with: + bump-type: minor + ref: ${{ github.ref }} \ No newline at end of file diff --git a/.github/workflows/release-bump-version.yaml b/.github/workflows/release-bump-version.yaml new file mode 100644 index 0000000000..1286cda04f --- /dev/null +++ b/.github/workflows/release-bump-version.yaml @@ -0,0 +1,85 @@ +name: Bump VERSION + +on: + workflow_call: + inputs: + ref: + description: "The branch to bump, use the branch the workflow is called on by default" + required: true + default: "" + type: string + bump-type: + description: "The type of bump to perform, one of 'minor' or 'patch'" + required: true + default: "patch" + type: string + +jobs: + create-bump-pr: + name: "Pull Request" + runs-on: ubuntu-latest + permissions: + contents: write + id-token: write + packages: write + env: + REF: ${{ inputs.ref == '' && github.ref || inputs.ref }} + steps: + - name: Validate Input + run: | + set -e + if [[ ${{ inputs.bump-type }} != "minor" && ${{ inputs.bump-type }} != "patch" ]]; then + >&2 echo "Invalid bump type: ${{ inputs.bump-type }}" + exit 1 + fi + - name: Generate token + id: generate_token + uses: tibdex/github-app-token@v2 + with: + app_id: ${{ secrets.OCMBOT_APP_ID }} + private_key: ${{ secrets.OCMBOT_PRIV_KEY }} + - name: Checkout + uses: actions/checkout@v4 + with: + ref: ${{ env.REF }} + sparse-checkout: | + api/version + VERSION + go.mod + - name: Setup Go + uses: actions/setup-go@v5 + with: + go-version-file: '${{ github.workspace }}/go.mod' + cache: 'false' + - name: Version Bump + id: version-bump + run: | + set -e + + echo "determining next version" + version=$(go run ./api/version/generate bump-${{ inputs.bump-type }}) + + echo "bumping main branch to $version" + echo $version > VERSION + + echo "version=$version" >> $GITHUB_OUTPUT + echo "version after bump: $version" + + - name: Create Pull Request + uses: peter-evans/create-pull-request@v7 + with: + token: ${{ steps.generate_token.outputs.token }} + title: "chore: bump VERSION to ${{ steps.version-bump.outputs.version }}" + commit-message: "[github-actions] Bump to ${{ steps.version-bump.outputs.version }}" + branch: "chore/bump-${{ inputs.bump-type }}/v${{ steps.version-bump.outputs.version }}" + delete-branch: true + sign-commits: true + add-paths: | + VERSION + body: | + Update OCM Version to ${{ steps.version-bump.outputs.version }} + + This makes sure that the branch contains the next valid version. + + ${{ inputs.bump-type == 'minor' && 'This is a minor bump, the next release will be a new minor version and signals opening of the development branch for new features.' || '' }} + ${{ inputs.bump-type == 'patch' && 'This is a patch bump, intended to allow creation of the next patch release without manually incrementing the VERSION.' || '' }} \ No newline at end of file diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 9c6fdb5d27..5abef69138 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -189,20 +189,6 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: make plain-push - - name: Bump Version File - if: inputs.release_candidate == false - run: | - set -e - git checkout ${GITHUB_REF#refs/heads/} - v="$(go run ./api/version/generate bump-version)" - echo "$v" > VERSION - # Trigger a bump of any potential files that depend on a new version - make -f hack/Makefile mdref && make -f hack/Makefile go-bindata && make generate - git add --all - git commit -m "Update version to $v" - git push origin ${GITHUB_REF#refs/heads/} - echo "Next branch version is $v" - - name: Publish Release Event if: inputs.release_candidate == false uses: peter-evans/repository-dispatch@v3 @@ -222,3 +208,17 @@ jobs: repository: ${{ github.repository_owner }}/ocm event-type: publish-ocm-cli client-payload: '{"version":"${{ env.RELEASE_VERSION }}","push-to-aur":true,"push-to-chocolatey":true,"push-to-winget":true}' + + # make sure that the branch contains the next valid patch + bump-release-branch-pr: + if: inputs.release_candidate == false + uses: ./.github/workflows/release-bump-version.yaml + needs: release + permissions: + contents: write + id-token: write + packages: write + secrets: inherit + with: + bump-type: patch + ref: ${{ github.ref }} \ No newline at end of file diff --git a/api/version/generate/release_generate.go b/api/version/generate/release_generate.go index d28b4e2122..c5549205d8 100644 --- a/api/version/generate/release_generate.go +++ b/api/version/generate/release_generate.go @@ -94,14 +94,8 @@ func main() { } else { fmt.Printf("%s-%s", v, pre) } - case "bump-version": - var next string - if nonpre.Patch() > 0 { - next = nonpre.IncPatch().String() - } else { - next = nonpre.IncMinor().String() - } - next += "-dev" + case "bump-minor": + next := nonpre.IncMinor().String() + "-dev" fmt.Printf("%s", next) case "bump-patch": next := nonpre.IncPatch().String() + "-dev" From edadfe3417cf61e376183b58ccb6e29bd2a5ff11 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Nov 2024 09:17:32 +0100 Subject: [PATCH 55/58] chore(deps): bump the ci group with 3 updates (#1092) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps the ci group with 3 updates: [DeterminateSystems/nix-installer-action](https://github.com/determinatesystems/nix-installer-action), [dcarbone/install-jq-action](https://github.com/dcarbone/install-jq-action) and [fsfe/reuse-action](https://github.com/fsfe/reuse-action). Updates `DeterminateSystems/nix-installer-action` from 15 to 16
Release notes

Sourced from DeterminateSystems/nix-installer-action's releases.

v16

What's Changed

Full Changelog: https://github.com/DeterminateSystems/nix-installer-action/compare/v15...v16

Commits
  • e50d5f7 Log in to flakehub on existing installs (#129)
  • 25431d2 Update detsys-ts for: `Merge pull request #67 from DeterminateSystems/allow...
  • See full diff in compare view

Updates `dcarbone/install-jq-action` from 2.1.0 to 3.0.1
Release notes

Sourced from dcarbone/install-jq-action's releases.

v3.0.1

What's Changed

Full Changelog: https://github.com/dcarbone/install-jq-action/compare/v3.0.0...v3.0.1

v3.0.0

What's Changed

Full Changelog: https://github.com/dcarbone/install-jq-action/compare/v2...v3.0.0

Commits

Updates `fsfe/reuse-action` from 4 to 5
Commits
  • bb774aa Merge pull request #35 from carmenbianca/bump-v5
  • b8e23e7 Bump to v5
  • 37c9187 Merge pull request #33 from AndyScherzinger/chore/noid/toml-v4-doc-updates
  • b2cec8e docs: Update examples to use v4 and remove dep5 definition
  • f15b48b Merge pull request #34 from bernhardreiter/patch-1
  • 618b8e9 Update README.md for new major version of action @​v3 -> @​v4
  • See full diff in compare view

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/flake_vendorhash.yaml | 2 +- .github/workflows/mend_scan.yaml | 2 +- .github/workflows/reuse_helper_tool.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/flake_vendorhash.yaml b/.github/workflows/flake_vendorhash.yaml index f03948f118..9b296efcd3 100644 --- a/.github/workflows/flake_vendorhash.yaml +++ b/.github/workflows/flake_vendorhash.yaml @@ -25,7 +25,7 @@ jobs: with: token: ${{ steps.generate_token.outputs.token }} - name: Install Nix - uses: DeterminateSystems/nix-installer-action@v15 + uses: DeterminateSystems/nix-installer-action@v16 - name: Update ocm vendor hash run: nix run .#nixpkgs.nix-update -- --flake --version=skip ocm - name: Check diff and create action summary diff --git a/.github/workflows/mend_scan.yaml b/.github/workflows/mend_scan.yaml index 3ec6096c24..fc59902887 100644 --- a/.github/workflows/mend_scan.yaml +++ b/.github/workflows/mend_scan.yaml @@ -60,7 +60,7 @@ jobs: cache_name: mend-scan-go-cache - name: 'Setup jq' - uses: dcarbone/install-jq-action@v2.1.0 + uses: dcarbone/install-jq-action@v3.0.1 with: version: '1.7' diff --git a/.github/workflows/reuse_helper_tool.yaml b/.github/workflows/reuse_helper_tool.yaml index ffd49ec236..ad08e35803 100644 --- a/.github/workflows/reuse_helper_tool.yaml +++ b/.github/workflows/reuse_helper_tool.yaml @@ -8,4 +8,4 @@ jobs: steps: - uses: actions/checkout@v4 - name: REUSE Compliance Check - uses: fsfe/reuse-action@v4 \ No newline at end of file + uses: fsfe/reuse-action@v5 \ No newline at end of file From 74be7054fe6037a7ee6bb8b2a48486e03f26cee9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Nov 2024 08:33:10 +0000 Subject: [PATCH 56/58] chore(deps): bump the go group with 6 updates (#1093) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps the go group with 6 updates: | Package | From | To | | --- | --- | --- | | [github.com/aws/aws-sdk-go-v2/config](https://github.com/aws/aws-sdk-go-v2) | `1.28.3` | `1.28.4` | | [github.com/aws/aws-sdk-go-v2/credentials](https://github.com/aws/aws-sdk-go-v2) | `1.17.44` | `1.17.45` | | [github.com/aws/aws-sdk-go-v2/feature/s3/manager](https://github.com/aws/aws-sdk-go-v2) | `1.17.37` | `1.17.38` | | [github.com/aws/aws-sdk-go-v2/service/s3](https://github.com/aws/aws-sdk-go-v2) | `1.66.3` | `1.67.0` | | [github.com/mikefarah/yq/v4](https://github.com/mikefarah/yq) | `4.44.3` | `4.44.5` | | [helm.sh/helm/v3](https://github.com/helm/helm) | `3.16.2` | `3.16.3` | Updates `github.com/aws/aws-sdk-go-v2/config` from 1.28.3 to 1.28.4
Commits

Updates `github.com/aws/aws-sdk-go-v2/credentials` from 1.17.44 to 1.17.45
Commits

Updates `github.com/aws/aws-sdk-go-v2/feature/s3/manager` from 1.17.37 to 1.17.38
Commits

Updates `github.com/aws/aws-sdk-go-v2/service/s3` from 1.66.3 to 1.67.0
Commits

Updates `github.com/mikefarah/yq/v4` from 4.44.3 to 4.44.5
Release notes

Sourced from github.com/mikefarah/yq/v4's releases.

v4.44.5

  • Format comments with a gray foreground (Thanks @​gabe565)
  • Fixed handling of nulls with sort_by expressions #2164
  • Force no color output when NO_COLOR env presents (Thanks @​narqo)
  • Fixed array subtraction update bug #2159
  • Fixed index out of range error
  • Can traverse straight from parent operator (parent.blah)
  • Bumped dependencies

Note: 4.44.4 was skipped as it had a release pipeline failure

Changelog

Sourced from github.com/mikefarah/yq/v4's changelog.

4.44.5:

  • Fixing release pipeline

4.44.4:

  • Format comments with a gray foreground (Thanks @​gabe565)
  • Fixed handling of nulls with sort_by expressions #2164
  • Force no color output when NO_COLOR env presents (Thanks @​narqo)
  • Fixed array subtraction update bug #2159
  • Fixed index out of range error
  • Can traverse straight from parent operator (parent.blah)
  • Bumped dependencies
Commits
  • bc5b54c Bumping version
  • 129e597 Fixing release pipeline
  • 42db154 Bumping version
  • f06c7c6 Updating release notes
  • 1ae6ac1 Merge branch 'gabe565-add-comment-style'
  • b710fad Regenerating go mod
  • 6a43f17 Merge branch 'add-comment-style' of github.com:gabe565/yq into gabe565-add-co...
  • 1a4b248 Merge branch 'master' into add-comment-style
  • 58cc9db Updated release notes
  • 4af292f Fixed handling of nulls with sort_by expressions #2164
  • Additional commits viewable in compare view

Updates `helm.sh/helm/v3` from 3.16.2 to 3.16.3
Release notes

Sourced from helm.sh/helm/v3's releases.

Helm v3.16.3 is a patch release. Users are encouraged to upgrade for the best experience. Users are encouraged to upgrade for the best experience.

The community keeps growing, and we'd love to see you there!

  • Join the discussion in Kubernetes Slack:
    • for questions and just to hang out
    • for discussing PRs, code, and bugs
  • Hang out at the Public Developer Call: Thursday, 9:30 Pacific via Zoom
  • Test, debug, and contribute charts: ArtifactHub/packages

Installation and Upgrading

Download Helm v3.16.3. The common platform binaries are here:

This release was signed with 672C 657B E06B 4B30 969C 4A57 4614 49C2 5E36 B98E and can be found at @​mattfarina keybase account. Please use the attached signatures for verifying this release using gpg.

The Quickstart Guide will get you going from there. For upgrade instructions or detailed installation notes, check the install guide. You can also use a script to install on any system with bash.

What's Next

  • 3.16.4 is the next patch release and will be on December 11, 2024
  • 3.17.0 is the next feature release and will be on January 15, 2025

Changelog

  • fix: fix label name cfd07493f46efc9debd9cc1b02a0961186df7fdf (wangjingcun)
  • Fix typo in pkg/lint/rules/chartfile_test.go a303060fc60bc713cd0757503b3fcb4636b14f34 (Zach Burgess)
  • Increasing the size of the runner used for releases. ab45e8a861e929e40163a7ad5a8636cb41f381ac (Matt Farina)
  • fix(hooks): correct hooks delete order 19fe320ae87e8d1d4bc1952d9da8ea2fe435aa6e (Suleiman Dibirov)
  • Bump github.com/containerd/containerd from 1.7.12 to 1.7.23 4fcc5c2cadf49d1399adfdbc5ab7222b2dff1d5b (dependabot[bot])
Commits
  • cfd0749 fix: fix label name
  • a303060 Fix typo in pkg/lint/rules/chartfile_test.go
  • ab45e8a Increasing the size of the runner used for releases.
  • 19fe320 fix(hooks): correct hooks delete order
  • 4fcc5c2 Bump github.com/containerd/containerd from 1.7.12 to 1.7.23
  • See full diff in compare view

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 19 +++++++++---------- go.sum | 38 ++++++++++++++++++-------------------- 2 files changed, 27 insertions(+), 30 deletions(-) diff --git a/go.mod b/go.mod index 2e21216e28..34f4a47665 100644 --- a/go.mod +++ b/go.mod @@ -9,11 +9,11 @@ require ( github.com/InfiniteLoopSpace/go_S-MIME v0.0.0-20181221134359-3f58f9a4b2b6 github.com/Masterminds/semver/v3 v3.3.0 github.com/aws/aws-sdk-go-v2 v1.32.4 - github.com/aws/aws-sdk-go-v2/config v1.28.3 - github.com/aws/aws-sdk-go-v2/credentials v1.17.44 - github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.37 + github.com/aws/aws-sdk-go-v2/config v1.28.4 + github.com/aws/aws-sdk-go-v2/credentials v1.17.45 + github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.38 github.com/aws/aws-sdk-go-v2/service/ecr v1.36.5 - github.com/aws/aws-sdk-go-v2/service/s3 v1.66.3 + github.com/aws/aws-sdk-go-v2/service/s3 v1.67.0 github.com/cloudflare/cfssl v1.6.5 github.com/containerd/containerd v1.7.23 github.com/containerd/errdefs v1.0.0 @@ -47,7 +47,7 @@ require ( github.com/mandelsoft/spiff v1.7.0-beta-6 github.com/mandelsoft/vfs v0.4.4 github.com/marstr/guid v1.1.0 - github.com/mikefarah/yq/v4 v4.44.3 + github.com/mikefarah/yq/v4 v4.44.5 github.com/mitchellh/copystructure v1.2.0 github.com/mittwald/go-helm-client v0.12.14 github.com/modern-go/reflect2 v1.0.2 @@ -75,7 +75,7 @@ require ( golang.org/x/text v0.20.0 gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473 gopkg.in/yaml.v3 v3.0.1 - helm.sh/helm/v3 v3.16.2 + helm.sh/helm/v3 v3.16.3 k8s.io/api v0.31.2 k8s.io/apiextensions-apiserver v0.31.2 k8s.io/apimachinery v0.31.2 @@ -139,7 +139,7 @@ require ( github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.4 // indirect github.com/aws/aws-sdk-go-v2/service/sso v1.24.5 // indirect github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.4 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.32.4 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.33.0 // indirect github.com/aws/smithy-go v1.22.0 // indirect github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20241009180534-e718692eec62 // indirect github.com/beorn7/perks v1.0.1 // indirect @@ -179,7 +179,7 @@ require ( github.com/evanphx/json-patch v5.9.0+incompatible // indirect github.com/evanphx/json-patch/v5 v5.9.0 // indirect github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f // indirect - github.com/fatih/color v1.17.0 // indirect + github.com/fatih/color v1.18.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/fvbommel/sortorder v1.1.0 // indirect @@ -200,7 +200,7 @@ require ( github.com/go-openapi/validate v0.24.0 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/goccy/go-json v0.10.3 // indirect - github.com/goccy/go-yaml v1.12.0 // indirect + github.com/goccy/go-yaml v1.13.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang-jwt/jwt/v4 v4.5.1 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect @@ -344,7 +344,6 @@ require ( golang.org/x/term v0.26.0 // indirect golang.org/x/time v0.7.0 // indirect golang.org/x/tools v0.26.0 // indirect - golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect google.golang.org/api v0.200.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20241007155032-5fefd90f89a9 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20241007155032-5fefd90f89a9 // indirect diff --git a/go.sum b/go.sum index 20fd9d62a3..698d9d4d71 100644 --- a/go.sum +++ b/go.sum @@ -169,14 +169,14 @@ github.com/aws/aws-sdk-go-v2 v1.32.4 h1:S13INUiTxgrPueTmrm5DZ+MiAo99zYzHEFh1UNkO github.com/aws/aws-sdk-go-v2 v1.32.4/go.mod h1:2SK5n0a2karNTv5tbP1SjsX0uhttou00v/HpXKM1ZUo= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.6 h1:pT3hpW0cOHRJx8Y0DfJUEQuqPild8jRGmSFmBgvydr0= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.6/go.mod h1:j/I2++U0xX+cr44QjHay4Cvxj6FUbnxrgmqN3H1jTZA= -github.com/aws/aws-sdk-go-v2/config v1.28.3 h1:kL5uAptPcPKaJ4q0sDUjUIdueO18Q7JDzl64GpVwdOM= -github.com/aws/aws-sdk-go-v2/config v1.28.3/go.mod h1:SPEn1KA8YbgQnwiJ/OISU4fz7+F6Fe309Jf0QTsRCl4= -github.com/aws/aws-sdk-go-v2/credentials v1.17.44 h1:qqfs5kulLUHUEXlHEZXLJkgGoF3kkUeFUTVA585cFpU= -github.com/aws/aws-sdk-go-v2/credentials v1.17.44/go.mod h1:0Lm2YJ8etJdEdw23s+q/9wTpOeo2HhNE97XcRa7T8MA= +github.com/aws/aws-sdk-go-v2/config v1.28.4 h1:qgD0MKmkIzZR2DrAjWJcI9UkndjR+8f6sjUQvXh0mb0= +github.com/aws/aws-sdk-go-v2/config v1.28.4/go.mod h1:LgnWnNzHZw4MLplSyEGia0WgJ/kCGD86zGCjvNpehJs= +github.com/aws/aws-sdk-go-v2/credentials v1.17.45 h1:DUgm5lFso57E7150RBgu1JpVQoF8fAPretiDStIuVjg= +github.com/aws/aws-sdk-go-v2/credentials v1.17.45/go.mod h1:dnBpENcPC1ekZrGpSWspX+ZRGzhkvqngT2Qp5xBR1dY= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.19 h1:woXadbf0c7enQ2UGCi8gW/WuKmE0xIzxBF/eD94jMKQ= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.19/go.mod h1:zminj5ucw7w0r65bP6nhyOd3xL6veAUMc3ElGMoLVb4= -github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.37 h1:jHKR76E81sZvz1+x1vYYrHMxphG5LFBJPhSqEr4CLlE= -github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.37/go.mod h1:iMkyPkmoJWQKzSOtaX+8oEJxAuqr7s8laxcqGDSHeII= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.38 h1:xN0PViSptTHJ7QIKyWeWntuTCZoejutTPfhsZIoMDy0= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.38/go.mod h1:orUzUoWBICDyc+hz49KpySb3sa2Tw3c0IaFqrH4c4dg= github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.23 h1:A2w6m6Tmr+BNXjDsr7M90zkWjsu4JXHwrzPg235STs4= github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.23/go.mod h1:35EVp9wyeANdujZruvHiQUAo9E3vbhnIO1mTCAxMlY0= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.23 h1:pgYW9FCabt2M25MoHYCfMrVY2ghiiBKYWUVXfwZs+sU= @@ -199,14 +199,14 @@ github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.4 h1:E5ZAVOmI2apR8A github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.4/go.mod h1:wezzqVUOVVdk+2Z/JzQT4NxAU0NbhRe5W8pIE72jsWI= github.com/aws/aws-sdk-go-v2/service/kms v1.37.0 h1:ovrHGOiNu4S0GSMeexZlsMhBkUb3bCE3iOktFZ7rmBU= github.com/aws/aws-sdk-go-v2/service/kms v1.37.0/go.mod h1:YLqfMkq9GWbICgqT5XMIzT8I2+MxVKodTnNBo3BONgE= -github.com/aws/aws-sdk-go-v2/service/s3 v1.66.3 h1:neNOYJl72bHrz9ikAEED4VqWyND/Po0DnEx64RW6YM4= -github.com/aws/aws-sdk-go-v2/service/s3 v1.66.3/go.mod h1:TMhLIyRIyoGVlaEMAt+ITMbwskSTpcGsCPDq91/ihY0= +github.com/aws/aws-sdk-go-v2/service/s3 v1.67.0 h1:SwaJ0w0MOp0pBTIKTamLVeTKD+iOWyNJRdJ2KCQRg6Q= +github.com/aws/aws-sdk-go-v2/service/s3 v1.67.0/go.mod h1:TMhLIyRIyoGVlaEMAt+ITMbwskSTpcGsCPDq91/ihY0= github.com/aws/aws-sdk-go-v2/service/sso v1.24.5 h1:HJwZwRt2Z2Tdec+m+fPjvdmkq2s9Ra+VR0hjF7V2o40= github.com/aws/aws-sdk-go-v2/service/sso v1.24.5/go.mod h1:wrMCEwjFPms+V86TCQQeOxQF/If4vT44FGIOFiMC2ck= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.4 h1:zcx9LiGWZ6i6pjdcoE9oXAB6mUdeyC36Ia/QEiIvYdg= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.4/go.mod h1:Tp/ly1cTjRLGBBmNccFumbZ8oqpZlpdhFf80SrRh4is= -github.com/aws/aws-sdk-go-v2/service/sts v1.32.4 h1:yDxvkz3/uOKfxnv8YhzOi9m+2OGIxF+on3KOISbK5IU= -github.com/aws/aws-sdk-go-v2/service/sts v1.32.4/go.mod h1:9XEUty5v5UAsMiFOBJrNibZgwCeOma73jgGwwhgffa8= +github.com/aws/aws-sdk-go-v2/service/sts v1.33.0 h1:s7LRgBqhwLaxcocnAniBJp7gaAB+4I4vHzqUqjH18yc= +github.com/aws/aws-sdk-go-v2/service/sts v1.33.0/go.mod h1:9XEUty5v5UAsMiFOBJrNibZgwCeOma73jgGwwhgffa8= github.com/aws/smithy-go v1.22.0 h1:uunKnWlcoL3zO7q+gG2Pk53joueEOsnNB28QdMsmiMM= github.com/aws/smithy-go v1.22.0/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20241009180534-e718692eec62 h1:T5b8GwBFIlqQzAbqTNcyLvzcAvJ09MXrF6zyUlIic8A= @@ -384,8 +384,8 @@ github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0 github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f h1:Wl78ApPPB2Wvf/TIe2xdyJxTlb6obmF18d8QdkxNDu4= github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f/go.mod h1:OSYXu++VVOHnXeitef/D8n/6y4QV8uLHSFXX4NeXMGc= -github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= -github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= +github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= +github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fluxcd/cli-utils v0.36.0-flux.9 h1:RITKdwIAqT3EFKXl7B91mj6usVjxcy7W8PJZlxqUa84= @@ -476,8 +476,8 @@ github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= -github.com/goccy/go-yaml v1.12.0 h1:/1WHjnMsI1dlIBQutrvSMGZRQufVO3asrHfTwfACoPM= -github.com/goccy/go-yaml v1.12.0/go.mod h1:wKnAMd44+9JAAnGQpWVEgBzGt3YuTaQ4uXoHvE4m7WU= +github.com/goccy/go-yaml v1.13.0 h1:0Wtp0FZLd7Sm8gERmR9S6Iczzb3vItJj7NaHmFg8pTs= +github.com/goccy/go-yaml v1.13.0/go.mod h1:IjYwxUiJDoqpx2RmbdjMUceGHZwYLon3sfOGl5Hi9lc= github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.0.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -729,8 +729,8 @@ github.com/miekg/pkcs11 v1.0.2/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WT github.com/miekg/pkcs11 v1.0.3-0.20190429190417-a667d056470f/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= github.com/miekg/pkcs11 v1.1.1 h1:Ugu9pdy6vAYku5DEpVWVFPYnzV+bxB+iRdbuFSu7TvU= github.com/miekg/pkcs11 v1.1.1/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= -github.com/mikefarah/yq/v4 v4.44.3 h1:3zxHntH67maSHr6ynCjM44htw7LZNINmTzYn3tM2t+I= -github.com/mikefarah/yq/v4 v4.44.3/go.mod h1:1pm9sJoyZLDql3OqgklvRCkD0XIIHMZV38jKZgAuxwY= +github.com/mikefarah/yq/v4 v4.44.5 h1:/Xm1dM1BfyDJMg+yIpnl2AgpmLFQg3Lcm/kuyYgHEXE= +github.com/mikefarah/yq/v4 v4.44.5/go.mod h1:rpn3xGVz+2pDuLJTlCvzatCwTmmUeHcm7MbkbtHdvkc= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= @@ -1265,8 +1265,6 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da h1:noIWHXmPHxILtqtCOPIhSt0ABwskkZKjD3bXGnZGpNY= -golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= google.golang.org/api v0.200.0 h1:0ytfNWn101is6e9VBoct2wrGDjOi5vn7jw5KtaQgDrU= google.golang.org/api v0.200.0/go.mod h1:Tc5u9kcbjO7A8SwGlYj4IiVifJU01UqXtEgDMYmBmV8= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= @@ -1338,8 +1336,8 @@ gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU= gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= -helm.sh/helm/v3 v3.16.2 h1:Y9v7ry+ubQmi+cb5zw1Llx8OKHU9Hk9NQ/+P+LGBe2o= -helm.sh/helm/v3 v3.16.2/go.mod h1:SyTXgKBjNqi2NPsHCW5dDAsHqvGIu0kdNYNH9gQaw70= +helm.sh/helm/v3 v3.16.3 h1:kb8bSxMeRJ+knsK/ovvlaVPfdis0X3/ZhYCSFRP+YmY= +helm.sh/helm/v3 v3.16.3/go.mod h1:zeVWGDR4JJgiRbT3AnNsjYaX8OTJlIE9zC+Q7F7iUSU= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= k8s.io/api v0.31.2 h1:3wLBbL5Uom/8Zy98GRPXpJ254nEFpl+hwndmk9RwmL0= From 22711f7cd89e51d907f78e7f060b9ba4ee947b7e Mon Sep 17 00:00:00 2001 From: "ocmbot[bot]" <125909804+ocmbot[bot]@users.noreply.github.com> Date: Mon, 18 Nov 2024 08:47:16 +0000 Subject: [PATCH 57/58] chore: update 'flake.nix' (#1095) Update OCM CLI vendor hash (see: .github/workflows/flake_vendorhash.yaml) Co-authored-by: ocmbot[bot] <125909804+ocmbot[bot]@users.noreply.github.com> --- flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index 1f55c69617..de809a651c 100644 --- a/flake.nix +++ b/flake.nix @@ -35,7 +35,7 @@ state = if (self ? rev) then "clean" else "dirty"; # This vendorHash represents a derivative of all go.mod dependencies and needs to be adjusted with every change - vendorHash = "sha256-a4es06aTjdnSXV9Xseh3WZ6zprWGM/Yk2PNhQwUZnxM="; + vendorHash = "sha256-g7zvy5tMww/sqiYz93/WsR3Wol/Un3EHZp1WbGDpBAI="; src = ./.; From 8b6bd17190ecfd0da8d1a7ef919a9ad34f42c346 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakob=20M=C3=B6ller?= Date: Mon, 18 Nov 2024 16:59:58 +0100 Subject: [PATCH 58/58] chore: directly reference integration tests as job (#1096) #### What this PR does / why we need it This sets up a github workflow that triggers the integration test via workflow call. This allows us to directly have them in our job overview, allowing us to remove the event based trigger with comments. An example run can be seen here: https://github.com/open-component-model/ocm-cicd-playground/actions/runs/11855343659/job/33039365025 The corresponding adjustment PR in the integration test repo can be found here: https://github.com/open-component-model/ocm-integrationtest/pull/31 #### Which issue(s) this PR fixes fix #1097 --- .github/workflows/integration-test.yaml | 27 +++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 .github/workflows/integration-test.yaml diff --git a/.github/workflows/integration-test.yaml b/.github/workflows/integration-test.yaml new file mode 100644 index 0000000000..384748e96c --- /dev/null +++ b/.github/workflows/integration-test.yaml @@ -0,0 +1,27 @@ +name: Integration Tests + +on: + push: + branches: + - main + pull_request_target: + branches: + - main + workflow_dispatch: + +permissions: + # Necessary to write the branch + # TODO: Remove once https://github.com/open-component-model/ocm-integrationtest/blob/main/.github/workflows/integrationtest.yaml#L41 is not needed anymore + contents: write + +jobs: + test: + name: Run tests + uses: open-component-model/ocm-integrationtest/.github/workflows/integrationtest.yaml@main + permissions: + contents: write + id-token: write + packages: write + secrets: inherit + with: + ref: ${{ github.ref }} \ No newline at end of file