From 9e6e36efa3b9254662e9571a23b1724ee73b1479 Mon Sep 17 00:00:00 2001
From: Christoph Witzko <github@christophwitzko.com>
Date: Wed, 1 Feb 2023 22:41:12 +0100
Subject: [PATCH] feat(registry): add single plugin fetching

---
 pkg/plugin/discovery/discovery.go             | 61 ++++++++++++++++---
 .../discovery/resolver/registry/registry.go   | 61 +++++++++++++++++++
 .../discovery/resolver/registryV1/registry.go |  2 +-
 pkg/plugin/discovery/resolver/resolver.go     |  9 +++
 4 files changed, 123 insertions(+), 10 deletions(-)

diff --git a/pkg/plugin/discovery/discovery.go b/pkg/plugin/discovery/discovery.go
index 496debe..0b4e887 100644
--- a/pkg/plugin/discovery/discovery.go
+++ b/pkg/plugin/discovery/discovery.go
@@ -65,26 +65,69 @@ func (d *Discovery) fetchPlugin(pluginInfo *plugin.Info) (string, error) {
 	return downloadPlugin(pluginInfo, downloadInfo, d.config.ShowProgress)
 }
 
-func (d *Discovery) FindPlugin(t, name string) (*plugin.Info, error) {
-	pInfo, err := plugin.GetPluginInfo(t, name)
-	if err != nil {
-		return nil, err
-	}
+func (d *Discovery) IsBatchResolver(resolverName string) bool {
+	_, ok := d.resolvers[resolverName].(resolver.BatchResolver)
+	return ok
+}
 
-	err = setAndEnsurePluginPath(pInfo)
+func (d *Discovery) FindPluginByPluginInfo(pInfo *plugin.Info) error {
+	err := setAndEnsurePluginPath(pInfo)
 	if err != nil {
-		return nil, err
+		return err
 	}
 
 	binPath, err := findPluginLocally(pInfo)
 	if errors.Is(err, ErrPluginNotFound) {
 		binPath, err = d.fetchPlugin(pInfo)
 		if err != nil {
-			return nil, err
+			return err
 		}
 	} else if err != nil {
-		return nil, err
+		return err
 	}
 	pInfo.BinPath = binPath
+	return nil
+}
+
+func (d *Discovery) FindPlugin(t, name string) (*plugin.Info, error) {
+	pInfo, err := plugin.GetPluginInfo(t, name)
+	if err != nil {
+		return nil, err
+	}
+	err = d.FindPluginByPluginInfo(pInfo)
+	if err != nil {
+		return nil, err
+	}
 	return pInfo, nil
 }
+
+func (d *Discovery) FindPluginsWithBatchResolver(resolverName string, pInfos []*plugin.Info) error {
+	if !d.IsBatchResolver(resolverName) {
+		return fmt.Errorf("resolver %s does not support batch resolving", resolverName)
+	}
+	missingPlugins := make([]*plugin.Info, 0)
+	for _, pInfo := range pInfos {
+		err := setAndEnsurePluginPath(pInfo)
+		if err != nil {
+			return err
+		}
+
+		binPath, err := findPluginLocally(pInfo)
+		if errors.Is(err, ErrPluginNotFound) {
+			missingPlugins = append(missingPlugins, pInfo)
+			continue
+		} else if err != nil {
+			return err
+		}
+		pInfo.BinPath = binPath
+	}
+
+	batchResolver := d.resolvers[resolverName].(resolver.BatchResolver)
+	batchDownloadInfo, err := batchResolver.BatchResolvePlugins(missingPlugins)
+	if err != nil {
+		return err
+	}
+	// TODO
+	_ = batchDownloadInfo
+	return nil
+}
diff --git a/pkg/plugin/discovery/resolver/registry/registry.go b/pkg/plugin/discovery/resolver/registry/registry.go
index 6e28c08..28d3d17 100644
--- a/pkg/plugin/discovery/resolver/registry/registry.go
+++ b/pkg/plugin/discovery/resolver/registry/registry.go
@@ -1,8 +1,12 @@
 package registry
 
 import (
+	"context"
 	"fmt"
+	"runtime"
+	"sort"
 
+	"github.com/Masterminds/semver/v3"
 	"github.com/go-semantic-release/plugin-registry/pkg/client"
 	"github.com/go-semantic-release/semantic-release/v2/pkg/plugin"
 	"github.com/go-semantic-release/semantic-release/v2/pkg/plugin/discovery/resolver"
@@ -21,6 +25,63 @@ func NewResolver() *Resolver {
 }
 
 func (r *Resolver) ResolvePlugin(pluginInfo *plugin.Info) (*resolver.PluginDownloadInfo, error) {
+	getPluginRes, err := r.client.GetPlugin(context.Background(), pluginInfo.ShortNormalizedName)
+	if err != nil {
+		return nil, err
+	}
+
+	osArch := fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH)
+	if pluginInfo.Constraint == nil {
+		foundAsset := getPluginRes.LatestRelease.Assets[osArch]
+		if foundAsset == nil {
+			return nil, fmt.Errorf("a matching plugin was not found for %s/%s", runtime.GOOS, runtime.GOARCH)
+		}
+		return &resolver.PluginDownloadInfo{
+			URL:      foundAsset.URL,
+			Checksum: foundAsset.Checksum,
+			FileName: foundAsset.FileName,
+			Version:  getPluginRes.LatestRelease.Version,
+		}, nil
+	}
+
+	foundVersion := ""
+	versions := make(semver.Collection, 0)
+	for _, v := range getPluginRes.Versions {
+		pv, sErr := semver.NewVersion(v)
+		if sErr != nil {
+			return nil, sErr
+		}
+		versions = append(versions, pv)
+	}
+	sort.Sort(sort.Reverse(versions))
+	for _, v := range versions {
+		if pluginInfo.Constraint.Check(v) {
+			foundVersion = v.String()
+			break
+		}
+	}
+	if foundVersion == "" {
+		return nil, fmt.Errorf("no matching version was found")
+	}
+
+	pluginRelease, err := r.client.GetPluginRelease(context.Background(), pluginInfo.ShortNormalizedName, foundVersion)
+	if err != nil {
+		return nil, err
+	}
+	foundAsset := pluginRelease.Assets[osArch]
+	if foundAsset == nil {
+		return nil, fmt.Errorf("a matching plugin was not found for %s/%s", runtime.GOOS, runtime.GOARCH)
+	}
+
+	return &resolver.PluginDownloadInfo{
+		URL:      foundAsset.URL,
+		Checksum: foundAsset.Checksum,
+		FileName: foundAsset.FileName,
+		Version:  getPluginRes.LatestRelease.Version,
+	}, nil
+}
+
+func (r *Resolver) BatchResolvePlugins(pluginInfos []*plugin.Info) (*resolver.BatchPluginDownloadInfo, error) {
 	return nil, fmt.Errorf("not implemented")
 }
 
diff --git a/pkg/plugin/discovery/resolver/registryV1/registry.go b/pkg/plugin/discovery/resolver/registryV1/registry.go
index 470ae66..d30e89d 100644
--- a/pkg/plugin/discovery/resolver/registryV1/registry.go
+++ b/pkg/plugin/discovery/resolver/registryV1/registry.go
@@ -18,7 +18,7 @@ func NewResolver() *Resolver {
 }
 
 func (r *Resolver) ResolvePlugin(pluginInfo *plugin.Info) (*resolver.PluginDownloadInfo, error) {
-	pluginAPIRes, err := getPluginInfo(pluginInfo.NormalizedName)
+	pluginAPIRes, err := getPluginInfo(pluginInfo.ShortNormalizedName)
 	if err != nil {
 		return nil, err
 	}
diff --git a/pkg/plugin/discovery/resolver/resolver.go b/pkg/plugin/discovery/resolver/resolver.go
index 947f8f1..5a1b93b 100644
--- a/pkg/plugin/discovery/resolver/resolver.go
+++ b/pkg/plugin/discovery/resolver/resolver.go
@@ -9,7 +9,16 @@ type PluginDownloadInfo struct {
 	Version  string
 }
 
+type BatchPluginDownloadInfo struct {
+	URL      string
+	Checksum string
+}
+
 type Resolver interface {
 	ResolvePlugin(*plugin.Info) (*PluginDownloadInfo, error)
 	Names() []string
 }
+
+type BatchResolver interface {
+	BatchResolvePlugins([]*plugin.Info) (*BatchPluginDownloadInfo, error)
+}
-- 
GitLab