package promote import ( "context" "fmt" "path" "strings" "github.com/google/go-containerregistry/pkg/name" "edge-infra.dev/pkg/f8n/warehouse/oci/remote" ) const dockerRegistrySuffix = "-docker.pkg.dev" // repository represents a GAR repository instance type Repository struct { Name string // name of the GAR repository instance, e.g. warehouse ProjectID string // project-id where GAR registry exists, e.g. ret-edge-stage1-foreman Registry string // the OCI compliant registry, e.g. us-east1-docker.pkg.dev Ref string // full GAR repository reference, e.g. us-east1-docker.pkg.dev/ret-edge-stage1-foreman/warehouse } func (repo Repository) String() string { return repo.Ref } // Return the full reference for a given package and its tag func (repo Repository) NewPackageTag(pkgName, tag string) (name.Tag, error) { gcTag, err := name.NewTag(fmt.Sprintf("%s/%s:%s", repo.Ref, pkgName, tag)) if err != nil { return name.Tag{}, err } return gcTag, nil } // Return the full reference for a given package and its tag func (repo Repository) NewPackageDigest(pkgName, version string) (name.Digest, error) { gcDigest, err := name.NewDigest(fmt.Sprintf("%s/%s@%s", repo.Ref, pkgName, version)) if err != nil { return name.Digest{}, err } return gcDigest, nil } // Return the full reference for a given package and its tag func (repo Repository) PackageTagRef(pkgName, version string) string { return fmt.Sprintf("%s/%s:%s", repo.Ref, pkgName, version) } // Return the full reference for a given package and its digest func (repo Repository) PackageDigestRef(pkgName, version string) string { return fmt.Sprintf("%s/%s@%s", repo.Ref, pkgName, version) } // Return the full reference for a given package and its version ("latest" or hash) func (repo Repository) PackageTagRefs(pkgName string, tags []string) []string { packageRefs := []string{} for _, tag := range tags { packageRefs = append(packageRefs, fmt.Sprintf("%s/%s:%s", repo.Ref, pkgName, tag)) } return packageRefs } // Finds the hash for the latest version of the package in the repository func (repo Repository) EnsurePackageDigestExists(pkgName string, digest string) error { pkgRef := repo.PackageDigestRef(pkgName, digest) ref, err := name.ParseReference(pkgRef) if err != nil { return fmt.Errorf("package reference is invalid: %s, reason: %v", pkgRef, err) } _, err = remote.Head(ref) if err != nil { return err } return nil } // Finds the hash for the latest version of the package in the repository func (repo Repository) GetLatestPackageVersion(pkgName string) (string, error) { pkgRef := repo.PackageTagRef(pkgName, Latest) ref, err := name.ParseReference(pkgRef) if err != nil { return "", fmt.Errorf("package reference is invalid: %s, reason: %v", pkgRef, err) } artifact, err := remote.Get(ref) if err != nil { return "", err } hash, err := artifact.Digest() if err != nil { return "", err } return hash.String(), nil } // Lists the packages in the repository func (repo Repository) ListPackages(ctx context.Context) (pkgNames []string, err error) { registry, err := name.NewRegistry(repo.Registry) if err != nil { return nil, err } // get all OCI repositories (packages) in the registry pkgs, err := remote.Catalog(ctx, registry) if err != nil { return nil, err } // filter results for packages in this GAR repository instance for _, pkg := range pkgs { if strings.Contains(pkg, path.Join(repo.ProjectID, repo.Name)) { pkgNames = append(pkgNames, path.Base(pkg)) } } return pkgNames, nil } func newRepository(repoName, projectID, gcpLocation string) Repository { registry := gcpLocation + dockerRegistrySuffix return Repository{ Name: repoName, ProjectID: projectID, Registry: registry, Ref: path.Join(registry, projectID, repoName), } }