Skip to content

Commit

Permalink
Add bufremoteplugin support for Nuget registries (#3150)
Browse files Browse the repository at this point in the history
  • Loading branch information
pkwarren authored Jul 11, 2024
1 parent 51b3098 commit d8f68e4
Show file tree
Hide file tree
Showing 8 changed files with 422 additions and 23 deletions.
116 changes: 93 additions & 23 deletions private/bufpkg/bufremoteplugin/bufremoteplugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"github.com/bufbuild/buf/private/bufpkg/bufremoteplugin/bufremotepluginconfig"
"github.com/bufbuild/buf/private/bufpkg/bufremoteplugin/bufremotepluginref"
registryv1alpha1 "github.com/bufbuild/buf/private/gen/proto/go/buf/alpha/registry/v1alpha1"
"github.com/bufbuild/buf/private/pkg/slicesext"
)

// Plugin represents a plugin defined by a buf.plugin.yaml.
Expand Down Expand Up @@ -67,19 +68,22 @@ func NewPlugin(
// PluginToProtoPluginRegistryType determines the appropriate registryv1alpha1.PluginRegistryType for the plugin.
func PluginToProtoPluginRegistryType(plugin Plugin) registryv1alpha1.PluginRegistryType {
registryType := registryv1alpha1.PluginRegistryType_PLUGIN_REGISTRY_TYPE_UNSPECIFIED
if plugin.Registry() != nil {
if plugin.Registry().Go != nil {
if registry := plugin.Registry(); registry != nil {
switch {
case registry.Go != nil:
registryType = registryv1alpha1.PluginRegistryType_PLUGIN_REGISTRY_TYPE_GO
} else if plugin.Registry().NPM != nil {
case registry.NPM != nil:
registryType = registryv1alpha1.PluginRegistryType_PLUGIN_REGISTRY_TYPE_NPM
} else if plugin.Registry().Maven != nil {
case registry.Maven != nil:
registryType = registryv1alpha1.PluginRegistryType_PLUGIN_REGISTRY_TYPE_MAVEN
} else if plugin.Registry().Swift != nil {
case registry.Swift != nil:
registryType = registryv1alpha1.PluginRegistryType_PLUGIN_REGISTRY_TYPE_SWIFT
} else if plugin.Registry().Python != nil {
case registry.Python != nil:
registryType = registryv1alpha1.PluginRegistryType_PLUGIN_REGISTRY_TYPE_PYTHON
} else if plugin.Registry().Cargo != nil {
case registry.Cargo != nil:
registryType = registryv1alpha1.PluginRegistryType_PLUGIN_REGISTRY_TYPE_CARGO
case registry.Nuget != nil:
registryType = registryv1alpha1.PluginRegistryType_PLUGIN_REGISTRY_TYPE_NUGET
}
}
return registryType
Expand Down Expand Up @@ -123,7 +127,8 @@ func PluginRegistryToProtoRegistryConfig(pluginRegistry *bufremotepluginconfig.R
registryConfig := &registryv1alpha1.RegistryConfig{
Options: bufremotepluginconfig.PluginOptionsToOptionsSlice(pluginRegistry.Options),
}
if pluginRegistry.Go != nil {
switch {
case pluginRegistry.Go != nil:
goConfig := &registryv1alpha1.GoConfig{}
goConfig.MinimumVersion = pluginRegistry.Go.MinVersion
if pluginRegistry.Go.Deps != nil {
Expand All @@ -133,7 +138,7 @@ func PluginRegistryToProtoRegistryConfig(pluginRegistry *bufremotepluginconfig.R
}
}
registryConfig.RegistryConfig = &registryv1alpha1.RegistryConfig_GoConfig{GoConfig: goConfig}
} else if pluginRegistry.NPM != nil {
case pluginRegistry.NPM != nil:
importStyle, err := npmImportStyleToNPMProtoImportStyle(pluginRegistry.NPM.ImportStyle)
if err != nil {
return nil, err
Expand All @@ -149,7 +154,7 @@ func PluginRegistryToProtoRegistryConfig(pluginRegistry *bufremotepluginconfig.R
}
}
registryConfig.RegistryConfig = &registryv1alpha1.RegistryConfig_NpmConfig{NpmConfig: npmConfig}
} else if pluginRegistry.Maven != nil {
case pluginRegistry.Maven != nil:
mavenConfig := &registryv1alpha1.MavenConfig{}
var javaCompilerConfig *registryv1alpha1.MavenConfig_CompilerJavaConfig
if compiler := pluginRegistry.Maven.Compiler.Java; compiler != (bufremotepluginconfig.MavenCompilerJavaConfig{}) {
Expand Down Expand Up @@ -188,21 +193,27 @@ func PluginRegistryToProtoRegistryConfig(pluginRegistry *bufremotepluginconfig.R
}
}
registryConfig.RegistryConfig = &registryv1alpha1.RegistryConfig_MavenConfig{MavenConfig: mavenConfig}
} else if pluginRegistry.Swift != nil {
case pluginRegistry.Swift != nil:
swiftConfig := SwiftRegistryConfigToProtoSwiftConfig(pluginRegistry.Swift)
registryConfig.RegistryConfig = &registryv1alpha1.RegistryConfig_SwiftConfig{SwiftConfig: swiftConfig}
} else if pluginRegistry.Python != nil {
case pluginRegistry.Python != nil:
pythonConfig, err := PythonRegistryConfigToProtoPythonConfig(pluginRegistry.Python)
if err != nil {
return nil, err
}
registryConfig.RegistryConfig = &registryv1alpha1.RegistryConfig_PythonConfig{PythonConfig: pythonConfig}
} else if pluginRegistry.Cargo != nil {
case pluginRegistry.Cargo != nil:
cargoConfig, err := CargoRegistryConfigToProtoCargoConfig(pluginRegistry.Cargo)
if err != nil {
return nil, err
}
registryConfig.RegistryConfig = &registryv1alpha1.RegistryConfig_CargoConfig{CargoConfig: cargoConfig}
case pluginRegistry.Nuget != nil:
nugetConfig, err := NugetRegistryConfigToProtoNugetConfig(pluginRegistry.Nuget)
if err != nil {
return nil, err
}
registryConfig.RegistryConfig = &registryv1alpha1.RegistryConfig_NugetConfig{NugetConfig: nugetConfig}
}
return registryConfig, nil
}
Expand All @@ -226,7 +237,8 @@ func ProtoRegistryConfigToPluginRegistry(config *registryv1alpha1.RegistryConfig
registryConfig := &bufremotepluginconfig.RegistryConfig{
Options: bufremotepluginconfig.OptionsSliceToPluginOptions(config.Options),
}
if config.GetGoConfig() != nil {
switch {
case config.GetGoConfig() != nil:
goConfig := &bufremotepluginconfig.GoRegistryConfig{}
goConfig.MinVersion = config.GetGoConfig().GetMinimumVersion()
runtimeLibraries := config.GetGoConfig().GetRuntimeLibraries()
Expand All @@ -237,7 +249,7 @@ func ProtoRegistryConfigToPluginRegistry(config *registryv1alpha1.RegistryConfig
}
}
registryConfig.Go = goConfig
} else if config.GetNpmConfig() != nil {
case config.GetNpmConfig() != nil:
importStyle, err := npmProtoImportStyleToNPMImportStyle(config.GetNpmConfig().GetImportStyle())
if err != nil {
return nil, err
Expand All @@ -254,30 +266,36 @@ func ProtoRegistryConfigToPluginRegistry(config *registryv1alpha1.RegistryConfig
}
}
registryConfig.NPM = npmConfig
} else if protoMavenConfig := config.GetMavenConfig(); protoMavenConfig != nil {
mavenConfig, err := ProtoMavenConfigToMavenRegistryConfig(protoMavenConfig)
case config.GetMavenConfig() != nil:
mavenConfig, err := ProtoMavenConfigToMavenRegistryConfig(config.GetMavenConfig())
if err != nil {
return nil, err
}
registryConfig.Maven = mavenConfig
} else if protoSwiftConfig := config.GetSwiftConfig(); protoSwiftConfig != nil {
swiftConfig, err := ProtoSwiftConfigToSwiftRegistryConfig(protoSwiftConfig)
case config.GetSwiftConfig() != nil:
swiftConfig, err := ProtoSwiftConfigToSwiftRegistryConfig(config.GetSwiftConfig())
if err != nil {
return nil, err
}
registryConfig.Swift = swiftConfig
} else if protoPythonConfig := config.GetPythonConfig(); protoPythonConfig != nil {
pythonConfig, err := ProtoPythonConfigToPythonRegistryConfig(protoPythonConfig)
case config.GetPythonConfig() != nil:
pythonConfig, err := ProtoPythonConfigToPythonRegistryConfig(config.GetPythonConfig())
if err != nil {
return nil, err
}
registryConfig.Python = pythonConfig
} else if protoCargoConfig := config.GetCargoConfig(); protoCargoConfig != nil {
cargoConfig, err := ProtoCargoConfigToCargoRegistryConfig(protoCargoConfig)
case config.GetCargoConfig() != nil:
cargoConfig, err := ProtoCargoConfigToCargoRegistryConfig(config.GetCargoConfig())
if err != nil {
return nil, err
}
registryConfig.Cargo = cargoConfig
case config.GetNugetConfig() != nil:
nugetConfig, err := ProtoNugetConfigToNugetRegistryConfig(config.GetNugetConfig())
if err != nil {
return nil, err
}
registryConfig.Nuget = nugetConfig
}
return registryConfig, nil
}
Expand All @@ -298,6 +316,32 @@ func ProtoCargoConfigToCargoRegistryConfig(protoCargoConfig *registryv1alpha1.Ca
return cargoConfig, nil
}

// ProtoNugetConfigToNugetRegistryConfig converts protoConfig to an equivalent [*bufremotepluginconfig.NugetRegistryConfig].
func ProtoNugetConfigToNugetRegistryConfig(protoConfig *registryv1alpha1.NugetConfig) (*bufremotepluginconfig.NugetRegistryConfig, error) {
targetFrameworks, err := slicesext.MapError(protoConfig.TargetFrameworks, dotnetTargetFrameworkToString)
if err != nil {
return nil, err
}
config := &bufremotepluginconfig.NugetRegistryConfig{
TargetFrameworks: targetFrameworks,
}
for _, dependency := range protoConfig.RuntimeLibraries {
var depTargetFrameworks []string
if len(dependency.TargetFrameworks) > 0 {
depTargetFrameworks, err = slicesext.MapError(dependency.TargetFrameworks, dotnetTargetFrameworkToString)
if err != nil {
return nil, err
}
}
config.Deps = append(config.Deps, bufremotepluginconfig.NugetDependencyConfig{
Name: dependency.Name,
Version: dependency.Version,
TargetFrameworks: depTargetFrameworks,
})
}
return config, err
}

// CargoRegistryConfigToProtoCargoConfig converts cargoConfig to an equivalent [*registryv1alpha1.CargoConfig].
func CargoRegistryConfigToProtoCargoConfig(cargoConfig *bufremotepluginconfig.CargoRegistryConfig) (*registryv1alpha1.CargoConfig, error) {
protoCargoConfig := &registryv1alpha1.CargoConfig{
Expand All @@ -314,6 +358,32 @@ func CargoRegistryConfigToProtoCargoConfig(cargoConfig *bufremotepluginconfig.Ca
return protoCargoConfig, nil
}

// NugetRegistryConfigToProtoNugetConfig converts nugetConfig to an equivalent [*registryv1alpha1.NugetConfig].
func NugetRegistryConfigToProtoNugetConfig(nugetConfig *bufremotepluginconfig.NugetRegistryConfig) (*registryv1alpha1.NugetConfig, error) {
targetFrameworks, err := slicesext.MapError(nugetConfig.TargetFrameworks, dotnetTargetFrameworkFromString)
if err != nil {
return nil, err
}
protoNugetConfig := &registryv1alpha1.NugetConfig{
TargetFrameworks: targetFrameworks,
}
for _, dependency := range nugetConfig.Deps {
var depTargetFrameworks []registryv1alpha1.DotnetTargetFramework
if len(dependency.TargetFrameworks) > 0 {
depTargetFrameworks, err = slicesext.MapError(dependency.TargetFrameworks, dotnetTargetFrameworkFromString)
if err != nil {
return nil, err
}
}
protoNugetConfig.RuntimeLibraries = append(protoNugetConfig.RuntimeLibraries, &registryv1alpha1.NugetConfig_RuntimeLibrary{
Name: dependency.Name,
Version: dependency.Version,
TargetFrameworks: depTargetFrameworks,
})
}
return protoNugetConfig, nil
}

// ProtoPythonConfigToPythonRegistryConfig converts protoPythonConfig to an equivalent [*bufremotepluginconfig.PythonRegistryConfig].
func ProtoPythonConfigToPythonRegistryConfig(protoPythonConfig *registryv1alpha1.PythonConfig) (*bufremotepluginconfig.PythonRegistryConfig, error) {
pythonConfig := &bufremotepluginconfig.PythonRegistryConfig{
Expand Down
19 changes: 19 additions & 0 deletions private/bufpkg/bufremoteplugin/bufremoteplugin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ func TestPluginToProtoPluginRegistryType(t *testing.T) {
assertPluginToPluginRegistryType(t, &bufremotepluginconfig.RegistryConfig{NPM: &bufremotepluginconfig.NPMRegistryConfig{}}, registryv1alpha1.PluginRegistryType_PLUGIN_REGISTRY_TYPE_NPM)
assertPluginToPluginRegistryType(t, &bufremotepluginconfig.RegistryConfig{Maven: &bufremotepluginconfig.MavenRegistryConfig{}}, registryv1alpha1.PluginRegistryType_PLUGIN_REGISTRY_TYPE_MAVEN)
assertPluginToPluginRegistryType(t, &bufremotepluginconfig.RegistryConfig{Swift: &bufremotepluginconfig.SwiftRegistryConfig{}}, registryv1alpha1.PluginRegistryType_PLUGIN_REGISTRY_TYPE_SWIFT)
assertPluginToPluginRegistryType(t, &bufremotepluginconfig.RegistryConfig{Python: &bufremotepluginconfig.PythonRegistryConfig{}}, registryv1alpha1.PluginRegistryType_PLUGIN_REGISTRY_TYPE_PYTHON)
assertPluginToPluginRegistryType(t, &bufremotepluginconfig.RegistryConfig{Cargo: &bufremotepluginconfig.CargoRegistryConfig{}}, registryv1alpha1.PluginRegistryType_PLUGIN_REGISTRY_TYPE_CARGO)
assertPluginToPluginRegistryType(t, &bufremotepluginconfig.RegistryConfig{Nuget: &bufremotepluginconfig.NugetRegistryConfig{}}, registryv1alpha1.PluginRegistryType_PLUGIN_REGISTRY_TYPE_NUGET)
}

func assertPluginToPluginRegistryType(t testing.TB, config *bufremotepluginconfig.RegistryConfig, registryType registryv1alpha1.PluginRegistryType) {
Expand Down Expand Up @@ -187,6 +190,22 @@ func TestPluginRegistryRoundTrip(t *testing.T) {
},
},
})
assertPluginRegistryRoundTrip(t, &bufremotepluginconfig.RegistryConfig{
Nuget: &bufremotepluginconfig.NugetRegistryConfig{
TargetFrameworks: []string{"netstandard2.0", "netstandard2.1"},
Deps: []bufremotepluginconfig.NugetDependencyConfig{
{
Name: "Grpc.Core.Api",
Version: "1.2.3",
},
{
Name: "Grpc.Other.Api",
Version: "4.5.6",
TargetFrameworks: []string{"netstandard2.1"},
},
},
},
})
}

func assertPluginRegistryRoundTrip(t testing.TB, config *bufremotepluginconfig.RegistryConfig) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ type RegistryConfig struct {
Swift *SwiftRegistryConfig
Python *PythonRegistryConfig
Cargo *CargoRegistryConfig
Nuget *NugetRegistryConfig
// Options is the set of options passed into the plugin for the
// remote registry.
//
Expand Down Expand Up @@ -267,6 +268,27 @@ type CargoRegistryConfig struct {
Deps []CargoRegistryDependency
}

// NugetDependencyConfig defines a runtime dependency for a generated nuget package.
type NugetDependencyConfig struct {
// Name specifies the name of the dependency.
Name string
// Version specifies the version of the dependency.
// This can be an exact version or a version range.
Version string
// TargetFrameworks specify the optional target frameworks for the dependency.
// If specified, the dependency will be added only for the specified framework.
TargetFrameworks []string
}

// NugetRegistryConfig defines the configuration for a nuget registry.
type NugetRegistryConfig struct {
// TargetFrameworks specify the frameworks to build.
// At least one target framework must be specified.
TargetFrameworks []string
// Deps specifies the dependencies for the generated SDK.
Deps []NugetDependencyConfig
}

// ConfigOption is an optional option used when loading a Config.
type ConfigOption func(*configOptions)

Expand Down Expand Up @@ -398,6 +420,7 @@ type ExternalRegistryConfig struct {
Swift *ExternalSwiftRegistryConfig `json:"swift,omitempty" yaml:"swift,omitempty"`
Python *ExternalPythonRegistryConfig `json:"python,omitempty" yaml:"python,omitempty"`
Cargo *ExternalCargoRegistryConfig `json:"cargo,omitempty" yaml:"cargo,omitempty"`
Nuget *ExternalNugetRegistryConfig `json:"nuget,omitempty" yaml:"nuget,omitempty"`
Opts []string `json:"opts,omitempty" yaml:"opts,omitempty"`
}

Expand Down Expand Up @@ -539,6 +562,24 @@ type ExternalCargoRegistryConfig struct {
Deps []ExternalCargoDependency `json:"deps,omitempty" yaml:"deps,omitempty"`
}

// ExternalNugetDependency defines a nuget package dependency.
type ExternalNugetDependency struct {
// Name specifies the name of the dependency.
Name string `json:"name,omitempty" yaml:"name,omitempty"`
// Version specifies the version of the dependency.
Version string `json:"version,omitempty" yaml:"version,omitempty"`
// TargetFrameworks specify the optional target frameworks for the dependency.
TargetFrameworks []string `json:"target_frameworks" yaml:"target_frameworks,omitempty"`
}

// ExternalNugetRegistryConfig defines the configuration for a nuget registry.
type ExternalNugetRegistryConfig struct {
// TargetFrameworks specify the frameworks to build.
TargetFrameworks []string `json:"target_frameworks" yaml:"target_frameworks,omitempty"`
// Deps specifies the dependencies for the generated SDK.
Deps []ExternalNugetDependency `json:"deps,omitempty" yaml:"deps,omitempty"`
}

type externalConfigVersion struct {
Version string `json:"version,omitempty" yaml:"version,omitempty"`
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,47 @@ func TestParsePluginConfigCargoYAML(t *testing.T) {
)
}

func TestParsePluginConfigNugetYAML(t *testing.T) {
t.Parallel()
pluginConfig, err := ParseConfig(filepath.Join("testdata", "success", "nuget", "buf.plugin.yaml"))
require.NoError(t, err)
pluginIdentity, err := bufremotepluginref.PluginIdentityForString("buf.build/grpc/csharp")
require.NoError(t, err)
depPluginRef, err := bufremotepluginref.PluginReferenceForString("buf.build/protocolbuffers/csharp:v26.1", 0)
require.NoError(t, err)
require.Equal(
t,
&Config{
Name: pluginIdentity,
PluginVersion: "v1.65.0",
Dependencies: []bufremotepluginref.PluginReference{depPluginRef},
SourceURL: "https://github.com/grpc/grpc",
Description: "Generates C# client and server stubs for the gRPC framework.",
SPDXLicenseID: "Apache-2.0",
LicenseURL: "https://github.com/grpc/grpc/blob/v1.65.0/LICENSE",
OutputLanguages: []string{"csharp"},
Registry: &RegistryConfig{
Nuget: &NugetRegistryConfig{
TargetFrameworks: []string{"netstandard2.0", "netstandard2.1"},
Deps: []NugetDependencyConfig{
{
Name: "Grpc.Core.Api",
Version: "2.63.0",
},
{
Name: "Grpc.Other.Api",
Version: "1.0.31",
TargetFrameworks: []string{"netstandard2.1"},
},
},
},
Options: map[string]string{"base_namespace": ""},
},
},
pluginConfig,
)
}

func TestParsePluginConfigOptionsYAML(t *testing.T) {
t.Parallel()
pluginConfig, err := ParseConfig(filepath.Join("testdata", "success", "options", "buf.plugin.yaml"))
Expand Down
Loading

0 comments on commit d8f68e4

Please sign in to comment.