|
| 1 | +// Copyright 2020-2025 Buf Technologies, Inc. |
| 2 | +// |
| 3 | +// Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | +// you may not use this file except in compliance with the License. |
| 5 | +// You may obtain a copy of the License at |
| 6 | +// |
| 7 | +// http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | +// |
| 9 | +// Unless required by applicable law or agreed to in writing, software |
| 10 | +// distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | +// See the License for the specific language governing permissions and |
| 13 | +// limitations under the License. |
| 14 | + |
| 15 | +package sdkinfo |
| 16 | + |
| 17 | +import ( |
| 18 | + "context" |
| 19 | + "fmt" |
| 20 | + |
| 21 | + "buf.build/go/app/appcmd" |
| 22 | + "buf.build/go/app/appext" |
| 23 | + "connectrpc.com/connect" |
| 24 | + "github.com/bufbuild/buf/private/buf/bufcli" |
| 25 | + "github.com/bufbuild/buf/private/buf/bufprint" |
| 26 | + "github.com/bufbuild/buf/private/bufpkg/bufparse" |
| 27 | + "github.com/bufbuild/buf/private/bufpkg/bufremoteplugin/bufremotepluginref" |
| 28 | + "github.com/bufbuild/buf/private/gen/proto/connect/buf/alpha/registry/v1alpha1/registryv1alpha1connect" |
| 29 | + registryv1alpha1 "github.com/bufbuild/buf/private/gen/proto/go/buf/alpha/registry/v1alpha1" |
| 30 | + "github.com/bufbuild/buf/private/pkg/connectclient" |
| 31 | + "github.com/spf13/pflag" |
| 32 | +) |
| 33 | + |
| 34 | +const ( |
| 35 | + formatFlagName = "format" |
| 36 | + moduleFlagName = "module" |
| 37 | + pluginFlagName = "plugin" |
| 38 | + versionFlagName = "version" |
| 39 | +) |
| 40 | + |
| 41 | +// NewCommand returns a new Command. |
| 42 | +func NewCommand( |
| 43 | + name string, |
| 44 | + builder appext.SubCommandBuilder, |
| 45 | +) *appcmd.Command { |
| 46 | + flags := newFlags() |
| 47 | + return &appcmd.Command{ |
| 48 | + Use: name + " --module=<remote/owner/repository[:ref]> --plugin=<remote/owner/plugin[:version]>", |
| 49 | + Short: "Get SDK information for the given module, plugin, and optionally version.", |
| 50 | + Long: `This command returns the version information for a Generated SDK based on the specified information. |
| 51 | +In order to resolve the SDK information, a module and plugin must be specified. |
| 52 | +
|
| 53 | +Examples: |
| 54 | +
|
| 55 | +To get the SDK information for the latest commit of a module and latest version of a plugin, you only need to specify the module and plugin. |
| 56 | +The following will resolve the SDK information for the latest commit of the connectrpc/eliza module and the latest version of the bufbuild/es plugin: |
| 57 | +
|
| 58 | + $ buf registry sdk info --module=buf.build/connectrpc/eliza --plugin=buf.build/connectrpc/es |
| 59 | + Module |
| 60 | + Owner: connectrpc |
| 61 | + Name: eliza |
| 62 | + Commit: <latest commit on default label> |
| 63 | +
|
| 64 | + Plugin |
| 65 | + Owner: bufbuild |
| 66 | + Name: es |
| 67 | + Version: <latest version of plugin> |
| 68 | + Revision: <latest revision of the plugin version> |
| 69 | +
|
| 70 | + Version: <SDK version for the resolved module commit and plugin version> |
| 71 | +
|
| 72 | +To get the SDK information for a specific commit of a module and/or a specific version of a plugin, you can specify the commit with the module and/or the version with the plugin. |
| 73 | +The following will resolve the SDK information for the specified commit of the connectrpc/eliza module and specified version of the bufbuild/es plugin: |
| 74 | +
|
| 75 | + $ buf registry sdk info --module=buf.build/connectrpc/eliza:d8fbf2620c604277a0ece1ff3a26f2ff --plugin=buf.build/bufbuild/es:v1.2.1 |
| 76 | + Module |
| 77 | + Owner: connectrpc |
| 78 | + Name: eliza |
| 79 | + Commit: d8fbf2620c604277a0ece1ff3a26f2ff |
| 80 | +
|
| 81 | + Plugin |
| 82 | + Owner: bufbuild |
| 83 | + Name: es |
| 84 | + Version: v1.2.1 |
| 85 | + Revision: 1 |
| 86 | +
|
| 87 | + Version: 1.2.1-20230727062025-d8fbf2620c60.1 |
| 88 | +
|
| 89 | +If you have a SDK version and want to know the corresponding module commit and plugin version information for the SDK, you can specify the module and plugin with the version string. |
| 90 | +The following will resolve the SDK information for the specified SDK version of the connectrpc/eliza module and bufbuild/es plugin. |
| 91 | +
|
| 92 | + $ buf registry sdk --module=buf.build/connectrpc/eliza --plugin=buf.build/bufbuild/es --version=1.2.1-20230727062025-d8fbf2620c60.1 |
| 93 | + Module |
| 94 | + Owner: connectrpc |
| 95 | + Name: eliza |
| 96 | + Commit: d8fbf2620c604277a0ece1ff3a26f2ff |
| 97 | +
|
| 98 | + Plugin |
| 99 | + Owner: bufbuild |
| 100 | + Name: es |
| 101 | + Version: v1.2.1 |
| 102 | + Revision: 1 |
| 103 | +
|
| 104 | + Version: 1.2.1-20230727062025-d8fbf2620c60.1 |
| 105 | +
|
| 106 | +The module commit and plugin version information are resolved based on the specified SDK version string. |
| 107 | +
|
| 108 | +If a module reference and/or plugin version are specified along with the SDK version, then the SDK version will be validated against the specified module reference and/or plugin version. |
| 109 | +If there is a mismatch, this command will error. |
| 110 | +
|
| 111 | + $ buf registry sdk info \ |
| 112 | + --module=buf.build/connectrpc/eliza:8b8b971d6fde4dc8ba5d96f9fda7d53c \ |
| 113 | + --plugin=buf.build/bufbuild/es \ |
| 114 | + --version=1.2.1-20230727062025-d8fbf2620c60.1 |
| 115 | + Failure: invalid_argument: invalid SDK version v1.2.1-20230727062025-d8fbf2620c60.1 with module short commit d8fbf2620c60 for resolved module reference connectrpc/eliza:8b8b971d6fde4dc8ba5d96f9fda7d53c |
| 116 | +
|
| 117 | +In this case, the SDK version provided resolves to a different commit than the commit provided for the module.`, |
| 118 | + Args: appcmd.NoArgs, |
| 119 | + Run: builder.NewRunFunc( |
| 120 | + func(ctx context.Context, container appext.Container) error { |
| 121 | + return run(ctx, container, flags) |
| 122 | + }, |
| 123 | + ), |
| 124 | + BindFlags: flags.Bind, |
| 125 | + } |
| 126 | +} |
| 127 | + |
| 128 | +type flags struct { |
| 129 | + Format string |
| 130 | + Module string |
| 131 | + Plugin string |
| 132 | + Version string |
| 133 | +} |
| 134 | + |
| 135 | +func newFlags() *flags { |
| 136 | + return &flags{} |
| 137 | +} |
| 138 | + |
| 139 | +func (f *flags) Bind(flagSet *pflag.FlagSet) { |
| 140 | + flagSet.StringVar( |
| 141 | + &f.Format, |
| 142 | + formatFlagName, |
| 143 | + bufprint.FormatText.String(), |
| 144 | + fmt.Sprintf("The output format to use. Must be one of %s", bufprint.AllFormatsString), |
| 145 | + ) |
| 146 | + flagSet.StringVar(&f.Module, moduleFlagName, "", "The module reference for the SDK.") |
| 147 | + flagSet.StringVar(&f.Plugin, pluginFlagName, "", "The plugin reference for the SDK.") |
| 148 | + flagSet.StringVar(&f.Version, versionFlagName, "", "The version of the SDK.") |
| 149 | + _ = appcmd.MarkFlagRequired(flagSet, moduleFlagName) |
| 150 | + _ = appcmd.MarkFlagRequired(flagSet, pluginFlagName) |
| 151 | +} |
| 152 | + |
| 153 | +func run( |
| 154 | + ctx context.Context, |
| 155 | + container appext.Container, |
| 156 | + flags *flags, |
| 157 | +) error { |
| 158 | + moduleRef, err := bufparse.ParseRef(flags.Module) |
| 159 | + if err != nil { |
| 160 | + return appcmd.WrapInvalidArgumentError(err) |
| 161 | + } |
| 162 | + pluginIdentity, pluginVersion, err := bufremotepluginref.ParsePluginIdentityOptionalVersion(flags.Plugin) |
| 163 | + if err != nil { |
| 164 | + return appcmd.WrapInvalidArgumentError(err) |
| 165 | + } |
| 166 | + if moduleRef.FullName().Registry() != pluginIdentity.Remote() { |
| 167 | + return appcmd.NewInvalidArgumentError("module and plugin must be from the same BSR instance") |
| 168 | + } |
| 169 | + clientConfig, err := bufcli.NewConnectClientConfig(container) |
| 170 | + if err != nil { |
| 171 | + return err |
| 172 | + } |
| 173 | + resolveServiceClient := connectclient.Make( |
| 174 | + clientConfig, |
| 175 | + moduleRef.FullName().Registry(), |
| 176 | + registryv1alpha1connect.NewResolveServiceClient, |
| 177 | + ) |
| 178 | + res, err := resolveServiceClient.GetSDKInfo( |
| 179 | + ctx, |
| 180 | + connect.NewRequest(registryv1alpha1.GetSDKInfoRequest_builder{ |
| 181 | + ModuleReference: registryv1alpha1.LocalModuleReference_builder{ |
| 182 | + Owner: moduleRef.FullName().Owner(), |
| 183 | + Repository: moduleRef.FullName().Name(), |
| 184 | + Reference: moduleRef.Ref(), |
| 185 | + }.Build(), |
| 186 | + PluginReference: registryv1alpha1.GetRemotePackageVersionPlugin_builder{ |
| 187 | + Owner: pluginIdentity.Owner(), |
| 188 | + Name: pluginIdentity.Plugin(), |
| 189 | + Version: pluginVersion, |
| 190 | + }.Build(), |
| 191 | + SdkVersion: flags.Version, |
| 192 | + }.Build()), |
| 193 | + ) |
| 194 | + if err != nil { |
| 195 | + return err |
| 196 | + } |
| 197 | + format, err := bufprint.ParseFormat(flags.Format) |
| 198 | + if err != nil { |
| 199 | + return err |
| 200 | + } |
| 201 | + return bufprint.NewSDKInfoPrinter(container.Stdout()).PrintSDKInfo( |
| 202 | + ctx, |
| 203 | + format, |
| 204 | + res.Msg, |
| 205 | + ) |
| 206 | +} |
0 commit comments