Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
emcfarlane committed Oct 31, 2024
1 parent da80689 commit d0af6a8
Show file tree
Hide file tree
Showing 12 changed files with 738 additions and 4 deletions.
12 changes: 12 additions & 0 deletions private/buf/bufcli/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@ func NewLabelNameAlreadyExistsError(name string) error {
return fmt.Errorf("a label named %q already exists", name)
}

// NewPluginNameAlreadyExistsError informs the user that a plugin
// with that name already exists.
func NewPluginNameAlreadyExistsError(name string) error {
return fmt.Errorf("a plugin named %q already exists", name)
}

// NewOrganizationNotFoundError informs the user that an organization with
// that name does not exist.
func NewOrganizationNotFoundError(name string) error {
Expand Down Expand Up @@ -88,6 +94,12 @@ func NewTokenNotFoundError(tokenID string) error {
return fmt.Errorf("a token with ID %q does not exist", tokenID)
}

// NewPluginNotFoundError informs the user that a plugin with
// that name does not exist.
func NewPluginNotFoundError(name string) error {
return fmt.Errorf("a plugin named %q does not exist", name)
}

// NewInvalidRemoteError informs the user that the given remote is invalid.
func NewInvalidRemoteError(err error, remote string, moduleFullName string) error {
var connectErr *connect.Error
Expand Down
16 changes: 16 additions & 0 deletions private/buf/bufcli/flags_args.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"fmt"

modulev1 "buf.build/gen/go/bufbuild/registry/protocolbuffers/go/buf/registry/module/v1"
pluginv1beta1 "buf.build/gen/go/bufbuild/registry/protocolbuffers/go/buf/registry/plugin/v1beta1"
"github.com/bufbuild/buf/private/buf/buffetch"
"github.com/bufbuild/buf/private/pkg/app"
"github.com/bufbuild/buf/private/pkg/app/appcmd"
Expand Down Expand Up @@ -302,6 +303,21 @@ func VisibilityFlagToVisibilityAllowUnspecified(visibility string) (modulev1.Mod
}
}

// VisibilityFlagToPluginVisibilityAllowUnspecified parses the given string as a pluginv1.PluginVisibility
// where an empty string will be parsed as unspecified.
func VisibilityFlagToPluginVisibilityAllowUnspecified(visibility string) (pluginv1beta1.PluginVisibility, error) {
switch visibility {
case publicVisibility:
return pluginv1beta1.PluginVisibility_PLUGIN_VISIBILITY_PUBLIC, nil
case privateVisibility:
return pluginv1beta1.PluginVisibility_PLUGIN_VISIBILITY_PRIVATE, nil
case "":
return pluginv1beta1.PluginVisibility_PLUGIN_VISIBILITY_UNSPECIFIED, nil
default:
return 0, fmt.Errorf("invalid visibility: %s", visibility)
}
}

// ArchiveStatusFlagToArchiveStatusFilter parses the given string as a modulev1.ListLabelsRequest_ArchiveFilter.
func ArchiveStatusFlagToArchiveStatusFilter(archiveStatus string) (modulev1.ListLabelsRequest_ArchiveFilter, error) {
switch archiveStatus {
Expand Down
27 changes: 27 additions & 0 deletions private/buf/bufprint/bufprint.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (

modulev1 "buf.build/gen/go/bufbuild/registry/protocolbuffers/go/buf/registry/module/v1"
ownerv1 "buf.build/gen/go/bufbuild/registry/protocolbuffers/go/buf/registry/owner/v1"
pluginv1beta1 "buf.build/gen/go/bufbuild/registry/protocolbuffers/go/buf/registry/plugin/v1beta1"
"github.com/bufbuild/buf/private/bufpkg/bufmodule"
registryv1alpha1 "github.com/bufbuild/buf/private/gen/proto/go/buf/alpha/registry/v1alpha1"
"github.com/bufbuild/buf/private/pkg/protoencoding"
Expand Down Expand Up @@ -248,6 +249,19 @@ func NewOrganizationEntity(organization *ownerv1.Organization, remote string) En
}
}

// NewPluginEntity returns a new plugin entity to print.
func NewPluginEntity(plugin *pluginv1beta1.Plugin, pluginFullName bufmodule.ModuleFullName) Entity {
// TODO: update pluginFullName to use bufparse.FullName.
return outputPlugin{
ID: plugin.Id,
Remote: pluginFullName.Registry(),
Owner: pluginFullName.Owner(),
Name: pluginFullName.Name(),
FullName: pluginFullName.String(),
CreateTime: plugin.CreateTime.AsTime(),
}
}

// NewUserEntity returns a new user entity to print.
func NewUserEntity(user *registryv1alpha1.User) Entity {
return outputUser{
Expand Down Expand Up @@ -466,6 +480,19 @@ func (o outputOrganization) fullName() string {
return o.FullName
}

type outputPlugin struct {
ID string `json:"id,omitempty"`
Remote string `json:"remote,omitempty"`
Owner string `json:"owner,omitempty"`
Name string `json:"name,omitempty"`
FullName string `json:"-" bufprint:"Name"`
CreateTime time.Time `json:"create_time,omitempty" bufprint:"Create Time"`
}

func (m outputPlugin) fullName() string {
return m.FullName
}

type outputUser struct {
Username string `json:"username,omitempty"`
FullName string `json:"-" bufprint:"Name"`
Expand Down
22 changes: 18 additions & 4 deletions private/buf/cmd/buf/buf.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ import (
"github.com/bufbuild/buf/private/buf/cmd/buf/command/beta/bufpluginv2"
"github.com/bufbuild/buf/private/buf/cmd/buf/command/beta/lsp"
"github.com/bufbuild/buf/private/buf/cmd/buf/command/beta/price"
"github.com/bufbuild/buf/private/buf/cmd/buf/command/beta/registry/plugin/plugindelete"
"github.com/bufbuild/buf/private/buf/cmd/buf/command/beta/registry/plugin/pluginpush"
betaplugindelete "github.com/bufbuild/buf/private/buf/cmd/buf/command/beta/registry/plugin/plugindelete"
betapluginpush "github.com/bufbuild/buf/private/buf/cmd/buf/command/beta/registry/plugin/pluginpush"
"github.com/bufbuild/buf/private/buf/cmd/buf/command/beta/registry/webhook/webhookcreate"
"github.com/bufbuild/buf/private/buf/cmd/buf/command/beta/registry/webhook/webhookdelete"
"github.com/bufbuild/buf/private/buf/cmd/buf/command/beta/registry/webhook/webhooklist"
Expand Down Expand Up @@ -81,6 +81,10 @@ import (
"github.com/bufbuild/buf/private/buf/cmd/buf/command/registry/organization/organizationdelete"
"github.com/bufbuild/buf/private/buf/cmd/buf/command/registry/organization/organizationinfo"
"github.com/bufbuild/buf/private/buf/cmd/buf/command/registry/organization/organizationupdate"
"github.com/bufbuild/buf/private/buf/cmd/buf/command/registry/plugin/plugincreate"
"github.com/bufbuild/buf/private/buf/cmd/buf/command/registry/plugin/plugindelete"
"github.com/bufbuild/buf/private/buf/cmd/buf/command/registry/plugin/plugininfo"
"github.com/bufbuild/buf/private/buf/cmd/buf/command/registry/plugin/pluginupdate"
"github.com/bufbuild/buf/private/buf/cmd/buf/command/registry/registrycc"
"github.com/bufbuild/buf/private/buf/cmd/buf/command/registry/registrylogin"
"github.com/bufbuild/buf/private/buf/cmd/buf/command/registry/registrylogout"
Expand Down Expand Up @@ -228,6 +232,16 @@ func NewRootCommand(name string) *appcmd.Command {
moduleupdate.NewCommand("update", builder),
},
},
{
Use: "plugin",
Short: "Manage BSR plugins",
SubCommands: []*appcmd.Command{
plugincreate.NewCommand("create", builder),
plugininfo.NewCommand("info", builder),
plugindelete.NewCommand("delete", builder),
pluginupdate.NewCommand("update", builder),
},
},
},
},
{
Expand Down Expand Up @@ -258,8 +272,8 @@ func NewRootCommand(name string) *appcmd.Command {
Use: "plugin",
Short: "Manage plugins on the Buf Schema Registry",
SubCommands: []*appcmd.Command{
pluginpush.NewCommand("push", builder),
plugindelete.NewCommand("delete", builder),
betapluginpush.NewCommand("push", builder),
betaplugindelete.NewCommand("delete", builder),
},
},
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
// Copyright 2020-2024 Buf Technologies, Inc.
//
// 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 plugincreate

import (
"context"
"fmt"

ownerv1 "buf.build/gen/go/bufbuild/registry/protocolbuffers/go/buf/registry/owner/v1"
pluginv1beta1 "buf.build/gen/go/bufbuild/registry/protocolbuffers/go/buf/registry/plugin/v1beta1"
"connectrpc.com/connect"
"github.com/bufbuild/buf/private/buf/bufcli"
"github.com/bufbuild/buf/private/buf/bufprint"
"github.com/bufbuild/buf/private/bufpkg/bufmodule"
"github.com/bufbuild/buf/private/bufpkg/bufregistryapi/bufregistryapiplugin"
"github.com/bufbuild/buf/private/pkg/app/appcmd"
"github.com/bufbuild/buf/private/pkg/app/appext"
"github.com/bufbuild/buf/private/pkg/stringutil"
"github.com/bufbuild/buf/private/pkg/syserror"
"github.com/spf13/pflag"
)

const (
formatFlagName = "format"
visibilityFlagName = "visibility"
defaultLabeFlagName = "default-label-name"
typeFlagName = "type"

defaultDefaultLabel = "main"

pluginTypeProtocCodeGeneration = "protoc_code_generation"
pluginTypeCodeGeneration = "code_generation"
pluginTypeCheck = "check"
)

var (
allPluginTypeStrings = []string{
pluginTypeProtocCodeGeneration,
pluginTypeCodeGeneration,
pluginTypeCheck,
}
)

// NewCommand returns a new Command.
func NewCommand(
name string,
builder appext.SubCommandBuilder,
) *appcmd.Command {
flags := newFlags()
return &appcmd.Command{
Use: name + " <remote/owner/plugin>",
Short: "Create a BSR plugin",
Args: appcmd.ExactArgs(1),
Run: builder.NewRunFunc(
func(ctx context.Context, container appext.Container) error {
return run(ctx, container, flags)
},
),
BindFlags: flags.Bind,
}
}

type flags struct {
Format string
Visibility string
DefautlLabel string
Type string
}

func newFlags() *flags {
return &flags{}
}

func (f *flags) Bind(flagSet *pflag.FlagSet) {
bufcli.BindVisibility(flagSet, &f.Visibility, visibilityFlagName, false)
flagSet.StringVar(
&f.Format,
formatFlagName,
bufprint.FormatText.String(),
fmt.Sprintf(`The output format to use. Must be one of %s`, bufprint.AllFormatsString),
)
flagSet.StringVar(
&f.DefautlLabel,
defaultLabeFlagName,
defaultDefaultLabel,
"The default label name of the module",
)
flagSet.StringVar(
&f.Type,
typeFlagName,
"",
fmt.Sprintf(
"The type of the plugin. Must be one of %s",
stringutil.SliceToString(allPluginTypeStrings),
),
)
_ = appcmd.MarkFlagRequired(flagSet, typeFlagName)
}

func run(
ctx context.Context,
container appext.Container,
flags *flags,
) error {
// TODO: update to use bufparse.ParseFullName.
pluginFullName, err := bufmodule.ParseModuleFullName(container.Arg(0))
if err != nil {
return appcmd.WrapInvalidArgumentError(err)
}
visibility, err := bufcli.VisibilityFlagToPluginVisibilityAllowUnspecified(flags.Visibility)
if err != nil {
return appcmd.WrapInvalidArgumentError(err)
}
format, err := bufprint.ParseFormat(flags.Format)
if err != nil {
return appcmd.WrapInvalidArgumentError(err)
}
pluginType, err := typeFlagToPluginType(flags.Type)
if err != nil {
return appcmd.WrapInvalidArgumentError(err)
}

clientConfig, err := bufcli.NewConnectClientConfig(container)
if err != nil {
return err
}
pluginServiceClient := bufregistryapiplugin.NewClientProvider(clientConfig).
V1Beta1PluginServiceClient(pluginFullName.Registry())

pluginResponse, err := pluginServiceClient.CreatePlugins(ctx, connect.NewRequest(
&pluginv1beta1.CreatePluginsRequest{
Values: []*pluginv1beta1.CreatePluginsRequest_Value{
{
OwnerRef: &ownerv1.OwnerRef{
Value: &ownerv1.OwnerRef_Name{
Name: pluginFullName.Owner(),
},
},
Name: pluginFullName.Name(),
Visibility: visibility,
Type: pluginType,
},
},
},
))
if err != nil {
if connect.CodeOf(err) == connect.CodeAlreadyExists {
return bufcli.NewPluginNameAlreadyExistsError(pluginFullName.String())
}
return err
}
plugins := pluginResponse.Msg.Plugins
if len(plugins) != 1 {
return syserror.Newf("unexpected number of plugins returned from server: %d", len(plugins))
}
if format == bufprint.FormatText {
_, err = fmt.Fprintf(container.Stdout(), "Created %s.\n", pluginFullName)
if err != nil {
return syserror.Wrap(err)
}
return nil
}
return bufprint.PrintNames(
container.Stdout(),
format,
bufprint.NewPluginEntity(plugins[0], pluginFullName),
)
}

// typeFlagToPluginType parses the given string as a pluginv1.PluginType.
func typeFlagToPluginType(pluginType string) (pluginv1beta1.PluginType, error) {
switch pluginType {
case pluginTypeCheck:
return pluginv1beta1.PluginType_PLUGIN_TYPE_CHECK, nil
default:
return 0, fmt.Errorf("invalid plugin type: %s", pluginType)
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit d0af6a8

Please sign in to comment.