Skip to content

Commit

Permalink
Merge branch 'main' into ed/pluginRegistryCommitCmds
Browse files Browse the repository at this point in the history
  • Loading branch information
emcfarlane authored Dec 3, 2024
2 parents cbb0f8a + 1c39351 commit 536cbff
Show file tree
Hide file tree
Showing 17 changed files with 1,308 additions and 23 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@

- Add `buf registry plugin {create,delete,info,update}` commands to manage BSR plugins.
- Breaking analysis support for `buf beta lsp`.
- Fix bug when using the `--type` flag filter for `buf build` where import ordering is not
determinisitic.
- Add `buf plugin push` command to push a plugin to the Buf Schema Registry.
Only WebAssembly check plugins are supported at this time.
- Add `buf registry plugin commit {add-label,info,list,resolve}` to manage BSR plugin commits.

## [v1.47.2] - 2024-11-14
Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,12 @@ require (
github.com/klauspost/pgzip v1.2.6
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c
github.com/pkg/profile v1.7.0
github.com/quic-go/quic-go v0.48.1
github.com/quic-go/quic-go v0.48.2
github.com/rs/cors v1.11.1
github.com/spf13/cobra v1.8.1
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.10.0
github.com/tetratelabs/wazero v1.8.1
github.com/tetratelabs/wazero v1.8.2
go.lsp.dev/jsonrpc2 v0.10.0
go.lsp.dev/protocol v0.12.0
go.uber.org/zap v1.27.0
Expand Down
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -229,8 +229,8 @@ github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0leargg
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
github.com/quic-go/quic-go v0.48.1 h1:y/8xmfWI9qmGTc+lBr4jKRUWLGSlSigv847ULJ4hYXA=
github.com/quic-go/quic-go v0.48.1/go.mod h1:yBgs3rWBOADpga7F+jJsb6Ybg1LSYiQvwWlLX+/6HMs=
github.com/quic-go/quic-go v0.48.2 h1:wsKXZPeGWpMpCGSWqOcqpW2wZYic/8T3aqiOID0/KWE=
github.com/quic-go/quic-go v0.48.2/go.mod h1:yBgs3rWBOADpga7F+jJsb6Ybg1LSYiQvwWlLX+/6HMs=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA=
Expand Down Expand Up @@ -258,8 +258,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/tetratelabs/wazero v1.8.1 h1:NrcgVbWfkWvVc4UtT4LRLDf91PsOzDzefMdwhLfA550=
github.com/tetratelabs/wazero v1.8.1/go.mod h1:yAI0XTsMBhREkM/YDAK/zNou3GoiAce1P6+rp/wQhjs=
github.com/tetratelabs/wazero v1.8.2 h1:yIgLR/b2bN31bjxwXHD8a3d+BogigR952csSDdLYEv4=
github.com/tetratelabs/wazero v1.8.2/go.mod h1:yAI0XTsMBhREkM/YDAK/zNou3GoiAce1P6+rp/wQhjs=
github.com/vbatts/tar-split v0.11.6 h1:4SjTW5+PU11n6fZenf2IPoV8/tz3AaYHMWjf23envGs=
github.com/vbatts/tar-split v0.11.6/go.mod h1:dqKNtesIOr2j2Qv3W/cHjnvk9I8+G7oAkFDFN6TCBEI=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
Expand Down
30 changes: 26 additions & 4 deletions private/buf/bufcli/uploader.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,32 @@ package bufcli
import (
"github.com/bufbuild/buf/private/bufpkg/bufmodule"
"github.com/bufbuild/buf/private/bufpkg/bufmodule/bufmoduleapi"
"github.com/bufbuild/buf/private/bufpkg/bufplugin"
"github.com/bufbuild/buf/private/bufpkg/bufplugin/bufpluginapi"
"github.com/bufbuild/buf/private/bufpkg/bufregistryapi/bufregistryapimodule"
"github.com/bufbuild/buf/private/bufpkg/bufregistryapi/bufregistryapiplugin"
"github.com/bufbuild/buf/private/pkg/app/appext"
)

// NewUploader returns a new Uploader.
func NewUploader(container appext.Container) (bufmodule.Uploader, error) {
// NewModuleUploader returns a new Uploader for ModuleSets.
func NewModuleUploader(container appext.Container) (bufmodule.Uploader, error) {
clientConfig, err := NewConnectClientConfig(container)
if err != nil {
return nil, err
}
return newUploader(container, bufregistryapimodule.NewClientProvider(clientConfig)), nil
return newModuleUploader(container, bufregistryapimodule.NewClientProvider(clientConfig)), nil
}

func newUploader(
// NewPluginUploader returns a new Uploader for Plugins.
func NewPluginUploader(container appext.Container) (bufplugin.Uploader, error) {
clientConfig, err := NewConnectClientConfig(container)
if err != nil {
return nil, err
}
return newPluginUploader(container, bufregistryapiplugin.NewClientProvider(clientConfig)), nil
}

func newModuleUploader(
container appext.Container,
clientProvider bufregistryapimodule.ClientProvider,
) bufmodule.Uploader {
Expand All @@ -41,3 +53,13 @@ func newUploader(
bufmoduleapi.UploaderWithPublicRegistry(container.Env(publicRegistryEnvKey)),
)
}

func newPluginUploader(
container appext.Container,
clientProvider bufregistryapiplugin.ClientProvider,
) bufplugin.Uploader {
return bufpluginapi.NewUploader(
container.Logger(),
clientProvider,
)
}
8 changes: 8 additions & 0 deletions private/buf/cmd/buf/buf.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ import (
"github.com/bufbuild/buf/private/buf/cmd/buf/command/mod/modlsbreakingrules"
"github.com/bufbuild/buf/private/buf/cmd/buf/command/mod/modlslintrules"
"github.com/bufbuild/buf/private/buf/cmd/buf/command/mod/modopen"
"github.com/bufbuild/buf/private/buf/cmd/buf/command/plugin/pluginpush"
"github.com/bufbuild/buf/private/buf/cmd/buf/command/push"
"github.com/bufbuild/buf/private/buf/cmd/buf/command/registry/module/modulecommit/modulecommitaddlabel"
"github.com/bufbuild/buf/private/buf/cmd/buf/command/registry/module/modulecommit/modulecommitinfo"
Expand Down Expand Up @@ -179,6 +180,13 @@ func NewRootCommand(name string) *appcmd.Command {
modlsbreakingrules.NewCommand("ls-breaking-rules", builder),
},
},
{
Use: "plugin",
Short: "Work with check plugins",
SubCommands: []*appcmd.Command{
pluginpush.NewCommand("push", builder),
},
},
{
Use: "registry",
Short: "Manage assets on the Buf Schema Registry",
Expand Down
263 changes: 263 additions & 0 deletions private/buf/cmd/buf/command/plugin/pluginpush/pluginpush.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,263 @@
// 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 pluginpush

import (
"context"
"fmt"
"os"
"strings"

"github.com/bufbuild/buf/private/buf/bufcli"
"github.com/bufbuild/buf/private/bufpkg/bufparse"
"github.com/bufbuild/buf/private/bufpkg/bufplugin"
"github.com/bufbuild/buf/private/pkg/app/appcmd"
"github.com/bufbuild/buf/private/pkg/app/appext"
"github.com/bufbuild/buf/private/pkg/slicesext"
"github.com/bufbuild/buf/private/pkg/stringutil"
"github.com/bufbuild/buf/private/pkg/syserror"
"github.com/spf13/pflag"
)

const (
labelFlagName = "label"
binaryFlagName = "binary"
createFlagName = "create"
createVisibilityFlagName = "create-visibility"
createTypeFlagName = "create-type"
sourceControlURLFlagName = "source-control-url"
)

// 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: "Push a check plugin to a registry",
Long: `The first argument is the plugin full name in the format <remote/owner/plugin>.`,
Args: appcmd.MaximumNArgs(1),
Run: builder.NewRunFunc(
func(ctx context.Context, container appext.Container) error {
return run(ctx, container, flags)
},
),
BindFlags: flags.Bind,
}
}

type flags struct {
Labels []string
Binary string
Create bool
CreateVisibility string
CreateType string
SourceControlURL string
}

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

func (f *flags) Bind(flagSet *pflag.FlagSet) {
bufcli.BindCreateVisibility(flagSet, &f.CreateVisibility, createVisibilityFlagName, createFlagName)
flagSet.StringSliceVar(
&f.Labels,
labelFlagName,
nil,
"Associate the label with the plugins pushed. Can be used multiple times.",
)
flagSet.StringVar(
&f.Binary,
binaryFlagName,
"",
"The path to the Wasm binary file to push.",
)
flagSet.BoolVar(
&f.Create,
createFlagName,
false,
fmt.Sprintf(
"Create the plugin if it does not exist. Defaults to creating a private plugin on the BSR if --%s is not set. Must be used with --%s.",
createVisibilityFlagName,
createTypeFlagName,
),
)
flagSet.StringVar(
&f.CreateType,
createTypeFlagName,
"",
fmt.Sprintf(
"The plugin's type setting, if created. Can only be set with --%s. Must be one of %s",
createTypeFlagName,
stringutil.SliceToString(bufplugin.AllPluginTypeStrings),
),
)
flagSet.StringVar(
&f.SourceControlURL,
sourceControlURLFlagName,
"",
"The URL for viewing the source code of the pushed plugins (e.g. the specific commit in source control).",
)
}

func run(
ctx context.Context,
container appext.Container,
flags *flags,
) (retErr error) {
if err := validateFlags(flags); err != nil {
return err
}
// We parse the plugin full name from the user-provided argument.
pluginFullName, err := bufparse.ParseFullName(container.Arg(0))
if err != nil {
return appcmd.WrapInvalidArgumentError(err)
}
commit, err := upload(ctx, container, flags, pluginFullName)
if err != nil {
return err
}
// Only one commit is returned.
if _, err := fmt.Fprintf(container.Stdout(), "%s\n", commit.PluginKey().String()); err != nil {
return syserror.Wrap(err)
}
return nil
}

func upload(
ctx context.Context,
container appext.Container,
flags *flags,
pluginFullName bufparse.FullName,
) (_ bufplugin.Commit, retErr error) {
var plugin bufplugin.Plugin
switch {
case flags.Binary != "":
var err error
plugin, err = bufplugin.NewLocalWasmPlugin(
pluginFullName,
func() ([]byte, error) {
wasmBinary, err := os.ReadFile(flags.Binary)
if err != nil {
return nil, fmt.Errorf("could not read Wasm binary %q: %w", flags.Binary, err)
}
return wasmBinary, nil
},
)
if err != nil {
return nil, err
}
default:
// This should never happen because the flags are validated.
return nil, syserror.Newf("--%s must be set", binaryFlagName)
}
uploader, err := bufcli.NewPluginUploader(container)
if err != nil {
return nil, err
}
var options []bufplugin.UploadOption
if flags.Create {
createPluginVisibility, err := bufplugin.ParsePluginVisibility(flags.CreateVisibility)
if err != nil {
return nil, err
}
createPluginType, err := bufplugin.ParsePluginType(flags.CreateType)
if err != nil {
return nil, err
}
options = append(options, bufplugin.UploadWithCreateIfNotExist(
createPluginVisibility,
createPluginType,
))
}
commits, err := uploader.Upload(ctx, []bufplugin.Plugin{plugin}, options...)
if err != nil {
return nil, err
}
if len(commits) != 1 {
return nil, syserror.Newf("unexpected number of commits returned from server: %d", len(commits))
}
return commits[0], nil
}

func validateFlags(flags *flags) error {
if err := validateLabelFlags(flags); err != nil {
return err
}
if err := validateTypeFlags(flags); err != nil {
return err
}
if err := validateCreateFlags(flags); err != nil {
return err
}
return nil
}

func validateLabelFlags(flags *flags) error {
return validateLabelFlagValues(flags)
}

func validateTypeFlags(flags *flags) error {
var typeFlags []string
if flags.Binary != "" {
typeFlags = append(typeFlags, binaryFlagName)
}
if len(typeFlags) > 1 {
usedFlagsErrStr := strings.Join(
slicesext.Map(
typeFlags,
func(flag string) string { return fmt.Sprintf("--%s", flag) },
),
", ",
)
return appcmd.NewInvalidArgumentErrorf("These flags cannot be used in combination with one another: %s", usedFlagsErrStr)
}
if len(typeFlags) == 0 {
return appcmd.NewInvalidArgumentErrorf("--%s must be set", binaryFlagName)
}
return nil
}

func validateLabelFlagValues(flags *flags) error {
for _, label := range flags.Labels {
if label == "" {
return appcmd.NewInvalidArgumentErrorf("--%s requires a non-empty string", labelFlagName)
}
}
return nil
}

func validateCreateFlags(flags *flags) error {
if flags.Create {
if flags.CreateVisibility == "" {
return appcmd.NewInvalidArgumentErrorf("--%s must be set if --%s is set", createVisibilityFlagName, createFlagName)
}
if _, err := bufplugin.ParsePluginVisibility(flags.CreateVisibility); err != nil {
return appcmd.WrapInvalidArgumentError(err)
}
}
if flags.Create {
if flags.CreateType == "" {
return appcmd.NewInvalidArgumentErrorf("--%s must be set if --%s is set", createTypeFlagName, createFlagName)
}
if _, err := bufplugin.ParsePluginType(flags.CreateType); err != nil {
return appcmd.WrapInvalidArgumentError(err)
}
}
return nil
}
Loading

0 comments on commit 536cbff

Please sign in to comment.